blob: d90655b095b13f1875afaa9ba2c5ef592ba3dd9a [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// 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 "v8.h"
29
Leon Clarkef7060e22010-06-03 12:02:55 +010030#if defined(V8_TARGET_ARCH_X64)
31
Steve Blocka7e24c12009-10-30 11:49:00 +000032#include "macro-assembler.h"
33#include "serialize.h"
34
35namespace v8 {
36namespace internal {
37
38// -----------------------------------------------------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +000039// Implementation of CpuFeatures
40
41// The required user mode extensions in X64 are (from AMD64 ABI Table A.1):
42// fpu, tsc, cx8, cmov, mmx, sse, sse2, fxsr, syscall
43uint64_t CpuFeatures::supported_ = kDefaultCpuFeatures;
44uint64_t CpuFeatures::enabled_ = 0;
Steve Blockd0582a62009-12-15 09:54:21 +000045uint64_t CpuFeatures::found_by_runtime_probing_ = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +000046
47void CpuFeatures::Probe() {
48 ASSERT(Heap::HasBeenSetup());
49 ASSERT(supported_ == kDefaultCpuFeatures);
Steve Blockd0582a62009-12-15 09:54:21 +000050 if (Serializer::enabled()) {
51 supported_ |= OS::CpuFeaturesImpliedByPlatform();
52 return; // No features if we might serialize.
53 }
Steve Blocka7e24c12009-10-30 11:49:00 +000054
55 Assembler assm(NULL, 0);
56 Label cpuid, done;
57#define __ assm.
58 // Save old rsp, since we are going to modify the stack.
59 __ push(rbp);
60 __ pushfq();
61 __ push(rcx);
62 __ push(rbx);
63 __ movq(rbp, rsp);
64
65 // If we can modify bit 21 of the EFLAGS register, then CPUID is supported.
66 __ pushfq();
67 __ pop(rax);
68 __ movq(rdx, rax);
69 __ xor_(rax, Immediate(0x200000)); // Flip bit 21.
70 __ push(rax);
71 __ popfq();
72 __ pushfq();
73 __ pop(rax);
74 __ xor_(rax, rdx); // Different if CPUID is supported.
75 __ j(not_zero, &cpuid);
76
77 // CPUID not supported. Clear the supported features in edx:eax.
78 __ xor_(rax, rax);
79 __ jmp(&done);
80
81 // Invoke CPUID with 1 in eax to get feature information in
82 // ecx:edx. Temporarily enable CPUID support because we know it's
83 // safe here.
84 __ bind(&cpuid);
85 __ movq(rax, Immediate(1));
86 supported_ = kDefaultCpuFeatures | (1 << CPUID);
87 { Scope fscope(CPUID);
88 __ cpuid();
89 // Move the result from ecx:edx to rdi.
90 __ movl(rdi, rdx); // Zero-extended to 64 bits.
91 __ shl(rcx, Immediate(32));
92 __ or_(rdi, rcx);
93
94 // Get the sahf supported flag, from CPUID(0x80000001)
95 __ movq(rax, 0x80000001, RelocInfo::NONE);
96 __ cpuid();
97 }
98 supported_ = kDefaultCpuFeatures;
99
100 // Put the CPU flags in rax.
101 // rax = (rcx & 1) | (rdi & ~1) | (1 << CPUID).
102 __ movl(rax, Immediate(1));
103 __ and_(rcx, rax); // Bit 0 is set if SAHF instruction supported.
104 __ not_(rax);
105 __ and_(rax, rdi);
106 __ or_(rax, rcx);
107 __ or_(rax, Immediate(1 << CPUID));
108
109 // Done.
110 __ bind(&done);
111 __ movq(rsp, rbp);
112 __ pop(rbx);
113 __ pop(rcx);
114 __ popfq();
115 __ pop(rbp);
116 __ ret(0);
117#undef __
118
119 CodeDesc desc;
120 assm.GetCode(&desc);
Steve Block6ded16b2010-05-10 14:33:55 +0100121 Object* code = Heap::CreateCode(desc,
Steve Block6ded16b2010-05-10 14:33:55 +0100122 Code::ComputeFlags(Code::STUB),
123 Handle<Object>());
Steve Blocka7e24c12009-10-30 11:49:00 +0000124 if (!code->IsCode()) return;
Steve Block6ded16b2010-05-10 14:33:55 +0100125 PROFILE(CodeCreateEvent(Logger::BUILTIN_TAG,
126 Code::cast(code), "CpuFeatures::Probe"));
Steve Blocka7e24c12009-10-30 11:49:00 +0000127 typedef uint64_t (*F0)();
128 F0 probe = FUNCTION_CAST<F0>(Code::cast(code)->entry());
129 supported_ = probe();
Steve Blockd0582a62009-12-15 09:54:21 +0000130 found_by_runtime_probing_ = supported_;
131 found_by_runtime_probing_ &= ~kDefaultCpuFeatures;
132 uint64_t os_guarantees = OS::CpuFeaturesImpliedByPlatform();
133 supported_ |= os_guarantees;
134 found_by_runtime_probing_ &= ~os_guarantees;
Steve Blocka7e24c12009-10-30 11:49:00 +0000135 // SSE2 and CMOV must be available on an X64 CPU.
136 ASSERT(IsSupported(CPUID));
137 ASSERT(IsSupported(SSE2));
138 ASSERT(IsSupported(CMOV));
139}
140
141
142// -----------------------------------------------------------------------------
143// Implementation of RelocInfo
144
145// Patch the code at the current PC with a call to the target address.
146// Additional guard int3 instructions can be added if required.
147void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) {
148 // Load register with immediate 64 and call through a register instructions
149 // takes up 13 bytes and int3 takes up one byte.
150 static const int kCallCodeSize = 13;
151 int code_size = kCallCodeSize + guard_bytes;
152
153 // Create a code patcher.
154 CodePatcher patcher(pc_, code_size);
155
156 // Add a label for checking the size of the code used for returning.
157#ifdef DEBUG
158 Label check_codesize;
159 patcher.masm()->bind(&check_codesize);
160#endif
161
162 // Patch the code.
163 patcher.masm()->movq(r10, target, RelocInfo::NONE);
164 patcher.masm()->call(r10);
165
166 // Check that the size of the code generated is as expected.
167 ASSERT_EQ(kCallCodeSize,
168 patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
169
170 // Add the requested number of int3 instructions after the call.
171 for (int i = 0; i < guard_bytes; i++) {
172 patcher.masm()->int3();
173 }
174}
175
176
177void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
178 // Patch the code at the current address with the supplied instructions.
179 for (int i = 0; i < instruction_count; i++) {
180 *(pc_ + i) = *(instructions + i);
181 }
182
183 // Indicate that code has changed.
184 CPU::FlushICache(pc_, instruction_count);
185}
186
187// -----------------------------------------------------------------------------
188// Implementation of Operand
189
Andrei Popescu402d9372010-02-26 13:31:12 +0000190Operand::Operand(Register base, int32_t disp) : rex_(0) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000191 len_ = 1;
192 if (base.is(rsp) || base.is(r12)) {
193 // SIB byte is needed to encode (rsp + offset) or (r12 + offset).
194 set_sib(times_1, rsp, base);
195 }
196
197 if (disp == 0 && !base.is(rbp) && !base.is(r13)) {
198 set_modrm(0, base);
199 } else if (is_int8(disp)) {
200 set_modrm(1, base);
201 set_disp8(disp);
202 } else {
203 set_modrm(2, base);
204 set_disp32(disp);
205 }
206}
207
208
209Operand::Operand(Register base,
210 Register index,
211 ScaleFactor scale,
Andrei Popescu402d9372010-02-26 13:31:12 +0000212 int32_t disp) : rex_(0) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000213 ASSERT(!index.is(rsp));
214 len_ = 1;
215 set_sib(scale, index, base);
216 if (disp == 0 && !base.is(rbp) && !base.is(r13)) {
217 // This call to set_modrm doesn't overwrite the REX.B (or REX.X) bits
218 // possibly set by set_sib.
219 set_modrm(0, rsp);
220 } else if (is_int8(disp)) {
221 set_modrm(1, rsp);
222 set_disp8(disp);
223 } else {
224 set_modrm(2, rsp);
225 set_disp32(disp);
226 }
227}
228
229
Andrei Popescu402d9372010-02-26 13:31:12 +0000230Operand::Operand(Register index,
231 ScaleFactor scale,
232 int32_t disp) : rex_(0) {
233 ASSERT(!index.is(rsp));
234 len_ = 1;
235 set_modrm(0, rsp);
236 set_sib(scale, index, rbp);
237 set_disp32(disp);
238}
239
240
Leon Clarkef7060e22010-06-03 12:02:55 +0100241Operand::Operand(const Operand& operand, int32_t offset) {
242 ASSERT(operand.len_ >= 1);
243 // Operand encodes REX ModR/M [SIB] [Disp].
244 byte modrm = operand.buf_[0];
245 ASSERT(modrm < 0xC0); // Disallow mode 3 (register target).
246 bool has_sib = ((modrm & 0x07) == 0x04);
247 byte mode = modrm & 0xC0;
248 int disp_offset = has_sib ? 2 : 1;
249 int base_reg = (has_sib ? operand.buf_[1] : modrm) & 0x07;
250 // Mode 0 with rbp/r13 as ModR/M or SIB base register always has a 32-bit
251 // displacement.
252 bool is_baseless = (mode == 0) && (base_reg == 0x05); // No base or RIP base.
253 int32_t disp_value = 0;
254 if (mode == 0x80 || is_baseless) {
255 // Mode 2 or mode 0 with rbp/r13 as base: Word displacement.
256 disp_value = *reinterpret_cast<const int32_t*>(&operand.buf_[disp_offset]);
257 } else if (mode == 0x40) {
258 // Mode 1: Byte displacement.
259 disp_value = static_cast<signed char>(operand.buf_[disp_offset]);
260 }
261
262 // Write new operand with same registers, but with modified displacement.
263 ASSERT(offset >= 0 ? disp_value + offset > disp_value
264 : disp_value + offset < disp_value); // No overflow.
265 disp_value += offset;
266 rex_ = operand.rex_;
267 if (!is_int8(disp_value) || is_baseless) {
268 // Need 32 bits of displacement, mode 2 or mode 1 with register rbp/r13.
269 buf_[0] = (modrm & 0x3f) | (is_baseless ? 0x00 : 0x80);
270 len_ = disp_offset + 4;
271 Memory::int32_at(&buf_[disp_offset]) = disp_value;
272 } else if (disp_value != 0 || (base_reg == 0x05)) {
273 // Need 8 bits of displacement.
274 buf_[0] = (modrm & 0x3f) | 0x40; // Mode 1.
275 len_ = disp_offset + 1;
276 buf_[disp_offset] = static_cast<byte>(disp_value);
277 } else {
278 // Need no displacement.
279 buf_[0] = (modrm & 0x3f); // Mode 0.
280 len_ = disp_offset;
281 }
282 if (has_sib) {
283 buf_[1] = operand.buf_[1];
284 }
285}
286
Steve Blocka7e24c12009-10-30 11:49:00 +0000287// -----------------------------------------------------------------------------
Andrei Popescu31002712010-02-23 13:46:05 +0000288// Implementation of Assembler.
Steve Blocka7e24c12009-10-30 11:49:00 +0000289
290#ifdef GENERATED_CODE_COVERAGE
291static void InitCoverageLog();
292#endif
293
294byte* Assembler::spare_buffer_ = NULL;
295
Steve Block3ce2e202009-11-05 08:53:23 +0000296Assembler::Assembler(void* buffer, int buffer_size)
297 : code_targets_(100) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000298 if (buffer == NULL) {
Andrei Popescu31002712010-02-23 13:46:05 +0000299 // Do our own buffer management.
Steve Blocka7e24c12009-10-30 11:49:00 +0000300 if (buffer_size <= kMinimalBufferSize) {
301 buffer_size = kMinimalBufferSize;
302
303 if (spare_buffer_ != NULL) {
304 buffer = spare_buffer_;
305 spare_buffer_ = NULL;
306 }
307 }
308 if (buffer == NULL) {
309 buffer_ = NewArray<byte>(buffer_size);
310 } else {
311 buffer_ = static_cast<byte*>(buffer);
312 }
313 buffer_size_ = buffer_size;
314 own_buffer_ = true;
315 } else {
Andrei Popescu31002712010-02-23 13:46:05 +0000316 // Use externally provided buffer instead.
Steve Blocka7e24c12009-10-30 11:49:00 +0000317 ASSERT(buffer_size > 0);
318 buffer_ = static_cast<byte*>(buffer);
319 buffer_size_ = buffer_size;
320 own_buffer_ = false;
321 }
322
323 // Clear the buffer in debug mode unless it was provided by the
324 // caller in which case we can't be sure it's okay to overwrite
325 // existing code in it.
326#ifdef DEBUG
327 if (own_buffer_) {
328 memset(buffer_, 0xCC, buffer_size); // int3
329 }
330#endif
331
Andrei Popescu31002712010-02-23 13:46:05 +0000332 // Setup buffer pointers.
Steve Blocka7e24c12009-10-30 11:49:00 +0000333 ASSERT(buffer_ != NULL);
334 pc_ = buffer_;
335 reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
336
337 last_pc_ = NULL;
338 current_statement_position_ = RelocInfo::kNoPosition;
339 current_position_ = RelocInfo::kNoPosition;
340 written_statement_position_ = current_statement_position_;
341 written_position_ = current_position_;
342#ifdef GENERATED_CODE_COVERAGE
343 InitCoverageLog();
344#endif
345}
346
347
348Assembler::~Assembler() {
349 if (own_buffer_) {
350 if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) {
351 spare_buffer_ = buffer_;
352 } else {
353 DeleteArray(buffer_);
354 }
355 }
356}
357
358
359void Assembler::GetCode(CodeDesc* desc) {
Andrei Popescu31002712010-02-23 13:46:05 +0000360 // Finalize code (at this point overflow() may be true, but the gap ensures
361 // that we are still not overlapping instructions and relocation info).
362 ASSERT(pc_ <= reloc_info_writer.pos()); // No overlap.
363 // Setup code descriptor.
Steve Blocka7e24c12009-10-30 11:49:00 +0000364 desc->buffer = buffer_;
365 desc->buffer_size = buffer_size_;
366 desc->instr_size = pc_offset();
367 ASSERT(desc->instr_size > 0); // Zero-size code objects upset the system.
Steve Blockd0582a62009-12-15 09:54:21 +0000368 desc->reloc_size =
369 static_cast<int>((buffer_ + buffer_size_) - reloc_info_writer.pos());
Steve Blocka7e24c12009-10-30 11:49:00 +0000370 desc->origin = this;
371
372 Counters::reloc_info_size.Increment(desc->reloc_size);
373}
374
375
376void Assembler::Align(int m) {
377 ASSERT(IsPowerOf2(m));
Steve Block8defd9f2010-07-08 12:39:36 +0100378 int delta = (m - (pc_offset() & (m - 1))) & (m - 1);
379 while (delta >= 9) {
380 nop(9);
381 delta -= 9;
382 }
383 if (delta > 0) {
384 nop(delta);
Steve Blocka7e24c12009-10-30 11:49:00 +0000385 }
386}
387
388
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100389void Assembler::CodeTargetAlign() {
390 Align(16); // Preferred alignment of jump targets on x64.
391}
392
393
Steve Blocka7e24c12009-10-30 11:49:00 +0000394void Assembler::bind_to(Label* L, int pos) {
395 ASSERT(!L->is_bound()); // Label may only be bound once.
396 last_pc_ = NULL;
397 ASSERT(0 <= pos && pos <= pc_offset()); // Position must be valid.
398 if (L->is_linked()) {
399 int current = L->pos();
400 int next = long_at(current);
401 while (next != current) {
Andrei Popescu31002712010-02-23 13:46:05 +0000402 // Relative address, relative to point after address.
Steve Blocka7e24c12009-10-30 11:49:00 +0000403 int imm32 = pos - (current + sizeof(int32_t));
404 long_at_put(current, imm32);
405 current = next;
406 next = long_at(next);
407 }
408 // Fix up last fixup on linked list.
409 int last_imm32 = pos - (current + sizeof(int32_t));
410 long_at_put(current, last_imm32);
411 }
412 L->bind_to(pos);
413}
414
415
416void Assembler::bind(Label* L) {
417 bind_to(L, pc_offset());
418}
419
420
421void Assembler::GrowBuffer() {
Andrei Popescu31002712010-02-23 13:46:05 +0000422 ASSERT(buffer_overflow());
Steve Blocka7e24c12009-10-30 11:49:00 +0000423 if (!own_buffer_) FATAL("external code buffer is too small");
424
Andrei Popescu31002712010-02-23 13:46:05 +0000425 // Compute new buffer size.
Steve Blocka7e24c12009-10-30 11:49:00 +0000426 CodeDesc desc; // the new buffer
427 if (buffer_size_ < 4*KB) {
428 desc.buffer_size = 4*KB;
429 } else {
430 desc.buffer_size = 2*buffer_size_;
431 }
432 // Some internal data structures overflow for very large buffers,
433 // they must ensure that kMaximalBufferSize is not too large.
434 if ((desc.buffer_size > kMaximalBufferSize) ||
Steve Block3ce2e202009-11-05 08:53:23 +0000435 (desc.buffer_size > Heap::MaxOldGenerationSize())) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000436 V8::FatalProcessOutOfMemory("Assembler::GrowBuffer");
437 }
438
Andrei Popescu31002712010-02-23 13:46:05 +0000439 // Setup new buffer.
Steve Blocka7e24c12009-10-30 11:49:00 +0000440 desc.buffer = NewArray<byte>(desc.buffer_size);
441 desc.instr_size = pc_offset();
Steve Blockd0582a62009-12-15 09:54:21 +0000442 desc.reloc_size =
443 static_cast<int>((buffer_ + buffer_size_) - (reloc_info_writer.pos()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000444
445 // Clear the buffer in debug mode. Use 'int3' instructions to make
446 // sure to get into problems if we ever run uninitialized code.
447#ifdef DEBUG
448 memset(desc.buffer, 0xCC, desc.buffer_size);
449#endif
450
Andrei Popescu31002712010-02-23 13:46:05 +0000451 // Copy the data.
Steve Blocka7e24c12009-10-30 11:49:00 +0000452 intptr_t pc_delta = desc.buffer - buffer_;
453 intptr_t rc_delta = (desc.buffer + desc.buffer_size) -
454 (buffer_ + buffer_size_);
455 memmove(desc.buffer, buffer_, desc.instr_size);
456 memmove(rc_delta + reloc_info_writer.pos(),
457 reloc_info_writer.pos(), desc.reloc_size);
458
Andrei Popescu31002712010-02-23 13:46:05 +0000459 // Switch buffers.
Steve Blocka7e24c12009-10-30 11:49:00 +0000460 if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) {
461 spare_buffer_ = buffer_;
462 } else {
463 DeleteArray(buffer_);
464 }
465 buffer_ = desc.buffer;
466 buffer_size_ = desc.buffer_size;
467 pc_ += pc_delta;
468 if (last_pc_ != NULL) {
469 last_pc_ += pc_delta;
470 }
471 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
472 reloc_info_writer.last_pc() + pc_delta);
473
Andrei Popescu31002712010-02-23 13:46:05 +0000474 // Relocate runtime entries.
Steve Blocka7e24c12009-10-30 11:49:00 +0000475 for (RelocIterator it(desc); !it.done(); it.next()) {
476 RelocInfo::Mode rmode = it.rinfo()->rmode();
477 if (rmode == RelocInfo::INTERNAL_REFERENCE) {
478 intptr_t* p = reinterpret_cast<intptr_t*>(it.rinfo()->pc());
479 if (*p != 0) { // 0 means uninitialized.
480 *p += pc_delta;
481 }
482 }
483 }
484
485 ASSERT(!buffer_overflow());
486}
487
488
489void Assembler::emit_operand(int code, const Operand& adr) {
490 ASSERT(is_uint3(code));
491 const unsigned length = adr.len_;
492 ASSERT(length > 0);
493
494 // Emit updated ModR/M byte containing the given register.
495 ASSERT((adr.buf_[0] & 0x38) == 0);
496 pc_[0] = adr.buf_[0] | code << 3;
497
498 // Emit the rest of the encoded operand.
499 for (unsigned i = 1; i < length; i++) pc_[i] = adr.buf_[i];
500 pc_ += length;
501}
502
503
Andrei Popescu31002712010-02-23 13:46:05 +0000504// Assembler Instruction implementations.
Steve Blocka7e24c12009-10-30 11:49:00 +0000505
506void Assembler::arithmetic_op(byte opcode, Register reg, const Operand& op) {
507 EnsureSpace ensure_space(this);
508 last_pc_ = pc_;
509 emit_rex_64(reg, op);
510 emit(opcode);
511 emit_operand(reg, op);
512}
513
514
515void Assembler::arithmetic_op(byte opcode, Register reg, Register rm_reg) {
516 EnsureSpace ensure_space(this);
517 last_pc_ = pc_;
Leon Clarkef7060e22010-06-03 12:02:55 +0100518 ASSERT((opcode & 0xC6) == 2);
519 if (rm_reg.low_bits() == 4) { // Forces SIB byte.
520 // Swap reg and rm_reg and change opcode operand order.
521 emit_rex_64(rm_reg, reg);
522 emit(opcode ^ 0x02);
523 emit_modrm(rm_reg, reg);
524 } else {
525 emit_rex_64(reg, rm_reg);
526 emit(opcode);
527 emit_modrm(reg, rm_reg);
528 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000529}
530
531
532void Assembler::arithmetic_op_16(byte opcode, Register reg, Register rm_reg) {
533 EnsureSpace ensure_space(this);
534 last_pc_ = pc_;
Leon Clarkef7060e22010-06-03 12:02:55 +0100535 ASSERT((opcode & 0xC6) == 2);
536 if (rm_reg.low_bits() == 4) { // Forces SIB byte.
537 // Swap reg and rm_reg and change opcode operand order.
538 emit(0x66);
539 emit_optional_rex_32(rm_reg, reg);
540 emit(opcode ^ 0x02);
541 emit_modrm(rm_reg, reg);
542 } else {
543 emit(0x66);
544 emit_optional_rex_32(reg, rm_reg);
545 emit(opcode);
546 emit_modrm(reg, rm_reg);
547 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000548}
549
550
551void Assembler::arithmetic_op_16(byte opcode,
552 Register reg,
553 const Operand& rm_reg) {
554 EnsureSpace ensure_space(this);
555 last_pc_ = pc_;
556 emit(0x66);
557 emit_optional_rex_32(reg, rm_reg);
558 emit(opcode);
559 emit_operand(reg, rm_reg);
560}
561
562
563void Assembler::arithmetic_op_32(byte opcode, Register reg, Register rm_reg) {
564 EnsureSpace ensure_space(this);
565 last_pc_ = pc_;
Leon Clarkef7060e22010-06-03 12:02:55 +0100566 ASSERT((opcode & 0xC6) == 2);
567 if (rm_reg.low_bits() == 4) { // Forces SIB byte.
568 // Swap reg and rm_reg and change opcode operand order.
569 emit_optional_rex_32(rm_reg, reg);
570 emit(opcode ^ 0x02); // E.g. 0x03 -> 0x01 for ADD.
571 emit_modrm(rm_reg, reg);
572 } else {
573 emit_optional_rex_32(reg, rm_reg);
574 emit(opcode);
575 emit_modrm(reg, rm_reg);
576 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000577}
578
579
580void Assembler::arithmetic_op_32(byte opcode,
581 Register reg,
582 const Operand& rm_reg) {
583 EnsureSpace ensure_space(this);
584 last_pc_ = pc_;
585 emit_optional_rex_32(reg, rm_reg);
586 emit(opcode);
587 emit_operand(reg, rm_reg);
588}
589
590
591void Assembler::immediate_arithmetic_op(byte subcode,
592 Register dst,
593 Immediate src) {
594 EnsureSpace ensure_space(this);
595 last_pc_ = pc_;
596 emit_rex_64(dst);
597 if (is_int8(src.value_)) {
598 emit(0x83);
599 emit_modrm(subcode, dst);
600 emit(src.value_);
601 } else if (dst.is(rax)) {
602 emit(0x05 | (subcode << 3));
603 emitl(src.value_);
604 } else {
605 emit(0x81);
606 emit_modrm(subcode, dst);
607 emitl(src.value_);
608 }
609}
610
611void Assembler::immediate_arithmetic_op(byte subcode,
612 const Operand& dst,
613 Immediate src) {
614 EnsureSpace ensure_space(this);
615 last_pc_ = pc_;
616 emit_rex_64(dst);
617 if (is_int8(src.value_)) {
618 emit(0x83);
619 emit_operand(subcode, dst);
620 emit(src.value_);
621 } else {
622 emit(0x81);
623 emit_operand(subcode, dst);
624 emitl(src.value_);
625 }
626}
627
628
629void Assembler::immediate_arithmetic_op_16(byte subcode,
630 Register dst,
631 Immediate src) {
632 EnsureSpace ensure_space(this);
633 last_pc_ = pc_;
634 emit(0x66); // Operand size override prefix.
635 emit_optional_rex_32(dst);
636 if (is_int8(src.value_)) {
637 emit(0x83);
638 emit_modrm(subcode, dst);
639 emit(src.value_);
640 } else if (dst.is(rax)) {
641 emit(0x05 | (subcode << 3));
Steve Block3ce2e202009-11-05 08:53:23 +0000642 emitw(src.value_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000643 } else {
644 emit(0x81);
645 emit_modrm(subcode, dst);
Steve Block3ce2e202009-11-05 08:53:23 +0000646 emitw(src.value_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000647 }
648}
649
650
651void Assembler::immediate_arithmetic_op_16(byte subcode,
652 const Operand& dst,
653 Immediate src) {
654 EnsureSpace ensure_space(this);
655 last_pc_ = pc_;
656 emit(0x66); // Operand size override prefix.
657 emit_optional_rex_32(dst);
658 if (is_int8(src.value_)) {
659 emit(0x83);
660 emit_operand(subcode, dst);
661 emit(src.value_);
662 } else {
663 emit(0x81);
664 emit_operand(subcode, dst);
Steve Block3ce2e202009-11-05 08:53:23 +0000665 emitw(src.value_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000666 }
667}
668
669
670void Assembler::immediate_arithmetic_op_32(byte subcode,
671 Register dst,
672 Immediate src) {
673 EnsureSpace ensure_space(this);
674 last_pc_ = pc_;
675 emit_optional_rex_32(dst);
676 if (is_int8(src.value_)) {
677 emit(0x83);
678 emit_modrm(subcode, dst);
679 emit(src.value_);
680 } else if (dst.is(rax)) {
681 emit(0x05 | (subcode << 3));
682 emitl(src.value_);
683 } else {
684 emit(0x81);
685 emit_modrm(subcode, dst);
686 emitl(src.value_);
687 }
688}
689
690
691void Assembler::immediate_arithmetic_op_32(byte subcode,
692 const Operand& dst,
693 Immediate src) {
694 EnsureSpace ensure_space(this);
695 last_pc_ = pc_;
696 emit_optional_rex_32(dst);
697 if (is_int8(src.value_)) {
698 emit(0x83);
699 emit_operand(subcode, dst);
700 emit(src.value_);
701 } else {
702 emit(0x81);
703 emit_operand(subcode, dst);
704 emitl(src.value_);
705 }
706}
707
708
709void Assembler::immediate_arithmetic_op_8(byte subcode,
710 const Operand& dst,
711 Immediate src) {
712 EnsureSpace ensure_space(this);
713 last_pc_ = pc_;
714 emit_optional_rex_32(dst);
715 ASSERT(is_int8(src.value_) || is_uint8(src.value_));
716 emit(0x80);
717 emit_operand(subcode, dst);
718 emit(src.value_);
719}
720
721
722void Assembler::immediate_arithmetic_op_8(byte subcode,
723 Register dst,
724 Immediate src) {
725 EnsureSpace ensure_space(this);
726 last_pc_ = pc_;
727 if (dst.code() > 3) {
728 // Use 64-bit mode byte registers.
729 emit_rex_64(dst);
730 }
731 ASSERT(is_int8(src.value_) || is_uint8(src.value_));
732 emit(0x80);
733 emit_modrm(subcode, dst);
734 emit(src.value_);
735}
736
737
738void Assembler::shift(Register dst, Immediate shift_amount, int subcode) {
739 EnsureSpace ensure_space(this);
740 last_pc_ = pc_;
741 ASSERT(is_uint6(shift_amount.value_)); // illegal shift count
742 if (shift_amount.value_ == 1) {
743 emit_rex_64(dst);
744 emit(0xD1);
745 emit_modrm(subcode, dst);
746 } else {
747 emit_rex_64(dst);
748 emit(0xC1);
749 emit_modrm(subcode, dst);
750 emit(shift_amount.value_);
751 }
752}
753
754
755void Assembler::shift(Register dst, int subcode) {
756 EnsureSpace ensure_space(this);
757 last_pc_ = pc_;
758 emit_rex_64(dst);
759 emit(0xD3);
760 emit_modrm(subcode, dst);
761}
762
763
764void Assembler::shift_32(Register dst, int subcode) {
765 EnsureSpace ensure_space(this);
766 last_pc_ = pc_;
767 emit_optional_rex_32(dst);
768 emit(0xD3);
769 emit_modrm(subcode, dst);
770}
771
772
773void Assembler::shift_32(Register dst, Immediate shift_amount, int subcode) {
774 EnsureSpace ensure_space(this);
775 last_pc_ = pc_;
Steve Block3ce2e202009-11-05 08:53:23 +0000776 ASSERT(is_uint5(shift_amount.value_)); // illegal shift count
Steve Blocka7e24c12009-10-30 11:49:00 +0000777 if (shift_amount.value_ == 1) {
778 emit_optional_rex_32(dst);
779 emit(0xD1);
780 emit_modrm(subcode, dst);
781 } else {
782 emit_optional_rex_32(dst);
783 emit(0xC1);
784 emit_modrm(subcode, dst);
785 emit(shift_amount.value_);
786 }
787}
788
789
790void Assembler::bt(const Operand& dst, Register src) {
791 EnsureSpace ensure_space(this);
792 last_pc_ = pc_;
793 emit_rex_64(src, dst);
794 emit(0x0F);
795 emit(0xA3);
796 emit_operand(src, dst);
797}
798
799
800void Assembler::bts(const Operand& dst, Register src) {
801 EnsureSpace ensure_space(this);
802 last_pc_ = pc_;
803 emit_rex_64(src, dst);
804 emit(0x0F);
805 emit(0xAB);
806 emit_operand(src, dst);
807}
808
809
810void Assembler::call(Label* L) {
811 EnsureSpace ensure_space(this);
812 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000813 // 1110 1000 #32-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +0000814 emit(0xE8);
815 if (L->is_bound()) {
816 int offset = L->pos() - pc_offset() - sizeof(int32_t);
817 ASSERT(offset <= 0);
818 emitl(offset);
819 } else if (L->is_linked()) {
820 emitl(L->pos());
821 L->link_to(pc_offset() - sizeof(int32_t));
822 } else {
823 ASSERT(L->is_unused());
824 int32_t current = pc_offset();
825 emitl(current);
826 L->link_to(current);
827 }
828}
829
830
Steve Block3ce2e202009-11-05 08:53:23 +0000831void Assembler::call(Handle<Code> target, RelocInfo::Mode rmode) {
832 EnsureSpace ensure_space(this);
833 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000834 // 1110 1000 #32-bit disp.
Steve Block3ce2e202009-11-05 08:53:23 +0000835 emit(0xE8);
836 emit_code_target(target, rmode);
837}
838
839
Steve Blocka7e24c12009-10-30 11:49:00 +0000840void Assembler::call(Register adr) {
841 EnsureSpace ensure_space(this);
842 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000843 // Opcode: FF /2 r64.
Steve Block8defd9f2010-07-08 12:39:36 +0100844 emit_optional_rex_32(adr);
Steve Blocka7e24c12009-10-30 11:49:00 +0000845 emit(0xFF);
846 emit_modrm(0x2, adr);
847}
848
849
850void Assembler::call(const Operand& op) {
851 EnsureSpace ensure_space(this);
852 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000853 // Opcode: FF /2 m64.
Steve Block8defd9f2010-07-08 12:39:36 +0100854 emit_optional_rex_32(op);
Steve Blocka7e24c12009-10-30 11:49:00 +0000855 emit(0xFF);
Steve Block8defd9f2010-07-08 12:39:36 +0100856 emit_operand(0x2, op);
Steve Blocka7e24c12009-10-30 11:49:00 +0000857}
858
859
Steve Block3ce2e202009-11-05 08:53:23 +0000860void Assembler::clc() {
861 EnsureSpace ensure_space(this);
862 last_pc_ = pc_;
863 emit(0xF8);
864}
865
Steve Blocka7e24c12009-10-30 11:49:00 +0000866void Assembler::cdq() {
867 EnsureSpace ensure_space(this);
868 last_pc_ = pc_;
869 emit(0x99);
870}
871
872
873void Assembler::cmovq(Condition cc, Register dst, Register src) {
Steve Block3ce2e202009-11-05 08:53:23 +0000874 if (cc == always) {
875 movq(dst, src);
876 } else if (cc == never) {
877 return;
878 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000879 // No need to check CpuInfo for CMOV support, it's a required part of the
880 // 64-bit architecture.
881 ASSERT(cc >= 0); // Use mov for unconditional moves.
882 EnsureSpace ensure_space(this);
883 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000884 // Opcode: REX.W 0f 40 + cc /r.
Steve Blocka7e24c12009-10-30 11:49:00 +0000885 emit_rex_64(dst, src);
886 emit(0x0f);
887 emit(0x40 + cc);
888 emit_modrm(dst, src);
889}
890
891
892void Assembler::cmovq(Condition cc, Register dst, const Operand& src) {
Steve Block3ce2e202009-11-05 08:53:23 +0000893 if (cc == always) {
894 movq(dst, src);
895 } else if (cc == never) {
896 return;
897 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000898 ASSERT(cc >= 0);
899 EnsureSpace ensure_space(this);
900 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000901 // Opcode: REX.W 0f 40 + cc /r.
Steve Blocka7e24c12009-10-30 11:49:00 +0000902 emit_rex_64(dst, src);
903 emit(0x0f);
904 emit(0x40 + cc);
905 emit_operand(dst, src);
906}
907
908
909void Assembler::cmovl(Condition cc, Register dst, Register src) {
Steve Block3ce2e202009-11-05 08:53:23 +0000910 if (cc == always) {
911 movl(dst, src);
912 } else if (cc == never) {
913 return;
914 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000915 ASSERT(cc >= 0);
916 EnsureSpace ensure_space(this);
917 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000918 // Opcode: 0f 40 + cc /r.
Steve Blocka7e24c12009-10-30 11:49:00 +0000919 emit_optional_rex_32(dst, src);
920 emit(0x0f);
921 emit(0x40 + cc);
922 emit_modrm(dst, src);
923}
924
925
926void Assembler::cmovl(Condition cc, Register dst, const Operand& src) {
Steve Block3ce2e202009-11-05 08:53:23 +0000927 if (cc == always) {
928 movl(dst, src);
929 } else if (cc == never) {
930 return;
931 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000932 ASSERT(cc >= 0);
933 EnsureSpace ensure_space(this);
934 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000935 // Opcode: 0f 40 + cc /r.
Steve Blocka7e24c12009-10-30 11:49:00 +0000936 emit_optional_rex_32(dst, src);
937 emit(0x0f);
938 emit(0x40 + cc);
939 emit_operand(dst, src);
940}
941
942
943void Assembler::cmpb_al(Immediate imm8) {
944 ASSERT(is_int8(imm8.value_) || is_uint8(imm8.value_));
945 EnsureSpace ensure_space(this);
946 last_pc_ = pc_;
947 emit(0x3c);
948 emit(imm8.value_);
949}
950
951
952void Assembler::cpuid() {
Steve Blockd0582a62009-12-15 09:54:21 +0000953 ASSERT(CpuFeatures::IsEnabled(CPUID));
Steve Blocka7e24c12009-10-30 11:49:00 +0000954 EnsureSpace ensure_space(this);
955 last_pc_ = pc_;
956 emit(0x0F);
957 emit(0xA2);
958}
959
960
961void Assembler::cqo() {
962 EnsureSpace ensure_space(this);
963 last_pc_ = pc_;
964 emit_rex_64();
965 emit(0x99);
966}
967
968
969void Assembler::decq(Register dst) {
970 EnsureSpace ensure_space(this);
971 last_pc_ = pc_;
972 emit_rex_64(dst);
973 emit(0xFF);
974 emit_modrm(0x1, dst);
975}
976
977
978void Assembler::decq(const Operand& dst) {
979 EnsureSpace ensure_space(this);
980 last_pc_ = pc_;
981 emit_rex_64(dst);
982 emit(0xFF);
983 emit_operand(1, dst);
984}
985
986
987void Assembler::decl(Register dst) {
988 EnsureSpace ensure_space(this);
989 last_pc_ = pc_;
990 emit_optional_rex_32(dst);
991 emit(0xFF);
992 emit_modrm(0x1, dst);
993}
994
995
996void Assembler::decl(const Operand& dst) {
997 EnsureSpace ensure_space(this);
998 last_pc_ = pc_;
999 emit_optional_rex_32(dst);
1000 emit(0xFF);
1001 emit_operand(1, dst);
1002}
1003
1004
Steve Block3ce2e202009-11-05 08:53:23 +00001005void Assembler::decb(Register dst) {
1006 EnsureSpace ensure_space(this);
1007 last_pc_ = pc_;
1008 if (dst.code() > 3) {
1009 // Register is not one of al, bl, cl, dl. Its encoding needs REX.
1010 emit_rex_32(dst);
1011 }
1012 emit(0xFE);
1013 emit_modrm(0x1, dst);
1014}
1015
1016
1017void Assembler::decb(const Operand& dst) {
1018 EnsureSpace ensure_space(this);
1019 last_pc_ = pc_;
1020 emit_optional_rex_32(dst);
1021 emit(0xFE);
1022 emit_operand(1, dst);
1023}
1024
1025
Steve Blocka7e24c12009-10-30 11:49:00 +00001026void Assembler::enter(Immediate size) {
1027 EnsureSpace ensure_space(this);
1028 last_pc_ = pc_;
1029 emit(0xC8);
1030 emitw(size.value_); // 16 bit operand, always.
1031 emit(0);
1032}
1033
1034
1035void Assembler::hlt() {
1036 EnsureSpace ensure_space(this);
1037 last_pc_ = pc_;
1038 emit(0xF4);
1039}
1040
1041
1042void Assembler::idivq(Register src) {
1043 EnsureSpace ensure_space(this);
1044 last_pc_ = pc_;
1045 emit_rex_64(src);
1046 emit(0xF7);
1047 emit_modrm(0x7, src);
1048}
1049
1050
1051void Assembler::idivl(Register src) {
1052 EnsureSpace ensure_space(this);
1053 last_pc_ = pc_;
1054 emit_optional_rex_32(src);
1055 emit(0xF7);
1056 emit_modrm(0x7, src);
1057}
1058
1059
1060void Assembler::imul(Register src) {
1061 EnsureSpace ensure_space(this);
1062 last_pc_ = pc_;
1063 emit_rex_64(src);
1064 emit(0xF7);
1065 emit_modrm(0x5, src);
1066}
1067
1068
1069void Assembler::imul(Register dst, Register src) {
1070 EnsureSpace ensure_space(this);
1071 last_pc_ = pc_;
1072 emit_rex_64(dst, src);
1073 emit(0x0F);
1074 emit(0xAF);
1075 emit_modrm(dst, src);
1076}
1077
1078
1079void Assembler::imul(Register dst, const Operand& src) {
1080 EnsureSpace ensure_space(this);
1081 last_pc_ = pc_;
1082 emit_rex_64(dst, src);
1083 emit(0x0F);
1084 emit(0xAF);
1085 emit_operand(dst, src);
1086}
1087
1088
1089void Assembler::imul(Register dst, Register src, Immediate imm) {
1090 EnsureSpace ensure_space(this);
1091 last_pc_ = pc_;
1092 emit_rex_64(dst, src);
1093 if (is_int8(imm.value_)) {
1094 emit(0x6B);
1095 emit_modrm(dst, src);
1096 emit(imm.value_);
1097 } else {
1098 emit(0x69);
1099 emit_modrm(dst, src);
1100 emitl(imm.value_);
1101 }
1102}
1103
1104
1105void Assembler::imull(Register dst, Register src) {
1106 EnsureSpace ensure_space(this);
1107 last_pc_ = pc_;
1108 emit_optional_rex_32(dst, src);
1109 emit(0x0F);
1110 emit(0xAF);
1111 emit_modrm(dst, src);
1112}
1113
1114
Steve Block6ded16b2010-05-10 14:33:55 +01001115void Assembler::imull(Register dst, Register src, Immediate imm) {
1116 EnsureSpace ensure_space(this);
1117 last_pc_ = pc_;
1118 emit_optional_rex_32(dst, src);
1119 if (is_int8(imm.value_)) {
1120 emit(0x6B);
1121 emit_modrm(dst, src);
1122 emit(imm.value_);
1123 } else {
1124 emit(0x69);
1125 emit_modrm(dst, src);
1126 emitl(imm.value_);
1127 }
1128}
1129
1130
Steve Blocka7e24c12009-10-30 11:49:00 +00001131void Assembler::incq(Register dst) {
1132 EnsureSpace ensure_space(this);
1133 last_pc_ = pc_;
1134 emit_rex_64(dst);
1135 emit(0xFF);
1136 emit_modrm(0x0, dst);
1137}
1138
1139
1140void Assembler::incq(const Operand& dst) {
1141 EnsureSpace ensure_space(this);
1142 last_pc_ = pc_;
1143 emit_rex_64(dst);
1144 emit(0xFF);
1145 emit_operand(0, dst);
1146}
1147
1148
1149void Assembler::incl(const Operand& dst) {
1150 EnsureSpace ensure_space(this);
1151 last_pc_ = pc_;
1152 emit_optional_rex_32(dst);
1153 emit(0xFF);
1154 emit_operand(0, dst);
1155}
1156
1157
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001158void Assembler::incl(Register dst) {
1159 EnsureSpace ensure_space(this);
1160 last_pc_ = pc_;
1161 emit_optional_rex_32(dst);
1162 emit(0xFF);
1163 emit_modrm(0, dst);
1164}
1165
1166
Steve Blocka7e24c12009-10-30 11:49:00 +00001167void Assembler::int3() {
1168 EnsureSpace ensure_space(this);
1169 last_pc_ = pc_;
1170 emit(0xCC);
1171}
1172
1173
1174void Assembler::j(Condition cc, Label* L) {
Steve Block3ce2e202009-11-05 08:53:23 +00001175 if (cc == always) {
1176 jmp(L);
1177 return;
1178 } else if (cc == never) {
1179 return;
1180 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001181 EnsureSpace ensure_space(this);
1182 last_pc_ = pc_;
1183 ASSERT(is_uint4(cc));
1184 if (L->is_bound()) {
1185 const int short_size = 2;
1186 const int long_size = 6;
1187 int offs = L->pos() - pc_offset();
1188 ASSERT(offs <= 0);
1189 if (is_int8(offs - short_size)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001190 // 0111 tttn #8-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001191 emit(0x70 | cc);
1192 emit((offs - short_size) & 0xFF);
1193 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00001194 // 0000 1111 1000 tttn #32-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001195 emit(0x0F);
1196 emit(0x80 | cc);
1197 emitl(offs - long_size);
1198 }
1199 } else if (L->is_linked()) {
Andrei Popescu31002712010-02-23 13:46:05 +00001200 // 0000 1111 1000 tttn #32-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001201 emit(0x0F);
1202 emit(0x80 | cc);
1203 emitl(L->pos());
1204 L->link_to(pc_offset() - sizeof(int32_t));
1205 } else {
1206 ASSERT(L->is_unused());
1207 emit(0x0F);
1208 emit(0x80 | cc);
1209 int32_t current = pc_offset();
1210 emitl(current);
1211 L->link_to(current);
1212 }
1213}
1214
1215
Steve Block3ce2e202009-11-05 08:53:23 +00001216void Assembler::j(Condition cc,
1217 Handle<Code> target,
1218 RelocInfo::Mode rmode) {
1219 EnsureSpace ensure_space(this);
1220 last_pc_ = pc_;
1221 ASSERT(is_uint4(cc));
Andrei Popescu31002712010-02-23 13:46:05 +00001222 // 0000 1111 1000 tttn #32-bit disp.
Steve Block3ce2e202009-11-05 08:53:23 +00001223 emit(0x0F);
1224 emit(0x80 | cc);
1225 emit_code_target(target, rmode);
1226}
1227
1228
Steve Blocka7e24c12009-10-30 11:49:00 +00001229void Assembler::jmp(Label* L) {
1230 EnsureSpace ensure_space(this);
1231 last_pc_ = pc_;
Steve Block6ded16b2010-05-10 14:33:55 +01001232 const int short_size = sizeof(int8_t);
1233 const int long_size = sizeof(int32_t);
Steve Blocka7e24c12009-10-30 11:49:00 +00001234 if (L->is_bound()) {
1235 int offs = L->pos() - pc_offset() - 1;
1236 ASSERT(offs <= 0);
Steve Block6ded16b2010-05-10 14:33:55 +01001237 if (is_int8(offs - short_size)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001238 // 1110 1011 #8-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001239 emit(0xEB);
Steve Block6ded16b2010-05-10 14:33:55 +01001240 emit((offs - short_size) & 0xFF);
Steve Blocka7e24c12009-10-30 11:49:00 +00001241 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00001242 // 1110 1001 #32-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001243 emit(0xE9);
Steve Block6ded16b2010-05-10 14:33:55 +01001244 emitl(offs - long_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00001245 }
1246 } else if (L->is_linked()) {
Andrei Popescu31002712010-02-23 13:46:05 +00001247 // 1110 1001 #32-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001248 emit(0xE9);
1249 emitl(L->pos());
Steve Block6ded16b2010-05-10 14:33:55 +01001250 L->link_to(pc_offset() - long_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00001251 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00001252 // 1110 1001 #32-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001253 ASSERT(L->is_unused());
1254 emit(0xE9);
1255 int32_t current = pc_offset();
1256 emitl(current);
1257 L->link_to(current);
1258 }
1259}
1260
1261
Steve Block3ce2e202009-11-05 08:53:23 +00001262void Assembler::jmp(Handle<Code> target, RelocInfo::Mode rmode) {
1263 EnsureSpace ensure_space(this);
1264 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +00001265 // 1110 1001 #32-bit disp.
Steve Block3ce2e202009-11-05 08:53:23 +00001266 emit(0xE9);
1267 emit_code_target(target, rmode);
1268}
1269
1270
Steve Blocka7e24c12009-10-30 11:49:00 +00001271void Assembler::jmp(Register target) {
1272 EnsureSpace ensure_space(this);
1273 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +00001274 // Opcode FF/4 r64.
Steve Block8defd9f2010-07-08 12:39:36 +01001275 emit_optional_rex_32(target);
Steve Blocka7e24c12009-10-30 11:49:00 +00001276 emit(0xFF);
1277 emit_modrm(0x4, target);
1278}
1279
1280
1281void Assembler::jmp(const Operand& src) {
1282 EnsureSpace ensure_space(this);
1283 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +00001284 // Opcode FF/4 m64.
Steve Blocka7e24c12009-10-30 11:49:00 +00001285 emit_optional_rex_32(src);
1286 emit(0xFF);
1287 emit_operand(0x4, src);
1288}
1289
1290
1291void Assembler::lea(Register dst, const Operand& src) {
1292 EnsureSpace ensure_space(this);
1293 last_pc_ = pc_;
1294 emit_rex_64(dst, src);
1295 emit(0x8D);
1296 emit_operand(dst, src);
1297}
1298
1299
Steve Block6ded16b2010-05-10 14:33:55 +01001300void Assembler::leal(Register dst, const Operand& src) {
1301 EnsureSpace ensure_space(this);
1302 last_pc_ = pc_;
1303 emit_optional_rex_32(dst, src);
1304 emit(0x8D);
1305 emit_operand(dst, src);
1306}
1307
1308
Steve Blocka7e24c12009-10-30 11:49:00 +00001309void Assembler::load_rax(void* value, RelocInfo::Mode mode) {
1310 EnsureSpace ensure_space(this);
1311 last_pc_ = pc_;
1312 emit(0x48); // REX.W
1313 emit(0xA1);
1314 emitq(reinterpret_cast<uintptr_t>(value), mode);
1315}
1316
1317
1318void Assembler::load_rax(ExternalReference ref) {
1319 load_rax(ref.address(), RelocInfo::EXTERNAL_REFERENCE);
1320}
1321
1322
1323void Assembler::leave() {
1324 EnsureSpace ensure_space(this);
1325 last_pc_ = pc_;
1326 emit(0xC9);
1327}
1328
1329
1330void Assembler::movb(Register dst, const Operand& src) {
1331 EnsureSpace ensure_space(this);
1332 last_pc_ = pc_;
1333 emit_rex_32(dst, src);
1334 emit(0x8A);
1335 emit_operand(dst, src);
1336}
1337
Steve Block6ded16b2010-05-10 14:33:55 +01001338
Steve Blocka7e24c12009-10-30 11:49:00 +00001339void Assembler::movb(Register dst, Immediate imm) {
1340 EnsureSpace ensure_space(this);
1341 last_pc_ = pc_;
1342 emit_rex_32(dst);
1343 emit(0xC6);
1344 emit_modrm(0x0, dst);
1345 emit(imm.value_);
1346}
1347
Steve Block6ded16b2010-05-10 14:33:55 +01001348
Steve Blocka7e24c12009-10-30 11:49:00 +00001349void Assembler::movb(const Operand& dst, Register src) {
1350 EnsureSpace ensure_space(this);
1351 last_pc_ = pc_;
1352 emit_rex_32(src, dst);
1353 emit(0x88);
1354 emit_operand(src, dst);
1355}
1356
Steve Block6ded16b2010-05-10 14:33:55 +01001357
Steve Block3ce2e202009-11-05 08:53:23 +00001358void Assembler::movw(const Operand& dst, Register src) {
1359 EnsureSpace ensure_space(this);
1360 last_pc_ = pc_;
1361 emit(0x66);
1362 emit_optional_rex_32(src, dst);
1363 emit(0x89);
1364 emit_operand(src, dst);
1365}
1366
Steve Block6ded16b2010-05-10 14:33:55 +01001367
Steve Blocka7e24c12009-10-30 11:49:00 +00001368void Assembler::movl(Register dst, const Operand& src) {
1369 EnsureSpace ensure_space(this);
1370 last_pc_ = pc_;
1371 emit_optional_rex_32(dst, src);
1372 emit(0x8B);
1373 emit_operand(dst, src);
1374}
1375
1376
1377void Assembler::movl(Register dst, Register src) {
1378 EnsureSpace ensure_space(this);
1379 last_pc_ = pc_;
Leon Clarkef7060e22010-06-03 12:02:55 +01001380 if (src.low_bits() == 4) {
1381 emit_optional_rex_32(src, dst);
1382 emit(0x89);
1383 emit_modrm(src, dst);
1384 } else {
1385 emit_optional_rex_32(dst, src);
1386 emit(0x8B);
1387 emit_modrm(dst, src);
1388 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001389}
1390
1391
1392void Assembler::movl(const Operand& dst, Register src) {
1393 EnsureSpace ensure_space(this);
1394 last_pc_ = pc_;
1395 emit_optional_rex_32(src, dst);
1396 emit(0x89);
1397 emit_operand(src, dst);
1398}
1399
1400
1401void Assembler::movl(const Operand& dst, Immediate value) {
1402 EnsureSpace ensure_space(this);
1403 last_pc_ = pc_;
1404 emit_optional_rex_32(dst);
1405 emit(0xC7);
1406 emit_operand(0x0, dst);
1407 emit(value); // Only 32-bit immediates are possible, not 8-bit immediates.
1408}
1409
1410
1411void Assembler::movl(Register dst, Immediate value) {
1412 EnsureSpace ensure_space(this);
1413 last_pc_ = pc_;
1414 emit_optional_rex_32(dst);
1415 emit(0xC7);
1416 emit_modrm(0x0, dst);
1417 emit(value); // Only 32-bit immediates are possible, not 8-bit immediates.
1418}
1419
1420
1421void Assembler::movq(Register dst, const Operand& src) {
1422 EnsureSpace ensure_space(this);
1423 last_pc_ = pc_;
1424 emit_rex_64(dst, src);
1425 emit(0x8B);
1426 emit_operand(dst, src);
1427}
1428
1429
1430void Assembler::movq(Register dst, Register src) {
1431 EnsureSpace ensure_space(this);
1432 last_pc_ = pc_;
Leon Clarkef7060e22010-06-03 12:02:55 +01001433 if (src.low_bits() == 4) {
1434 emit_rex_64(src, dst);
1435 emit(0x89);
1436 emit_modrm(src, dst);
1437 } else {
1438 emit_rex_64(dst, src);
1439 emit(0x8B);
1440 emit_modrm(dst, src);
1441 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001442}
1443
1444
1445void Assembler::movq(Register dst, Immediate value) {
1446 EnsureSpace ensure_space(this);
1447 last_pc_ = pc_;
1448 emit_rex_64(dst);
1449 emit(0xC7);
1450 emit_modrm(0x0, dst);
1451 emit(value); // Only 32-bit immediates are possible, not 8-bit immediates.
1452}
1453
1454
1455void Assembler::movq(const Operand& dst, Register src) {
1456 EnsureSpace ensure_space(this);
1457 last_pc_ = pc_;
1458 emit_rex_64(src, dst);
1459 emit(0x89);
1460 emit_operand(src, dst);
1461}
1462
1463
1464void Assembler::movq(Register dst, void* value, RelocInfo::Mode rmode) {
1465 // This method must not be used with heap object references. The stored
1466 // address is not GC safe. Use the handle version instead.
1467 ASSERT(rmode > RelocInfo::LAST_GCED_ENUM);
1468 EnsureSpace ensure_space(this);
1469 last_pc_ = pc_;
1470 emit_rex_64(dst);
1471 emit(0xB8 | dst.low_bits());
1472 emitq(reinterpret_cast<uintptr_t>(value), rmode);
1473}
1474
1475
1476void Assembler::movq(Register dst, int64_t value, RelocInfo::Mode rmode) {
1477 // Non-relocatable values might not need a 64-bit representation.
1478 if (rmode == RelocInfo::NONE) {
1479 // Sadly, there is no zero or sign extending move for 8-bit immediates.
1480 if (is_int32(value)) {
1481 movq(dst, Immediate(static_cast<int32_t>(value)));
1482 return;
1483 } else if (is_uint32(value)) {
1484 movl(dst, Immediate(static_cast<int32_t>(value)));
1485 return;
1486 }
1487 // Value cannot be represented by 32 bits, so do a full 64 bit immediate
1488 // value.
1489 }
1490 EnsureSpace ensure_space(this);
1491 last_pc_ = pc_;
1492 emit_rex_64(dst);
1493 emit(0xB8 | dst.low_bits());
1494 emitq(value, rmode);
1495}
1496
1497
1498void Assembler::movq(Register dst, ExternalReference ref) {
Ben Murdochbb769b22010-08-11 14:56:33 +01001499 int64_t value = reinterpret_cast<int64_t>(ref.address());
1500 movq(dst, value, RelocInfo::EXTERNAL_REFERENCE);
Steve Blocka7e24c12009-10-30 11:49:00 +00001501}
1502
1503
1504void Assembler::movq(const Operand& dst, Immediate value) {
1505 EnsureSpace ensure_space(this);
1506 last_pc_ = pc_;
1507 emit_rex_64(dst);
1508 emit(0xC7);
1509 emit_operand(0, dst);
1510 emit(value);
1511}
1512
1513
Andrei Popescu31002712010-02-23 13:46:05 +00001514// Loads the ip-relative location of the src label into the target location
1515// (as a 32-bit offset sign extended to 64-bit).
Steve Blocka7e24c12009-10-30 11:49:00 +00001516void Assembler::movl(const Operand& dst, Label* src) {
1517 EnsureSpace ensure_space(this);
1518 last_pc_ = pc_;
1519 emit_optional_rex_32(dst);
1520 emit(0xC7);
1521 emit_operand(0, dst);
1522 if (src->is_bound()) {
1523 int offset = src->pos() - pc_offset() - sizeof(int32_t);
1524 ASSERT(offset <= 0);
1525 emitl(offset);
1526 } else if (src->is_linked()) {
1527 emitl(src->pos());
1528 src->link_to(pc_offset() - sizeof(int32_t));
1529 } else {
1530 ASSERT(src->is_unused());
1531 int32_t current = pc_offset();
1532 emitl(current);
1533 src->link_to(current);
1534 }
1535}
1536
1537
1538void Assembler::movq(Register dst, Handle<Object> value, RelocInfo::Mode mode) {
1539 // If there is no relocation info, emit the value of the handle efficiently
1540 // (possibly using less that 8 bytes for the value).
1541 if (mode == RelocInfo::NONE) {
1542 // There is no possible reason to store a heap pointer without relocation
1543 // info, so it must be a smi.
1544 ASSERT(value->IsSmi());
Steve Block3ce2e202009-11-05 08:53:23 +00001545 movq(dst, reinterpret_cast<int64_t>(*value), RelocInfo::NONE);
Steve Blocka7e24c12009-10-30 11:49:00 +00001546 } else {
1547 EnsureSpace ensure_space(this);
1548 last_pc_ = pc_;
1549 ASSERT(value->IsHeapObject());
1550 ASSERT(!Heap::InNewSpace(*value));
1551 emit_rex_64(dst);
1552 emit(0xB8 | dst.low_bits());
1553 emitq(reinterpret_cast<uintptr_t>(value.location()), mode);
1554 }
1555}
1556
1557
Steve Block3ce2e202009-11-05 08:53:23 +00001558void Assembler::movsxbq(Register dst, const Operand& src) {
1559 EnsureSpace ensure_space(this);
1560 last_pc_ = pc_;
Steve Block8defd9f2010-07-08 12:39:36 +01001561 emit_rex_64(dst, src);
Steve Block3ce2e202009-11-05 08:53:23 +00001562 emit(0x0F);
1563 emit(0xBE);
1564 emit_operand(dst, src);
1565}
1566
1567
1568void Assembler::movsxwq(Register dst, const Operand& src) {
1569 EnsureSpace ensure_space(this);
1570 last_pc_ = pc_;
1571 emit_rex_64(dst, src);
1572 emit(0x0F);
1573 emit(0xBF);
1574 emit_operand(dst, src);
1575}
1576
1577
Steve Blocka7e24c12009-10-30 11:49:00 +00001578void Assembler::movsxlq(Register dst, Register src) {
1579 EnsureSpace ensure_space(this);
1580 last_pc_ = pc_;
1581 emit_rex_64(dst, src);
1582 emit(0x63);
1583 emit_modrm(dst, src);
1584}
1585
1586
1587void Assembler::movsxlq(Register dst, const Operand& src) {
1588 EnsureSpace ensure_space(this);
1589 last_pc_ = pc_;
1590 emit_rex_64(dst, src);
1591 emit(0x63);
1592 emit_operand(dst, src);
1593}
1594
1595
1596void Assembler::movzxbq(Register dst, const Operand& src) {
1597 EnsureSpace ensure_space(this);
1598 last_pc_ = pc_;
Steve Block8defd9f2010-07-08 12:39:36 +01001599 emit_optional_rex_32(dst, src);
Steve Blocka7e24c12009-10-30 11:49:00 +00001600 emit(0x0F);
1601 emit(0xB6);
1602 emit_operand(dst, src);
1603}
1604
1605
1606void Assembler::movzxbl(Register dst, const Operand& src) {
1607 EnsureSpace ensure_space(this);
1608 last_pc_ = pc_;
1609 emit_optional_rex_32(dst, src);
1610 emit(0x0F);
1611 emit(0xB6);
1612 emit_operand(dst, src);
1613}
1614
1615
Steve Block3ce2e202009-11-05 08:53:23 +00001616void Assembler::movzxwq(Register dst, const Operand& src) {
1617 EnsureSpace ensure_space(this);
1618 last_pc_ = pc_;
Steve Block8defd9f2010-07-08 12:39:36 +01001619 emit_optional_rex_32(dst, src);
Steve Block3ce2e202009-11-05 08:53:23 +00001620 emit(0x0F);
1621 emit(0xB7);
1622 emit_operand(dst, src);
1623}
1624
1625
Steve Blocka7e24c12009-10-30 11:49:00 +00001626void Assembler::movzxwl(Register dst, const Operand& src) {
1627 EnsureSpace ensure_space(this);
1628 last_pc_ = pc_;
1629 emit_optional_rex_32(dst, src);
1630 emit(0x0F);
1631 emit(0xB7);
1632 emit_operand(dst, src);
1633}
1634
1635
Leon Clarked91b9f72010-01-27 17:25:45 +00001636void Assembler::repmovsb() {
1637 EnsureSpace ensure_space(this);
1638 last_pc_ = pc_;
1639 emit(0xF3);
1640 emit(0xA4);
1641}
1642
1643
1644void Assembler::repmovsw() {
1645 EnsureSpace ensure_space(this);
1646 last_pc_ = pc_;
1647 emit(0x66); // Operand size override.
1648 emit(0xF3);
1649 emit(0xA4);
1650}
1651
1652
1653void Assembler::repmovsl() {
1654 EnsureSpace ensure_space(this);
1655 last_pc_ = pc_;
1656 emit(0xF3);
1657 emit(0xA5);
1658}
1659
1660
1661void Assembler::repmovsq() {
1662 EnsureSpace ensure_space(this);
1663 last_pc_ = pc_;
1664 emit(0xF3);
1665 emit_rex_64();
1666 emit(0xA5);
1667}
1668
1669
Steve Blocka7e24c12009-10-30 11:49:00 +00001670void Assembler::mul(Register src) {
1671 EnsureSpace ensure_space(this);
1672 last_pc_ = pc_;
1673 emit_rex_64(src);
1674 emit(0xF7);
1675 emit_modrm(0x4, src);
1676}
1677
1678
1679void Assembler::neg(Register dst) {
1680 EnsureSpace ensure_space(this);
1681 last_pc_ = pc_;
1682 emit_rex_64(dst);
1683 emit(0xF7);
1684 emit_modrm(0x3, dst);
1685}
1686
1687
1688void Assembler::negl(Register dst) {
1689 EnsureSpace ensure_space(this);
1690 last_pc_ = pc_;
1691 emit_optional_rex_32(dst);
1692 emit(0xF7);
1693 emit_modrm(0x3, dst);
1694}
1695
1696
1697void Assembler::neg(const Operand& dst) {
1698 EnsureSpace ensure_space(this);
1699 last_pc_ = pc_;
1700 emit_rex_64(dst);
1701 emit(0xF7);
1702 emit_operand(3, dst);
1703}
1704
1705
1706void Assembler::nop() {
1707 EnsureSpace ensure_space(this);
1708 last_pc_ = pc_;
1709 emit(0x90);
1710}
1711
1712
1713void Assembler::not_(Register dst) {
1714 EnsureSpace ensure_space(this);
1715 last_pc_ = pc_;
1716 emit_rex_64(dst);
1717 emit(0xF7);
1718 emit_modrm(0x2, dst);
1719}
1720
1721
1722void Assembler::not_(const Operand& dst) {
1723 EnsureSpace ensure_space(this);
1724 last_pc_ = pc_;
1725 emit_rex_64(dst);
1726 emit(0xF7);
1727 emit_operand(2, dst);
1728}
1729
1730
Steve Block6ded16b2010-05-10 14:33:55 +01001731void Assembler::notl(Register dst) {
1732 EnsureSpace ensure_space(this);
1733 last_pc_ = pc_;
1734 emit_optional_rex_32(dst);
1735 emit(0xF7);
1736 emit_modrm(0x2, dst);
1737}
1738
1739
Steve Blocka7e24c12009-10-30 11:49:00 +00001740void Assembler::nop(int n) {
1741 // The recommended muti-byte sequences of NOP instructions from the Intel 64
1742 // and IA-32 Architectures Software Developer's Manual.
1743 //
1744 // Length Assembly Byte Sequence
1745 // 2 bytes 66 NOP 66 90H
1746 // 3 bytes NOP DWORD ptr [EAX] 0F 1F 00H
1747 // 4 bytes NOP DWORD ptr [EAX + 00H] 0F 1F 40 00H
1748 // 5 bytes NOP DWORD ptr [EAX + EAX*1 + 00H] 0F 1F 44 00 00H
1749 // 6 bytes 66 NOP DWORD ptr [EAX + EAX*1 + 00H] 66 0F 1F 44 00 00H
1750 // 7 bytes NOP DWORD ptr [EAX + 00000000H] 0F 1F 80 00 00 00 00H
1751 // 8 bytes NOP DWORD ptr [EAX + EAX*1 + 00000000H] 0F 1F 84 00 00 00 00 00H
1752 // 9 bytes 66 NOP DWORD ptr [EAX + EAX*1 + 66 0F 1F 84 00 00 00 00
1753 // 00000000H] 00H
1754
1755 ASSERT(1 <= n);
1756 ASSERT(n <= 9);
1757 EnsureSpace ensure_space(this);
1758 last_pc_ = pc_;
1759 switch (n) {
1760 case 1:
1761 emit(0x90);
1762 return;
1763 case 2:
1764 emit(0x66);
1765 emit(0x90);
1766 return;
1767 case 3:
1768 emit(0x0f);
1769 emit(0x1f);
1770 emit(0x00);
1771 return;
1772 case 4:
1773 emit(0x0f);
1774 emit(0x1f);
1775 emit(0x40);
1776 emit(0x00);
1777 return;
1778 case 5:
1779 emit(0x0f);
1780 emit(0x1f);
1781 emit(0x44);
1782 emit(0x00);
1783 emit(0x00);
1784 return;
1785 case 6:
1786 emit(0x66);
1787 emit(0x0f);
1788 emit(0x1f);
1789 emit(0x44);
1790 emit(0x00);
1791 emit(0x00);
1792 return;
1793 case 7:
1794 emit(0x0f);
1795 emit(0x1f);
1796 emit(0x80);
1797 emit(0x00);
1798 emit(0x00);
1799 emit(0x00);
1800 emit(0x00);
1801 return;
1802 case 8:
1803 emit(0x0f);
1804 emit(0x1f);
1805 emit(0x84);
1806 emit(0x00);
1807 emit(0x00);
1808 emit(0x00);
1809 emit(0x00);
1810 emit(0x00);
1811 return;
1812 case 9:
1813 emit(0x66);
1814 emit(0x0f);
1815 emit(0x1f);
1816 emit(0x84);
1817 emit(0x00);
1818 emit(0x00);
1819 emit(0x00);
1820 emit(0x00);
1821 emit(0x00);
1822 return;
1823 }
1824}
1825
1826
1827void Assembler::pop(Register dst) {
1828 EnsureSpace ensure_space(this);
1829 last_pc_ = pc_;
Steve Block8defd9f2010-07-08 12:39:36 +01001830 emit_optional_rex_32(dst);
Steve Blocka7e24c12009-10-30 11:49:00 +00001831 emit(0x58 | dst.low_bits());
1832}
1833
1834
1835void Assembler::pop(const Operand& dst) {
1836 EnsureSpace ensure_space(this);
1837 last_pc_ = pc_;
Steve Block8defd9f2010-07-08 12:39:36 +01001838 emit_optional_rex_32(dst);
Steve Blocka7e24c12009-10-30 11:49:00 +00001839 emit(0x8F);
1840 emit_operand(0, dst);
1841}
1842
1843
1844void Assembler::popfq() {
1845 EnsureSpace ensure_space(this);
1846 last_pc_ = pc_;
1847 emit(0x9D);
1848}
1849
1850
1851void Assembler::push(Register src) {
1852 EnsureSpace ensure_space(this);
1853 last_pc_ = pc_;
Steve Block8defd9f2010-07-08 12:39:36 +01001854 emit_optional_rex_32(src);
Steve Blocka7e24c12009-10-30 11:49:00 +00001855 emit(0x50 | src.low_bits());
1856}
1857
1858
1859void Assembler::push(const Operand& src) {
1860 EnsureSpace ensure_space(this);
1861 last_pc_ = pc_;
Steve Block8defd9f2010-07-08 12:39:36 +01001862 emit_optional_rex_32(src);
Steve Blocka7e24c12009-10-30 11:49:00 +00001863 emit(0xFF);
1864 emit_operand(6, src);
1865}
1866
1867
1868void Assembler::push(Immediate value) {
1869 EnsureSpace ensure_space(this);
1870 last_pc_ = pc_;
1871 if (is_int8(value.value_)) {
1872 emit(0x6A);
1873 emit(value.value_); // Emit low byte of value.
1874 } else {
1875 emit(0x68);
1876 emitl(value.value_);
1877 }
1878}
1879
1880
1881void Assembler::pushfq() {
1882 EnsureSpace ensure_space(this);
1883 last_pc_ = pc_;
1884 emit(0x9C);
1885}
1886
1887
Steve Blocka7e24c12009-10-30 11:49:00 +00001888void Assembler::rdtsc() {
1889 EnsureSpace ensure_space(this);
1890 last_pc_ = pc_;
1891 emit(0x0F);
1892 emit(0x31);
1893}
1894
1895
1896void Assembler::ret(int imm16) {
1897 EnsureSpace ensure_space(this);
1898 last_pc_ = pc_;
1899 ASSERT(is_uint16(imm16));
1900 if (imm16 == 0) {
1901 emit(0xC3);
1902 } else {
1903 emit(0xC2);
1904 emit(imm16 & 0xFF);
1905 emit((imm16 >> 8) & 0xFF);
1906 }
1907}
1908
1909
1910void Assembler::setcc(Condition cc, Register reg) {
Steve Block3ce2e202009-11-05 08:53:23 +00001911 if (cc > last_condition) {
1912 movb(reg, Immediate(cc == always ? 1 : 0));
1913 return;
1914 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001915 EnsureSpace ensure_space(this);
1916 last_pc_ = pc_;
1917 ASSERT(is_uint4(cc));
1918 if (reg.code() > 3) { // Use x64 byte registers, where different.
1919 emit_rex_32(reg);
1920 }
1921 emit(0x0F);
1922 emit(0x90 | cc);
1923 emit_modrm(0x0, reg);
1924}
1925
1926
1927void Assembler::shld(Register dst, Register src) {
1928 EnsureSpace ensure_space(this);
1929 last_pc_ = pc_;
1930 emit_rex_64(src, dst);
1931 emit(0x0F);
1932 emit(0xA5);
1933 emit_modrm(src, dst);
1934}
1935
1936
1937void Assembler::shrd(Register dst, Register src) {
1938 EnsureSpace ensure_space(this);
1939 last_pc_ = pc_;
1940 emit_rex_64(src, dst);
1941 emit(0x0F);
1942 emit(0xAD);
1943 emit_modrm(src, dst);
1944}
1945
1946
1947void Assembler::xchg(Register dst, Register src) {
1948 EnsureSpace ensure_space(this);
1949 last_pc_ = pc_;
1950 if (src.is(rax) || dst.is(rax)) { // Single-byte encoding
1951 Register other = src.is(rax) ? dst : src;
1952 emit_rex_64(other);
1953 emit(0x90 | other.low_bits());
Leon Clarkef7060e22010-06-03 12:02:55 +01001954 } else if (dst.low_bits() == 4) {
1955 emit_rex_64(dst, src);
1956 emit(0x87);
1957 emit_modrm(dst, src);
Steve Blocka7e24c12009-10-30 11:49:00 +00001958 } else {
1959 emit_rex_64(src, dst);
1960 emit(0x87);
1961 emit_modrm(src, dst);
1962 }
1963}
1964
1965
1966void Assembler::store_rax(void* dst, RelocInfo::Mode mode) {
1967 EnsureSpace ensure_space(this);
1968 last_pc_ = pc_;
1969 emit(0x48); // REX.W
1970 emit(0xA3);
1971 emitq(reinterpret_cast<uintptr_t>(dst), mode);
1972}
1973
1974
1975void Assembler::store_rax(ExternalReference ref) {
1976 store_rax(ref.address(), RelocInfo::EXTERNAL_REFERENCE);
1977}
1978
1979
Steve Block3ce2e202009-11-05 08:53:23 +00001980void Assembler::testb(Register dst, Register src) {
1981 EnsureSpace ensure_space(this);
1982 last_pc_ = pc_;
Leon Clarkef7060e22010-06-03 12:02:55 +01001983 if (src.low_bits() == 4) {
1984 emit_rex_32(src, dst);
1985 emit(0x84);
1986 emit_modrm(src, dst);
1987 } else {
1988 if (dst.code() > 3 || src.code() > 3) {
1989 // Register is not one of al, bl, cl, dl. Its encoding needs REX.
1990 emit_rex_32(dst, src);
1991 }
1992 emit(0x84);
1993 emit_modrm(dst, src);
Steve Block3ce2e202009-11-05 08:53:23 +00001994 }
Steve Block3ce2e202009-11-05 08:53:23 +00001995}
1996
1997
Steve Blocka7e24c12009-10-30 11:49:00 +00001998void Assembler::testb(Register reg, Immediate mask) {
1999 ASSERT(is_int8(mask.value_) || is_uint8(mask.value_));
2000 EnsureSpace ensure_space(this);
2001 last_pc_ = pc_;
2002 if (reg.is(rax)) {
2003 emit(0xA8);
2004 emit(mask.value_); // Low byte emitted.
2005 } else {
2006 if (reg.code() > 3) {
2007 // Register is not one of al, bl, cl, dl. Its encoding needs REX.
2008 emit_rex_32(reg);
2009 }
2010 emit(0xF6);
2011 emit_modrm(0x0, reg);
2012 emit(mask.value_); // Low byte emitted.
2013 }
2014}
2015
2016
2017void Assembler::testb(const Operand& op, Immediate mask) {
2018 ASSERT(is_int8(mask.value_) || is_uint8(mask.value_));
2019 EnsureSpace ensure_space(this);
2020 last_pc_ = pc_;
2021 emit_optional_rex_32(rax, op);
2022 emit(0xF6);
2023 emit_operand(rax, op); // Operation code 0
2024 emit(mask.value_); // Low byte emitted.
2025}
2026
2027
Leon Clarkee46be812010-01-19 14:06:41 +00002028void Assembler::testb(const Operand& op, Register reg) {
2029 EnsureSpace ensure_space(this);
2030 last_pc_ = pc_;
2031 if (reg.code() > 3) {
2032 // Register is not one of al, bl, cl, dl. Its encoding needs REX.
2033 emit_rex_32(reg, op);
2034 } else {
2035 emit_optional_rex_32(reg, op);
2036 }
2037 emit(0x84);
2038 emit_operand(reg, op);
2039}
2040
2041
Steve Blocka7e24c12009-10-30 11:49:00 +00002042void Assembler::testl(Register dst, Register src) {
2043 EnsureSpace ensure_space(this);
2044 last_pc_ = pc_;
Leon Clarkef7060e22010-06-03 12:02:55 +01002045 if (src.low_bits() == 4) {
2046 emit_optional_rex_32(src, dst);
2047 emit(0x85);
2048 emit_modrm(src, dst);
2049 } else {
2050 emit_optional_rex_32(dst, src);
2051 emit(0x85);
2052 emit_modrm(dst, src);
2053 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002054}
2055
2056
2057void Assembler::testl(Register reg, Immediate mask) {
2058 // testl with a mask that fits in the low byte is exactly testb.
2059 if (is_uint8(mask.value_)) {
2060 testb(reg, mask);
2061 return;
2062 }
2063 EnsureSpace ensure_space(this);
2064 last_pc_ = pc_;
2065 if (reg.is(rax)) {
2066 emit(0xA9);
2067 emit(mask);
2068 } else {
2069 emit_optional_rex_32(rax, reg);
2070 emit(0xF7);
2071 emit_modrm(0x0, reg);
2072 emit(mask);
2073 }
2074}
2075
2076
2077void Assembler::testl(const Operand& op, Immediate mask) {
2078 // testl with a mask that fits in the low byte is exactly testb.
2079 if (is_uint8(mask.value_)) {
2080 testb(op, mask);
2081 return;
2082 }
2083 EnsureSpace ensure_space(this);
2084 last_pc_ = pc_;
2085 emit_optional_rex_32(rax, op);
2086 emit(0xF7);
2087 emit_operand(rax, op); // Operation code 0
2088 emit(mask);
2089}
2090
2091
2092void Assembler::testq(const Operand& op, Register reg) {
2093 EnsureSpace ensure_space(this);
2094 last_pc_ = pc_;
2095 emit_rex_64(reg, op);
2096 emit(0x85);
2097 emit_operand(reg, op);
2098}
2099
2100
2101void Assembler::testq(Register dst, Register src) {
2102 EnsureSpace ensure_space(this);
2103 last_pc_ = pc_;
Leon Clarkef7060e22010-06-03 12:02:55 +01002104 if (src.low_bits() == 4) {
2105 emit_rex_64(src, dst);
2106 emit(0x85);
2107 emit_modrm(src, dst);
2108 } else {
2109 emit_rex_64(dst, src);
2110 emit(0x85);
2111 emit_modrm(dst, src);
2112 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002113}
2114
2115
2116void Assembler::testq(Register dst, Immediate mask) {
2117 EnsureSpace ensure_space(this);
2118 last_pc_ = pc_;
2119 if (dst.is(rax)) {
2120 emit_rex_64();
2121 emit(0xA9);
2122 emit(mask);
2123 } else {
2124 emit_rex_64(dst);
2125 emit(0xF7);
2126 emit_modrm(0, dst);
2127 emit(mask);
2128 }
2129}
2130
2131
Andrei Popescu31002712010-02-23 13:46:05 +00002132// FPU instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00002133
2134
2135void Assembler::fld(int i) {
2136 EnsureSpace ensure_space(this);
2137 last_pc_ = pc_;
2138 emit_farith(0xD9, 0xC0, i);
2139}
2140
2141
2142void Assembler::fld1() {
2143 EnsureSpace ensure_space(this);
2144 last_pc_ = pc_;
2145 emit(0xD9);
2146 emit(0xE8);
2147}
2148
2149
2150void Assembler::fldz() {
2151 EnsureSpace ensure_space(this);
2152 last_pc_ = pc_;
2153 emit(0xD9);
2154 emit(0xEE);
2155}
2156
2157
Steve Block6ded16b2010-05-10 14:33:55 +01002158void Assembler::fldpi() {
2159 EnsureSpace ensure_space(this);
2160 last_pc_ = pc_;
2161 emit(0xD9);
2162 emit(0xEB);
2163}
2164
2165
Steve Blocka7e24c12009-10-30 11:49:00 +00002166void Assembler::fld_s(const Operand& adr) {
2167 EnsureSpace ensure_space(this);
2168 last_pc_ = pc_;
2169 emit_optional_rex_32(adr);
2170 emit(0xD9);
2171 emit_operand(0, adr);
2172}
2173
2174
2175void Assembler::fld_d(const Operand& adr) {
2176 EnsureSpace ensure_space(this);
2177 last_pc_ = pc_;
2178 emit_optional_rex_32(adr);
2179 emit(0xDD);
2180 emit_operand(0, adr);
2181}
2182
2183
2184void Assembler::fstp_s(const Operand& adr) {
2185 EnsureSpace ensure_space(this);
2186 last_pc_ = pc_;
2187 emit_optional_rex_32(adr);
2188 emit(0xD9);
2189 emit_operand(3, adr);
2190}
2191
2192
2193void Assembler::fstp_d(const Operand& adr) {
2194 EnsureSpace ensure_space(this);
2195 last_pc_ = pc_;
2196 emit_optional_rex_32(adr);
2197 emit(0xDD);
2198 emit_operand(3, adr);
2199}
2200
2201
Steve Block3ce2e202009-11-05 08:53:23 +00002202void Assembler::fstp(int index) {
2203 ASSERT(is_uint3(index));
2204 EnsureSpace ensure_space(this);
2205 last_pc_ = pc_;
2206 emit_farith(0xDD, 0xD8, index);
2207}
2208
2209
Steve Blocka7e24c12009-10-30 11:49:00 +00002210void Assembler::fild_s(const Operand& adr) {
2211 EnsureSpace ensure_space(this);
2212 last_pc_ = pc_;
2213 emit_optional_rex_32(adr);
2214 emit(0xDB);
2215 emit_operand(0, adr);
2216}
2217
2218
2219void Assembler::fild_d(const Operand& adr) {
2220 EnsureSpace ensure_space(this);
2221 last_pc_ = pc_;
2222 emit_optional_rex_32(adr);
2223 emit(0xDF);
2224 emit_operand(5, adr);
2225}
2226
2227
2228void Assembler::fistp_s(const Operand& adr) {
2229 EnsureSpace ensure_space(this);
2230 last_pc_ = pc_;
2231 emit_optional_rex_32(adr);
2232 emit(0xDB);
2233 emit_operand(3, adr);
2234}
2235
2236
2237void Assembler::fisttp_s(const Operand& adr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002238 ASSERT(CpuFeatures::IsEnabled(SSE3));
Steve Blocka7e24c12009-10-30 11:49:00 +00002239 EnsureSpace ensure_space(this);
2240 last_pc_ = pc_;
2241 emit_optional_rex_32(adr);
2242 emit(0xDB);
2243 emit_operand(1, adr);
2244}
2245
2246
Leon Clarked91b9f72010-01-27 17:25:45 +00002247void Assembler::fisttp_d(const Operand& adr) {
2248 ASSERT(CpuFeatures::IsEnabled(SSE3));
2249 EnsureSpace ensure_space(this);
2250 last_pc_ = pc_;
2251 emit_optional_rex_32(adr);
2252 emit(0xDD);
2253 emit_operand(1, adr);
2254}
2255
2256
Steve Blocka7e24c12009-10-30 11:49:00 +00002257void Assembler::fist_s(const Operand& adr) {
2258 EnsureSpace ensure_space(this);
2259 last_pc_ = pc_;
2260 emit_optional_rex_32(adr);
2261 emit(0xDB);
2262 emit_operand(2, adr);
2263}
2264
2265
2266void Assembler::fistp_d(const Operand& adr) {
2267 EnsureSpace ensure_space(this);
2268 last_pc_ = pc_;
2269 emit_optional_rex_32(adr);
2270 emit(0xDF);
Steve Block3ce2e202009-11-05 08:53:23 +00002271 emit_operand(7, adr);
Steve Blocka7e24c12009-10-30 11:49:00 +00002272}
2273
2274
2275void Assembler::fabs() {
2276 EnsureSpace ensure_space(this);
2277 last_pc_ = pc_;
2278 emit(0xD9);
2279 emit(0xE1);
2280}
2281
2282
2283void Assembler::fchs() {
2284 EnsureSpace ensure_space(this);
2285 last_pc_ = pc_;
2286 emit(0xD9);
2287 emit(0xE0);
2288}
2289
2290
2291void Assembler::fcos() {
2292 EnsureSpace ensure_space(this);
2293 last_pc_ = pc_;
2294 emit(0xD9);
2295 emit(0xFF);
2296}
2297
2298
2299void Assembler::fsin() {
2300 EnsureSpace ensure_space(this);
2301 last_pc_ = pc_;
2302 emit(0xD9);
2303 emit(0xFE);
2304}
2305
2306
2307void Assembler::fadd(int i) {
2308 EnsureSpace ensure_space(this);
2309 last_pc_ = pc_;
2310 emit_farith(0xDC, 0xC0, i);
2311}
2312
2313
2314void Assembler::fsub(int i) {
2315 EnsureSpace ensure_space(this);
2316 last_pc_ = pc_;
2317 emit_farith(0xDC, 0xE8, i);
2318}
2319
2320
2321void Assembler::fisub_s(const Operand& adr) {
2322 EnsureSpace ensure_space(this);
2323 last_pc_ = pc_;
2324 emit_optional_rex_32(adr);
2325 emit(0xDA);
2326 emit_operand(4, adr);
2327}
2328
2329
2330void Assembler::fmul(int i) {
2331 EnsureSpace ensure_space(this);
2332 last_pc_ = pc_;
2333 emit_farith(0xDC, 0xC8, i);
2334}
2335
2336
2337void Assembler::fdiv(int i) {
2338 EnsureSpace ensure_space(this);
2339 last_pc_ = pc_;
2340 emit_farith(0xDC, 0xF8, i);
2341}
2342
2343
2344void Assembler::faddp(int i) {
2345 EnsureSpace ensure_space(this);
2346 last_pc_ = pc_;
2347 emit_farith(0xDE, 0xC0, i);
2348}
2349
2350
2351void Assembler::fsubp(int i) {
2352 EnsureSpace ensure_space(this);
2353 last_pc_ = pc_;
2354 emit_farith(0xDE, 0xE8, i);
2355}
2356
2357
2358void Assembler::fsubrp(int i) {
2359 EnsureSpace ensure_space(this);
2360 last_pc_ = pc_;
2361 emit_farith(0xDE, 0xE0, i);
2362}
2363
2364
2365void Assembler::fmulp(int i) {
2366 EnsureSpace ensure_space(this);
2367 last_pc_ = pc_;
2368 emit_farith(0xDE, 0xC8, i);
2369}
2370
2371
2372void Assembler::fdivp(int i) {
2373 EnsureSpace ensure_space(this);
2374 last_pc_ = pc_;
2375 emit_farith(0xDE, 0xF8, i);
2376}
2377
2378
2379void Assembler::fprem() {
2380 EnsureSpace ensure_space(this);
2381 last_pc_ = pc_;
2382 emit(0xD9);
2383 emit(0xF8);
2384}
2385
2386
2387void Assembler::fprem1() {
2388 EnsureSpace ensure_space(this);
2389 last_pc_ = pc_;
2390 emit(0xD9);
2391 emit(0xF5);
2392}
2393
2394
2395void Assembler::fxch(int i) {
2396 EnsureSpace ensure_space(this);
2397 last_pc_ = pc_;
2398 emit_farith(0xD9, 0xC8, i);
2399}
2400
2401
2402void Assembler::fincstp() {
2403 EnsureSpace ensure_space(this);
2404 last_pc_ = pc_;
2405 emit(0xD9);
2406 emit(0xF7);
2407}
2408
2409
2410void Assembler::ffree(int i) {
2411 EnsureSpace ensure_space(this);
2412 last_pc_ = pc_;
2413 emit_farith(0xDD, 0xC0, i);
2414}
2415
2416
2417void Assembler::ftst() {
2418 EnsureSpace ensure_space(this);
2419 last_pc_ = pc_;
2420 emit(0xD9);
2421 emit(0xE4);
2422}
2423
2424
2425void Assembler::fucomp(int i) {
2426 EnsureSpace ensure_space(this);
2427 last_pc_ = pc_;
2428 emit_farith(0xDD, 0xE8, i);
2429}
2430
2431
2432void Assembler::fucompp() {
2433 EnsureSpace ensure_space(this);
2434 last_pc_ = pc_;
2435 emit(0xDA);
2436 emit(0xE9);
2437}
2438
2439
Steve Block3ce2e202009-11-05 08:53:23 +00002440void Assembler::fucomi(int i) {
2441 EnsureSpace ensure_space(this);
2442 last_pc_ = pc_;
2443 emit(0xDB);
2444 emit(0xE8 + i);
2445}
2446
2447
2448void Assembler::fucomip() {
2449 EnsureSpace ensure_space(this);
2450 last_pc_ = pc_;
2451 emit(0xDF);
2452 emit(0xE9);
2453}
2454
2455
Steve Blocka7e24c12009-10-30 11:49:00 +00002456void Assembler::fcompp() {
2457 EnsureSpace ensure_space(this);
2458 last_pc_ = pc_;
2459 emit(0xDE);
2460 emit(0xD9);
2461}
2462
2463
2464void Assembler::fnstsw_ax() {
2465 EnsureSpace ensure_space(this);
2466 last_pc_ = pc_;
2467 emit(0xDF);
2468 emit(0xE0);
2469}
2470
2471
2472void Assembler::fwait() {
2473 EnsureSpace ensure_space(this);
2474 last_pc_ = pc_;
2475 emit(0x9B);
2476}
2477
2478
2479void Assembler::frndint() {
2480 EnsureSpace ensure_space(this);
2481 last_pc_ = pc_;
2482 emit(0xD9);
2483 emit(0xFC);
2484}
2485
2486
2487void Assembler::fnclex() {
2488 EnsureSpace ensure_space(this);
2489 last_pc_ = pc_;
2490 emit(0xDB);
2491 emit(0xE2);
2492}
2493
2494
2495void Assembler::sahf() {
2496 // TODO(X64): Test for presence. Not all 64-bit intel CPU's have sahf
2497 // in 64-bit mode. Test CpuID.
2498 EnsureSpace ensure_space(this);
2499 last_pc_ = pc_;
2500 emit(0x9E);
2501}
2502
2503
2504void Assembler::emit_farith(int b1, int b2, int i) {
2505 ASSERT(is_uint8(b1) && is_uint8(b2)); // wrong opcode
2506 ASSERT(is_uint3(i)); // illegal stack offset
2507 emit(b1);
2508 emit(b2 + i);
2509}
2510
Andrei Popescu31002712010-02-23 13:46:05 +00002511// SSE 2 operations.
Steve Blocka7e24c12009-10-30 11:49:00 +00002512
Steve Block6ded16b2010-05-10 14:33:55 +01002513void Assembler::movd(XMMRegister dst, Register src) {
2514 EnsureSpace ensure_space(this);
2515 last_pc_ = pc_;
2516 emit(0x66);
2517 emit_optional_rex_32(dst, src);
2518 emit(0x0F);
2519 emit(0x6E);
2520 emit_sse_operand(dst, src);
2521}
2522
2523
2524void Assembler::movd(Register dst, XMMRegister src) {
2525 EnsureSpace ensure_space(this);
2526 last_pc_ = pc_;
2527 emit(0x66);
Ben Murdochbb769b22010-08-11 14:56:33 +01002528 emit_optional_rex_32(src, dst);
Steve Block6ded16b2010-05-10 14:33:55 +01002529 emit(0x0F);
2530 emit(0x7E);
Ben Murdochbb769b22010-08-11 14:56:33 +01002531 emit_sse_operand(src, dst);
Steve Block6ded16b2010-05-10 14:33:55 +01002532}
2533
2534
2535void Assembler::movq(XMMRegister dst, Register src) {
2536 EnsureSpace ensure_space(this);
2537 last_pc_ = pc_;
2538 emit(0x66);
2539 emit_rex_64(dst, src);
2540 emit(0x0F);
2541 emit(0x6E);
2542 emit_sse_operand(dst, src);
2543}
2544
2545
2546void Assembler::movq(Register dst, XMMRegister src) {
2547 EnsureSpace ensure_space(this);
2548 last_pc_ = pc_;
2549 emit(0x66);
Ben Murdochbb769b22010-08-11 14:56:33 +01002550 emit_rex_64(src, dst);
Steve Block6ded16b2010-05-10 14:33:55 +01002551 emit(0x0F);
2552 emit(0x7E);
Ben Murdochbb769b22010-08-11 14:56:33 +01002553 emit_sse_operand(src, dst);
Steve Block6ded16b2010-05-10 14:33:55 +01002554}
2555
2556
2557void Assembler::extractps(Register dst, XMMRegister src, byte imm8) {
2558 ASSERT(is_uint2(imm8));
2559 EnsureSpace ensure_space(this);
2560 last_pc_ = pc_;
2561 emit(0x66);
2562 emit_optional_rex_32(dst, src);
2563 emit(0x0F);
2564 emit(0x3A);
2565 emit(0x17);
2566 emit_sse_operand(dst, src);
2567 emit(imm8);
2568}
2569
2570
Steve Blocka7e24c12009-10-30 11:49:00 +00002571void Assembler::movsd(const Operand& dst, XMMRegister src) {
2572 EnsureSpace ensure_space(this);
2573 last_pc_ = pc_;
2574 emit(0xF2); // double
2575 emit_optional_rex_32(src, dst);
2576 emit(0x0F);
2577 emit(0x11); // store
2578 emit_sse_operand(src, dst);
2579}
2580
2581
Steve Block3ce2e202009-11-05 08:53:23 +00002582void Assembler::movsd(XMMRegister dst, XMMRegister src) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002583 EnsureSpace ensure_space(this);
2584 last_pc_ = pc_;
2585 emit(0xF2); // double
2586 emit_optional_rex_32(dst, src);
2587 emit(0x0F);
2588 emit(0x10); // load
2589 emit_sse_operand(dst, src);
2590}
2591
2592
2593void Assembler::movsd(XMMRegister dst, const Operand& src) {
2594 EnsureSpace ensure_space(this);
2595 last_pc_ = pc_;
2596 emit(0xF2); // double
2597 emit_optional_rex_32(dst, src);
2598 emit(0x0F);
2599 emit(0x10); // load
2600 emit_sse_operand(dst, src);
2601}
2602
2603
Steve Block8defd9f2010-07-08 12:39:36 +01002604void Assembler::movss(XMMRegister dst, const Operand& src) {
2605 EnsureSpace ensure_space(this);
2606 last_pc_ = pc_;
2607 emit(0xF3); // single
2608 emit_optional_rex_32(dst, src);
2609 emit(0x0F);
2610 emit(0x10); // load
2611 emit_sse_operand(dst, src);
2612}
2613
2614
2615void Assembler::movss(const Operand& src, XMMRegister dst) {
2616 EnsureSpace ensure_space(this);
2617 last_pc_ = pc_;
2618 emit(0xF3); // single
2619 emit_optional_rex_32(dst, src);
2620 emit(0x0F);
2621 emit(0x11); // store
2622 emit_sse_operand(dst, src);
2623}
2624
2625
Steve Blocka7e24c12009-10-30 11:49:00 +00002626void Assembler::cvttss2si(Register dst, const Operand& src) {
2627 EnsureSpace ensure_space(this);
2628 last_pc_ = pc_;
2629 emit(0xF3);
2630 emit_optional_rex_32(dst, src);
2631 emit(0x0F);
2632 emit(0x2C);
2633 emit_operand(dst, src);
2634}
2635
2636
2637void Assembler::cvttsd2si(Register dst, const Operand& src) {
2638 EnsureSpace ensure_space(this);
2639 last_pc_ = pc_;
2640 emit(0xF2);
2641 emit_optional_rex_32(dst, src);
2642 emit(0x0F);
2643 emit(0x2C);
2644 emit_operand(dst, src);
2645}
2646
2647
Kristian Monsen25f61362010-05-21 11:50:48 +01002648void Assembler::cvttsd2siq(Register dst, XMMRegister src) {
2649 EnsureSpace ensure_space(this);
2650 last_pc_ = pc_;
2651 emit(0xF2);
2652 emit_rex_64(dst, src);
2653 emit(0x0F);
2654 emit(0x2C);
2655 emit_sse_operand(dst, src);
2656}
2657
2658
Steve Blocka7e24c12009-10-30 11:49:00 +00002659void Assembler::cvtlsi2sd(XMMRegister dst, const Operand& src) {
2660 EnsureSpace ensure_space(this);
2661 last_pc_ = pc_;
2662 emit(0xF2);
2663 emit_optional_rex_32(dst, src);
2664 emit(0x0F);
2665 emit(0x2A);
2666 emit_sse_operand(dst, src);
2667}
2668
2669
2670void Assembler::cvtlsi2sd(XMMRegister dst, Register src) {
2671 EnsureSpace ensure_space(this);
2672 last_pc_ = pc_;
2673 emit(0xF2);
2674 emit_optional_rex_32(dst, src);
2675 emit(0x0F);
2676 emit(0x2A);
2677 emit_sse_operand(dst, src);
2678}
2679
2680
Steve Block8defd9f2010-07-08 12:39:36 +01002681void Assembler::cvtlsi2ss(XMMRegister dst, Register src) {
2682 EnsureSpace ensure_space(this);
2683 last_pc_ = pc_;
2684 emit(0xF3);
2685 emit_optional_rex_32(dst, src);
2686 emit(0x0F);
2687 emit(0x2A);
2688 emit_sse_operand(dst, src);
2689}
2690
2691
Steve Blocka7e24c12009-10-30 11:49:00 +00002692void Assembler::cvtqsi2sd(XMMRegister dst, Register src) {
2693 EnsureSpace ensure_space(this);
2694 last_pc_ = pc_;
2695 emit(0xF2);
2696 emit_rex_64(dst, src);
2697 emit(0x0F);
2698 emit(0x2A);
2699 emit_sse_operand(dst, src);
2700}
2701
2702
Steve Block6ded16b2010-05-10 14:33:55 +01002703void Assembler::cvtss2sd(XMMRegister dst, XMMRegister src) {
2704 EnsureSpace ensure_space(this);
2705 last_pc_ = pc_;
2706 emit(0xF3);
2707 emit_optional_rex_32(dst, src);
2708 emit(0x0F);
2709 emit(0x5A);
2710 emit_sse_operand(dst, src);
2711}
2712
2713
Steve Block8defd9f2010-07-08 12:39:36 +01002714void Assembler::cvtss2sd(XMMRegister dst, const Operand& src) {
2715 EnsureSpace ensure_space(this);
2716 last_pc_ = pc_;
2717 emit(0xF3);
2718 emit_optional_rex_32(dst, src);
2719 emit(0x0F);
2720 emit(0x5A);
2721 emit_sse_operand(dst, src);
2722}
2723
2724
2725void Assembler::cvtsd2ss(XMMRegister dst, XMMRegister src) {
2726 EnsureSpace ensure_space(this);
2727 last_pc_ = pc_;
2728 emit(0xF2);
2729 emit_optional_rex_32(dst, src);
2730 emit(0x0F);
2731 emit(0x5A);
2732 emit_sse_operand(dst, src);
2733}
2734
2735
2736void Assembler::cvtsd2si(Register dst, XMMRegister src) {
2737 EnsureSpace ensure_space(this);
2738 last_pc_ = pc_;
2739 emit(0xF2);
2740 emit_optional_rex_32(dst, src);
2741 emit(0x0F);
2742 emit(0x2D);
2743 emit_sse_operand(dst, src);
2744}
2745
2746
2747void Assembler::cvtsd2siq(Register dst, XMMRegister src) {
2748 EnsureSpace ensure_space(this);
2749 last_pc_ = pc_;
2750 emit(0xF2);
2751 emit_rex_64(dst, src);
2752 emit(0x0F);
2753 emit(0x2D);
2754 emit_sse_operand(dst, src);
2755}
2756
2757
Steve Blocka7e24c12009-10-30 11:49:00 +00002758void Assembler::addsd(XMMRegister dst, XMMRegister src) {
2759 EnsureSpace ensure_space(this);
2760 last_pc_ = pc_;
2761 emit(0xF2);
2762 emit_optional_rex_32(dst, src);
2763 emit(0x0F);
2764 emit(0x58);
2765 emit_sse_operand(dst, src);
2766}
2767
2768
2769void Assembler::mulsd(XMMRegister dst, XMMRegister src) {
2770 EnsureSpace ensure_space(this);
2771 last_pc_ = pc_;
2772 emit(0xF2);
2773 emit_optional_rex_32(dst, src);
2774 emit(0x0F);
2775 emit(0x59);
2776 emit_sse_operand(dst, src);
2777}
2778
2779
2780void Assembler::subsd(XMMRegister dst, XMMRegister src) {
2781 EnsureSpace ensure_space(this);
2782 last_pc_ = pc_;
2783 emit(0xF2);
2784 emit_optional_rex_32(dst, src);
2785 emit(0x0F);
2786 emit(0x5C);
2787 emit_sse_operand(dst, src);
2788}
2789
2790
2791void Assembler::divsd(XMMRegister dst, XMMRegister src) {
2792 EnsureSpace ensure_space(this);
2793 last_pc_ = pc_;
2794 emit(0xF2);
2795 emit_optional_rex_32(dst, src);
2796 emit(0x0F);
2797 emit(0x5E);
2798 emit_sse_operand(dst, src);
2799}
2800
2801
Andrei Popescu402d9372010-02-26 13:31:12 +00002802void Assembler::xorpd(XMMRegister dst, XMMRegister src) {
2803 EnsureSpace ensure_space(this);
2804 last_pc_ = pc_;
2805 emit(0x66);
2806 emit_optional_rex_32(dst, src);
Steve Block6ded16b2010-05-10 14:33:55 +01002807 emit(0x0F);
Andrei Popescu402d9372010-02-26 13:31:12 +00002808 emit(0x57);
2809 emit_sse_operand(dst, src);
2810}
2811
2812
Steve Block6ded16b2010-05-10 14:33:55 +01002813void Assembler::sqrtsd(XMMRegister dst, XMMRegister src) {
2814 EnsureSpace ensure_space(this);
2815 last_pc_ = pc_;
2816 emit(0xF2);
2817 emit_optional_rex_32(dst, src);
2818 emit(0x0F);
2819 emit(0x51);
2820 emit_sse_operand(dst, src);
2821}
2822
2823
Andrei Popescu402d9372010-02-26 13:31:12 +00002824void Assembler::ucomisd(XMMRegister dst, XMMRegister src) {
2825 EnsureSpace ensure_space(this);
2826 last_pc_ = pc_;
2827 emit(0x66);
2828 emit_optional_rex_32(dst, src);
2829 emit(0x0f);
2830 emit(0x2e);
2831 emit_sse_operand(dst, src);
2832}
2833
Steve Blocka7e24c12009-10-30 11:49:00 +00002834
Steve Block8defd9f2010-07-08 12:39:36 +01002835void Assembler::ucomisd(XMMRegister dst, const Operand& src) {
2836 EnsureSpace ensure_space(this);
2837 last_pc_ = pc_;
2838 emit(0x66);
2839 emit_optional_rex_32(dst, src);
2840 emit(0x0f);
2841 emit(0x2e);
2842 emit_sse_operand(dst, src);
2843}
2844
2845
2846
Steve Blocka7e24c12009-10-30 11:49:00 +00002847void Assembler::emit_sse_operand(XMMRegister reg, const Operand& adr) {
2848 Register ireg = { reg.code() };
2849 emit_operand(ireg, adr);
2850}
2851
2852
2853void Assembler::emit_sse_operand(XMMRegister dst, XMMRegister src) {
2854 emit(0xC0 | (dst.low_bits() << 3) | src.low_bits());
2855}
2856
2857void Assembler::emit_sse_operand(XMMRegister dst, Register src) {
2858 emit(0xC0 | (dst.low_bits() << 3) | src.low_bits());
2859}
2860
Steve Block6ded16b2010-05-10 14:33:55 +01002861void Assembler::emit_sse_operand(Register dst, XMMRegister src) {
2862 emit(0xC0 | (dst.low_bits() << 3) | src.low_bits());
2863}
2864
Steve Blocka7e24c12009-10-30 11:49:00 +00002865
Andrei Popescu31002712010-02-23 13:46:05 +00002866// Relocation information implementations.
Steve Blocka7e24c12009-10-30 11:49:00 +00002867
2868void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
2869 ASSERT(rmode != RelocInfo::NONE);
2870 // Don't record external references unless the heap will be serialized.
2871 if (rmode == RelocInfo::EXTERNAL_REFERENCE &&
2872 !Serializer::enabled() &&
2873 !FLAG_debug_code) {
2874 return;
2875 }
2876 RelocInfo rinfo(pc_, rmode, data);
2877 reloc_info_writer.Write(&rinfo);
2878}
2879
2880void Assembler::RecordJSReturn() {
2881 WriteRecordedPositions();
2882 EnsureSpace ensure_space(this);
2883 RecordRelocInfo(RelocInfo::JS_RETURN);
2884}
2885
2886
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002887void Assembler::RecordDebugBreakSlot() {
2888 WriteRecordedPositions();
2889 EnsureSpace ensure_space(this);
2890 RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
2891}
2892
2893
Steve Blocka7e24c12009-10-30 11:49:00 +00002894void Assembler::RecordComment(const char* msg) {
2895 if (FLAG_debug_code) {
2896 EnsureSpace ensure_space(this);
2897 RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg));
2898 }
2899}
2900
2901
2902void Assembler::RecordPosition(int pos) {
2903 ASSERT(pos != RelocInfo::kNoPosition);
2904 ASSERT(pos >= 0);
2905 current_position_ = pos;
2906}
2907
2908
2909void Assembler::RecordStatementPosition(int pos) {
2910 ASSERT(pos != RelocInfo::kNoPosition);
2911 ASSERT(pos >= 0);
2912 current_statement_position_ = pos;
2913}
2914
2915
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002916bool Assembler::WriteRecordedPositions() {
2917 bool written = false;
2918
Steve Blocka7e24c12009-10-30 11:49:00 +00002919 // Write the statement position if it is different from what was written last
2920 // time.
2921 if (current_statement_position_ != written_statement_position_) {
2922 EnsureSpace ensure_space(this);
2923 RecordRelocInfo(RelocInfo::STATEMENT_POSITION, current_statement_position_);
2924 written_statement_position_ = current_statement_position_;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002925 written = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00002926 }
2927
2928 // Write the position if it is different from what was written last time and
2929 // also different from the written statement position.
2930 if (current_position_ != written_position_ &&
2931 current_position_ != written_statement_position_) {
2932 EnsureSpace ensure_space(this);
2933 RecordRelocInfo(RelocInfo::POSITION, current_position_);
2934 written_position_ = current_position_;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002935 written = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00002936 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002937
2938 // Return whether something was written.
2939 return written;
Steve Blocka7e24c12009-10-30 11:49:00 +00002940}
2941
2942
Steve Block3ce2e202009-11-05 08:53:23 +00002943const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask |
Ben Murdochbb769b22010-08-11 14:56:33 +01002944 1 << RelocInfo::INTERNAL_REFERENCE;
Steve Blocka7e24c12009-10-30 11:49:00 +00002945
Leon Clarkef7060e22010-06-03 12:02:55 +01002946
2947bool RelocInfo::IsCodedSpecially() {
2948 // The deserializer needs to know whether a pointer is specially coded. Being
2949 // specially coded on x64 means that it is a relative 32 bit address, as used
2950 // by branch instructions.
2951 return (1 << rmode_) & kApplyMask;
2952}
2953
2954
2955
Steve Blocka7e24c12009-10-30 11:49:00 +00002956} } // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01002957
2958#endif // V8_TARGET_ARCH_X64