blob: c19e2ba130a1d51420464e12eb67137dededf19e [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,
122 NULL,
123 Code::ComputeFlags(Code::STUB),
124 Handle<Object>());
Steve Blocka7e24c12009-10-30 11:49:00 +0000125 if (!code->IsCode()) return;
Steve Block6ded16b2010-05-10 14:33:55 +0100126 PROFILE(CodeCreateEvent(Logger::BUILTIN_TAG,
127 Code::cast(code), "CpuFeatures::Probe"));
Steve Blocka7e24c12009-10-30 11:49:00 +0000128 typedef uint64_t (*F0)();
129 F0 probe = FUNCTION_CAST<F0>(Code::cast(code)->entry());
130 supported_ = probe();
Steve Blockd0582a62009-12-15 09:54:21 +0000131 found_by_runtime_probing_ = supported_;
132 found_by_runtime_probing_ &= ~kDefaultCpuFeatures;
133 uint64_t os_guarantees = OS::CpuFeaturesImpliedByPlatform();
134 supported_ |= os_guarantees;
135 found_by_runtime_probing_ &= ~os_guarantees;
Steve Blocka7e24c12009-10-30 11:49:00 +0000136 // SSE2 and CMOV must be available on an X64 CPU.
137 ASSERT(IsSupported(CPUID));
138 ASSERT(IsSupported(SSE2));
139 ASSERT(IsSupported(CMOV));
140}
141
142
143// -----------------------------------------------------------------------------
144// Implementation of RelocInfo
145
146// Patch the code at the current PC with a call to the target address.
147// Additional guard int3 instructions can be added if required.
148void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) {
149 // Load register with immediate 64 and call through a register instructions
150 // takes up 13 bytes and int3 takes up one byte.
151 static const int kCallCodeSize = 13;
152 int code_size = kCallCodeSize + guard_bytes;
153
154 // Create a code patcher.
155 CodePatcher patcher(pc_, code_size);
156
157 // Add a label for checking the size of the code used for returning.
158#ifdef DEBUG
159 Label check_codesize;
160 patcher.masm()->bind(&check_codesize);
161#endif
162
163 // Patch the code.
164 patcher.masm()->movq(r10, target, RelocInfo::NONE);
165 patcher.masm()->call(r10);
166
167 // Check that the size of the code generated is as expected.
168 ASSERT_EQ(kCallCodeSize,
169 patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
170
171 // Add the requested number of int3 instructions after the call.
172 for (int i = 0; i < guard_bytes; i++) {
173 patcher.masm()->int3();
174 }
175}
176
177
178void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
179 // Patch the code at the current address with the supplied instructions.
180 for (int i = 0; i < instruction_count; i++) {
181 *(pc_ + i) = *(instructions + i);
182 }
183
184 // Indicate that code has changed.
185 CPU::FlushICache(pc_, instruction_count);
186}
187
188// -----------------------------------------------------------------------------
189// Implementation of Operand
190
Andrei Popescu402d9372010-02-26 13:31:12 +0000191Operand::Operand(Register base, int32_t disp) : rex_(0) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000192 len_ = 1;
193 if (base.is(rsp) || base.is(r12)) {
194 // SIB byte is needed to encode (rsp + offset) or (r12 + offset).
195 set_sib(times_1, rsp, base);
196 }
197
198 if (disp == 0 && !base.is(rbp) && !base.is(r13)) {
199 set_modrm(0, base);
200 } else if (is_int8(disp)) {
201 set_modrm(1, base);
202 set_disp8(disp);
203 } else {
204 set_modrm(2, base);
205 set_disp32(disp);
206 }
207}
208
209
210Operand::Operand(Register base,
211 Register index,
212 ScaleFactor scale,
Andrei Popescu402d9372010-02-26 13:31:12 +0000213 int32_t disp) : rex_(0) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000214 ASSERT(!index.is(rsp));
215 len_ = 1;
216 set_sib(scale, index, base);
217 if (disp == 0 && !base.is(rbp) && !base.is(r13)) {
218 // This call to set_modrm doesn't overwrite the REX.B (or REX.X) bits
219 // possibly set by set_sib.
220 set_modrm(0, rsp);
221 } else if (is_int8(disp)) {
222 set_modrm(1, rsp);
223 set_disp8(disp);
224 } else {
225 set_modrm(2, rsp);
226 set_disp32(disp);
227 }
228}
229
230
Andrei Popescu402d9372010-02-26 13:31:12 +0000231Operand::Operand(Register index,
232 ScaleFactor scale,
233 int32_t disp) : rex_(0) {
234 ASSERT(!index.is(rsp));
235 len_ = 1;
236 set_modrm(0, rsp);
237 set_sib(scale, index, rbp);
238 set_disp32(disp);
239}
240
241
Leon Clarkef7060e22010-06-03 12:02:55 +0100242Operand::Operand(const Operand& operand, int32_t offset) {
243 ASSERT(operand.len_ >= 1);
244 // Operand encodes REX ModR/M [SIB] [Disp].
245 byte modrm = operand.buf_[0];
246 ASSERT(modrm < 0xC0); // Disallow mode 3 (register target).
247 bool has_sib = ((modrm & 0x07) == 0x04);
248 byte mode = modrm & 0xC0;
249 int disp_offset = has_sib ? 2 : 1;
250 int base_reg = (has_sib ? operand.buf_[1] : modrm) & 0x07;
251 // Mode 0 with rbp/r13 as ModR/M or SIB base register always has a 32-bit
252 // displacement.
253 bool is_baseless = (mode == 0) && (base_reg == 0x05); // No base or RIP base.
254 int32_t disp_value = 0;
255 if (mode == 0x80 || is_baseless) {
256 // Mode 2 or mode 0 with rbp/r13 as base: Word displacement.
257 disp_value = *reinterpret_cast<const int32_t*>(&operand.buf_[disp_offset]);
258 } else if (mode == 0x40) {
259 // Mode 1: Byte displacement.
260 disp_value = static_cast<signed char>(operand.buf_[disp_offset]);
261 }
262
263 // Write new operand with same registers, but with modified displacement.
264 ASSERT(offset >= 0 ? disp_value + offset > disp_value
265 : disp_value + offset < disp_value); // No overflow.
266 disp_value += offset;
267 rex_ = operand.rex_;
268 if (!is_int8(disp_value) || is_baseless) {
269 // Need 32 bits of displacement, mode 2 or mode 1 with register rbp/r13.
270 buf_[0] = (modrm & 0x3f) | (is_baseless ? 0x00 : 0x80);
271 len_ = disp_offset + 4;
272 Memory::int32_at(&buf_[disp_offset]) = disp_value;
273 } else if (disp_value != 0 || (base_reg == 0x05)) {
274 // Need 8 bits of displacement.
275 buf_[0] = (modrm & 0x3f) | 0x40; // Mode 1.
276 len_ = disp_offset + 1;
277 buf_[disp_offset] = static_cast<byte>(disp_value);
278 } else {
279 // Need no displacement.
280 buf_[0] = (modrm & 0x3f); // Mode 0.
281 len_ = disp_offset;
282 }
283 if (has_sib) {
284 buf_[1] = operand.buf_[1];
285 }
286}
287
Steve Blocka7e24c12009-10-30 11:49:00 +0000288// -----------------------------------------------------------------------------
Andrei Popescu31002712010-02-23 13:46:05 +0000289// Implementation of Assembler.
Steve Blocka7e24c12009-10-30 11:49:00 +0000290
291#ifdef GENERATED_CODE_COVERAGE
292static void InitCoverageLog();
293#endif
294
295byte* Assembler::spare_buffer_ = NULL;
296
Steve Block3ce2e202009-11-05 08:53:23 +0000297Assembler::Assembler(void* buffer, int buffer_size)
298 : code_targets_(100) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000299 if (buffer == NULL) {
Andrei Popescu31002712010-02-23 13:46:05 +0000300 // Do our own buffer management.
Steve Blocka7e24c12009-10-30 11:49:00 +0000301 if (buffer_size <= kMinimalBufferSize) {
302 buffer_size = kMinimalBufferSize;
303
304 if (spare_buffer_ != NULL) {
305 buffer = spare_buffer_;
306 spare_buffer_ = NULL;
307 }
308 }
309 if (buffer == NULL) {
310 buffer_ = NewArray<byte>(buffer_size);
311 } else {
312 buffer_ = static_cast<byte*>(buffer);
313 }
314 buffer_size_ = buffer_size;
315 own_buffer_ = true;
316 } else {
Andrei Popescu31002712010-02-23 13:46:05 +0000317 // Use externally provided buffer instead.
Steve Blocka7e24c12009-10-30 11:49:00 +0000318 ASSERT(buffer_size > 0);
319 buffer_ = static_cast<byte*>(buffer);
320 buffer_size_ = buffer_size;
321 own_buffer_ = false;
322 }
323
324 // Clear the buffer in debug mode unless it was provided by the
325 // caller in which case we can't be sure it's okay to overwrite
326 // existing code in it.
327#ifdef DEBUG
328 if (own_buffer_) {
329 memset(buffer_, 0xCC, buffer_size); // int3
330 }
331#endif
332
Andrei Popescu31002712010-02-23 13:46:05 +0000333 // Setup buffer pointers.
Steve Blocka7e24c12009-10-30 11:49:00 +0000334 ASSERT(buffer_ != NULL);
335 pc_ = buffer_;
336 reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
337
338 last_pc_ = NULL;
339 current_statement_position_ = RelocInfo::kNoPosition;
340 current_position_ = RelocInfo::kNoPosition;
341 written_statement_position_ = current_statement_position_;
342 written_position_ = current_position_;
343#ifdef GENERATED_CODE_COVERAGE
344 InitCoverageLog();
345#endif
346}
347
348
349Assembler::~Assembler() {
350 if (own_buffer_) {
351 if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) {
352 spare_buffer_ = buffer_;
353 } else {
354 DeleteArray(buffer_);
355 }
356 }
357}
358
359
360void Assembler::GetCode(CodeDesc* desc) {
Andrei Popescu31002712010-02-23 13:46:05 +0000361 // Finalize code (at this point overflow() may be true, but the gap ensures
362 // that we are still not overlapping instructions and relocation info).
363 ASSERT(pc_ <= reloc_info_writer.pos()); // No overlap.
364 // Setup code descriptor.
Steve Blocka7e24c12009-10-30 11:49:00 +0000365 desc->buffer = buffer_;
366 desc->buffer_size = buffer_size_;
367 desc->instr_size = pc_offset();
368 ASSERT(desc->instr_size > 0); // Zero-size code objects upset the system.
Steve Blockd0582a62009-12-15 09:54:21 +0000369 desc->reloc_size =
370 static_cast<int>((buffer_ + buffer_size_) - reloc_info_writer.pos());
Steve Blocka7e24c12009-10-30 11:49:00 +0000371 desc->origin = this;
372
373 Counters::reloc_info_size.Increment(desc->reloc_size);
374}
375
376
377void Assembler::Align(int m) {
378 ASSERT(IsPowerOf2(m));
Steve Block8defd9f2010-07-08 12:39:36 +0100379 int delta = (m - (pc_offset() & (m - 1))) & (m - 1);
380 while (delta >= 9) {
381 nop(9);
382 delta -= 9;
383 }
384 if (delta > 0) {
385 nop(delta);
Steve Blocka7e24c12009-10-30 11:49:00 +0000386 }
387}
388
389
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100390void Assembler::CodeTargetAlign() {
391 Align(16); // Preferred alignment of jump targets on x64.
392}
393
394
Steve Blocka7e24c12009-10-30 11:49:00 +0000395void Assembler::bind_to(Label* L, int pos) {
396 ASSERT(!L->is_bound()); // Label may only be bound once.
397 last_pc_ = NULL;
398 ASSERT(0 <= pos && pos <= pc_offset()); // Position must be valid.
399 if (L->is_linked()) {
400 int current = L->pos();
401 int next = long_at(current);
402 while (next != current) {
Andrei Popescu31002712010-02-23 13:46:05 +0000403 // Relative address, relative to point after address.
Steve Blocka7e24c12009-10-30 11:49:00 +0000404 int imm32 = pos - (current + sizeof(int32_t));
405 long_at_put(current, imm32);
406 current = next;
407 next = long_at(next);
408 }
409 // Fix up last fixup on linked list.
410 int last_imm32 = pos - (current + sizeof(int32_t));
411 long_at_put(current, last_imm32);
412 }
413 L->bind_to(pos);
414}
415
416
417void Assembler::bind(Label* L) {
418 bind_to(L, pc_offset());
419}
420
421
422void Assembler::GrowBuffer() {
Andrei Popescu31002712010-02-23 13:46:05 +0000423 ASSERT(buffer_overflow());
Steve Blocka7e24c12009-10-30 11:49:00 +0000424 if (!own_buffer_) FATAL("external code buffer is too small");
425
Andrei Popescu31002712010-02-23 13:46:05 +0000426 // Compute new buffer size.
Steve Blocka7e24c12009-10-30 11:49:00 +0000427 CodeDesc desc; // the new buffer
428 if (buffer_size_ < 4*KB) {
429 desc.buffer_size = 4*KB;
430 } else {
431 desc.buffer_size = 2*buffer_size_;
432 }
433 // Some internal data structures overflow for very large buffers,
434 // they must ensure that kMaximalBufferSize is not too large.
435 if ((desc.buffer_size > kMaximalBufferSize) ||
Steve Block3ce2e202009-11-05 08:53:23 +0000436 (desc.buffer_size > Heap::MaxOldGenerationSize())) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000437 V8::FatalProcessOutOfMemory("Assembler::GrowBuffer");
438 }
439
Andrei Popescu31002712010-02-23 13:46:05 +0000440 // Setup new buffer.
Steve Blocka7e24c12009-10-30 11:49:00 +0000441 desc.buffer = NewArray<byte>(desc.buffer_size);
442 desc.instr_size = pc_offset();
Steve Blockd0582a62009-12-15 09:54:21 +0000443 desc.reloc_size =
444 static_cast<int>((buffer_ + buffer_size_) - (reloc_info_writer.pos()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000445
446 // Clear the buffer in debug mode. Use 'int3' instructions to make
447 // sure to get into problems if we ever run uninitialized code.
448#ifdef DEBUG
449 memset(desc.buffer, 0xCC, desc.buffer_size);
450#endif
451
Andrei Popescu31002712010-02-23 13:46:05 +0000452 // Copy the data.
Steve Blocka7e24c12009-10-30 11:49:00 +0000453 intptr_t pc_delta = desc.buffer - buffer_;
454 intptr_t rc_delta = (desc.buffer + desc.buffer_size) -
455 (buffer_ + buffer_size_);
456 memmove(desc.buffer, buffer_, desc.instr_size);
457 memmove(rc_delta + reloc_info_writer.pos(),
458 reloc_info_writer.pos(), desc.reloc_size);
459
Andrei Popescu31002712010-02-23 13:46:05 +0000460 // Switch buffers.
Steve Blocka7e24c12009-10-30 11:49:00 +0000461 if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) {
462 spare_buffer_ = buffer_;
463 } else {
464 DeleteArray(buffer_);
465 }
466 buffer_ = desc.buffer;
467 buffer_size_ = desc.buffer_size;
468 pc_ += pc_delta;
469 if (last_pc_ != NULL) {
470 last_pc_ += pc_delta;
471 }
472 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
473 reloc_info_writer.last_pc() + pc_delta);
474
Andrei Popescu31002712010-02-23 13:46:05 +0000475 // Relocate runtime entries.
Steve Blocka7e24c12009-10-30 11:49:00 +0000476 for (RelocIterator it(desc); !it.done(); it.next()) {
477 RelocInfo::Mode rmode = it.rinfo()->rmode();
478 if (rmode == RelocInfo::INTERNAL_REFERENCE) {
479 intptr_t* p = reinterpret_cast<intptr_t*>(it.rinfo()->pc());
480 if (*p != 0) { // 0 means uninitialized.
481 *p += pc_delta;
482 }
483 }
484 }
485
486 ASSERT(!buffer_overflow());
487}
488
489
490void Assembler::emit_operand(int code, const Operand& adr) {
491 ASSERT(is_uint3(code));
492 const unsigned length = adr.len_;
493 ASSERT(length > 0);
494
495 // Emit updated ModR/M byte containing the given register.
496 ASSERT((adr.buf_[0] & 0x38) == 0);
497 pc_[0] = adr.buf_[0] | code << 3;
498
499 // Emit the rest of the encoded operand.
500 for (unsigned i = 1; i < length; i++) pc_[i] = adr.buf_[i];
501 pc_ += length;
502}
503
504
Andrei Popescu31002712010-02-23 13:46:05 +0000505// Assembler Instruction implementations.
Steve Blocka7e24c12009-10-30 11:49:00 +0000506
507void Assembler::arithmetic_op(byte opcode, Register reg, const Operand& op) {
508 EnsureSpace ensure_space(this);
509 last_pc_ = pc_;
510 emit_rex_64(reg, op);
511 emit(opcode);
512 emit_operand(reg, op);
513}
514
515
516void Assembler::arithmetic_op(byte opcode, Register reg, Register rm_reg) {
517 EnsureSpace ensure_space(this);
518 last_pc_ = pc_;
Leon Clarkef7060e22010-06-03 12:02:55 +0100519 ASSERT((opcode & 0xC6) == 2);
520 if (rm_reg.low_bits() == 4) { // Forces SIB byte.
521 // Swap reg and rm_reg and change opcode operand order.
522 emit_rex_64(rm_reg, reg);
523 emit(opcode ^ 0x02);
524 emit_modrm(rm_reg, reg);
525 } else {
526 emit_rex_64(reg, rm_reg);
527 emit(opcode);
528 emit_modrm(reg, rm_reg);
529 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000530}
531
532
533void Assembler::arithmetic_op_16(byte opcode, Register reg, Register rm_reg) {
534 EnsureSpace ensure_space(this);
535 last_pc_ = pc_;
Leon Clarkef7060e22010-06-03 12:02:55 +0100536 ASSERT((opcode & 0xC6) == 2);
537 if (rm_reg.low_bits() == 4) { // Forces SIB byte.
538 // Swap reg and rm_reg and change opcode operand order.
539 emit(0x66);
540 emit_optional_rex_32(rm_reg, reg);
541 emit(opcode ^ 0x02);
542 emit_modrm(rm_reg, reg);
543 } else {
544 emit(0x66);
545 emit_optional_rex_32(reg, rm_reg);
546 emit(opcode);
547 emit_modrm(reg, rm_reg);
548 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000549}
550
551
552void Assembler::arithmetic_op_16(byte opcode,
553 Register reg,
554 const Operand& rm_reg) {
555 EnsureSpace ensure_space(this);
556 last_pc_ = pc_;
557 emit(0x66);
558 emit_optional_rex_32(reg, rm_reg);
559 emit(opcode);
560 emit_operand(reg, rm_reg);
561}
562
563
564void Assembler::arithmetic_op_32(byte opcode, Register reg, Register rm_reg) {
565 EnsureSpace ensure_space(this);
566 last_pc_ = pc_;
Leon Clarkef7060e22010-06-03 12:02:55 +0100567 ASSERT((opcode & 0xC6) == 2);
568 if (rm_reg.low_bits() == 4) { // Forces SIB byte.
569 // Swap reg and rm_reg and change opcode operand order.
570 emit_optional_rex_32(rm_reg, reg);
571 emit(opcode ^ 0x02); // E.g. 0x03 -> 0x01 for ADD.
572 emit_modrm(rm_reg, reg);
573 } else {
574 emit_optional_rex_32(reg, rm_reg);
575 emit(opcode);
576 emit_modrm(reg, rm_reg);
577 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000578}
579
580
581void Assembler::arithmetic_op_32(byte opcode,
582 Register reg,
583 const Operand& rm_reg) {
584 EnsureSpace ensure_space(this);
585 last_pc_ = pc_;
586 emit_optional_rex_32(reg, rm_reg);
587 emit(opcode);
588 emit_operand(reg, rm_reg);
589}
590
591
592void Assembler::immediate_arithmetic_op(byte subcode,
593 Register dst,
594 Immediate src) {
595 EnsureSpace ensure_space(this);
596 last_pc_ = pc_;
597 emit_rex_64(dst);
598 if (is_int8(src.value_)) {
599 emit(0x83);
600 emit_modrm(subcode, dst);
601 emit(src.value_);
602 } else if (dst.is(rax)) {
603 emit(0x05 | (subcode << 3));
604 emitl(src.value_);
605 } else {
606 emit(0x81);
607 emit_modrm(subcode, dst);
608 emitl(src.value_);
609 }
610}
611
612void Assembler::immediate_arithmetic_op(byte subcode,
613 const Operand& dst,
614 Immediate src) {
615 EnsureSpace ensure_space(this);
616 last_pc_ = pc_;
617 emit_rex_64(dst);
618 if (is_int8(src.value_)) {
619 emit(0x83);
620 emit_operand(subcode, dst);
621 emit(src.value_);
622 } else {
623 emit(0x81);
624 emit_operand(subcode, dst);
625 emitl(src.value_);
626 }
627}
628
629
630void Assembler::immediate_arithmetic_op_16(byte subcode,
631 Register dst,
632 Immediate src) {
633 EnsureSpace ensure_space(this);
634 last_pc_ = pc_;
635 emit(0x66); // Operand size override prefix.
636 emit_optional_rex_32(dst);
637 if (is_int8(src.value_)) {
638 emit(0x83);
639 emit_modrm(subcode, dst);
640 emit(src.value_);
641 } else if (dst.is(rax)) {
642 emit(0x05 | (subcode << 3));
Steve Block3ce2e202009-11-05 08:53:23 +0000643 emitw(src.value_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000644 } else {
645 emit(0x81);
646 emit_modrm(subcode, dst);
Steve Block3ce2e202009-11-05 08:53:23 +0000647 emitw(src.value_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000648 }
649}
650
651
652void Assembler::immediate_arithmetic_op_16(byte subcode,
653 const Operand& dst,
654 Immediate src) {
655 EnsureSpace ensure_space(this);
656 last_pc_ = pc_;
657 emit(0x66); // Operand size override prefix.
658 emit_optional_rex_32(dst);
659 if (is_int8(src.value_)) {
660 emit(0x83);
661 emit_operand(subcode, dst);
662 emit(src.value_);
663 } else {
664 emit(0x81);
665 emit_operand(subcode, dst);
Steve Block3ce2e202009-11-05 08:53:23 +0000666 emitw(src.value_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000667 }
668}
669
670
671void Assembler::immediate_arithmetic_op_32(byte subcode,
672 Register dst,
673 Immediate src) {
674 EnsureSpace ensure_space(this);
675 last_pc_ = pc_;
676 emit_optional_rex_32(dst);
677 if (is_int8(src.value_)) {
678 emit(0x83);
679 emit_modrm(subcode, dst);
680 emit(src.value_);
681 } else if (dst.is(rax)) {
682 emit(0x05 | (subcode << 3));
683 emitl(src.value_);
684 } else {
685 emit(0x81);
686 emit_modrm(subcode, dst);
687 emitl(src.value_);
688 }
689}
690
691
692void Assembler::immediate_arithmetic_op_32(byte subcode,
693 const Operand& dst,
694 Immediate src) {
695 EnsureSpace ensure_space(this);
696 last_pc_ = pc_;
697 emit_optional_rex_32(dst);
698 if (is_int8(src.value_)) {
699 emit(0x83);
700 emit_operand(subcode, dst);
701 emit(src.value_);
702 } else {
703 emit(0x81);
704 emit_operand(subcode, dst);
705 emitl(src.value_);
706 }
707}
708
709
710void Assembler::immediate_arithmetic_op_8(byte subcode,
711 const Operand& dst,
712 Immediate src) {
713 EnsureSpace ensure_space(this);
714 last_pc_ = pc_;
715 emit_optional_rex_32(dst);
716 ASSERT(is_int8(src.value_) || is_uint8(src.value_));
717 emit(0x80);
718 emit_operand(subcode, dst);
719 emit(src.value_);
720}
721
722
723void Assembler::immediate_arithmetic_op_8(byte subcode,
724 Register dst,
725 Immediate src) {
726 EnsureSpace ensure_space(this);
727 last_pc_ = pc_;
728 if (dst.code() > 3) {
729 // Use 64-bit mode byte registers.
730 emit_rex_64(dst);
731 }
732 ASSERT(is_int8(src.value_) || is_uint8(src.value_));
733 emit(0x80);
734 emit_modrm(subcode, dst);
735 emit(src.value_);
736}
737
738
739void Assembler::shift(Register dst, Immediate shift_amount, int subcode) {
740 EnsureSpace ensure_space(this);
741 last_pc_ = pc_;
742 ASSERT(is_uint6(shift_amount.value_)); // illegal shift count
743 if (shift_amount.value_ == 1) {
744 emit_rex_64(dst);
745 emit(0xD1);
746 emit_modrm(subcode, dst);
747 } else {
748 emit_rex_64(dst);
749 emit(0xC1);
750 emit_modrm(subcode, dst);
751 emit(shift_amount.value_);
752 }
753}
754
755
756void Assembler::shift(Register dst, int subcode) {
757 EnsureSpace ensure_space(this);
758 last_pc_ = pc_;
759 emit_rex_64(dst);
760 emit(0xD3);
761 emit_modrm(subcode, dst);
762}
763
764
765void Assembler::shift_32(Register dst, int subcode) {
766 EnsureSpace ensure_space(this);
767 last_pc_ = pc_;
768 emit_optional_rex_32(dst);
769 emit(0xD3);
770 emit_modrm(subcode, dst);
771}
772
773
774void Assembler::shift_32(Register dst, Immediate shift_amount, int subcode) {
775 EnsureSpace ensure_space(this);
776 last_pc_ = pc_;
Steve Block3ce2e202009-11-05 08:53:23 +0000777 ASSERT(is_uint5(shift_amount.value_)); // illegal shift count
Steve Blocka7e24c12009-10-30 11:49:00 +0000778 if (shift_amount.value_ == 1) {
779 emit_optional_rex_32(dst);
780 emit(0xD1);
781 emit_modrm(subcode, dst);
782 } else {
783 emit_optional_rex_32(dst);
784 emit(0xC1);
785 emit_modrm(subcode, dst);
786 emit(shift_amount.value_);
787 }
788}
789
790
791void Assembler::bt(const Operand& dst, Register src) {
792 EnsureSpace ensure_space(this);
793 last_pc_ = pc_;
794 emit_rex_64(src, dst);
795 emit(0x0F);
796 emit(0xA3);
797 emit_operand(src, dst);
798}
799
800
801void Assembler::bts(const Operand& dst, Register src) {
802 EnsureSpace ensure_space(this);
803 last_pc_ = pc_;
804 emit_rex_64(src, dst);
805 emit(0x0F);
806 emit(0xAB);
807 emit_operand(src, dst);
808}
809
810
811void Assembler::call(Label* L) {
812 EnsureSpace ensure_space(this);
813 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000814 // 1110 1000 #32-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +0000815 emit(0xE8);
816 if (L->is_bound()) {
817 int offset = L->pos() - pc_offset() - sizeof(int32_t);
818 ASSERT(offset <= 0);
819 emitl(offset);
820 } else if (L->is_linked()) {
821 emitl(L->pos());
822 L->link_to(pc_offset() - sizeof(int32_t));
823 } else {
824 ASSERT(L->is_unused());
825 int32_t current = pc_offset();
826 emitl(current);
827 L->link_to(current);
828 }
829}
830
831
Steve Block3ce2e202009-11-05 08:53:23 +0000832void Assembler::call(Handle<Code> target, RelocInfo::Mode rmode) {
833 EnsureSpace ensure_space(this);
834 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000835 // 1110 1000 #32-bit disp.
Steve Block3ce2e202009-11-05 08:53:23 +0000836 emit(0xE8);
837 emit_code_target(target, rmode);
838}
839
840
Steve Blocka7e24c12009-10-30 11:49:00 +0000841void Assembler::call(Register adr) {
842 EnsureSpace ensure_space(this);
843 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000844 // Opcode: FF /2 r64.
Steve Block8defd9f2010-07-08 12:39:36 +0100845 emit_optional_rex_32(adr);
Steve Blocka7e24c12009-10-30 11:49:00 +0000846 emit(0xFF);
847 emit_modrm(0x2, adr);
848}
849
850
851void Assembler::call(const Operand& op) {
852 EnsureSpace ensure_space(this);
853 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000854 // Opcode: FF /2 m64.
Steve Block8defd9f2010-07-08 12:39:36 +0100855 emit_optional_rex_32(op);
Steve Blocka7e24c12009-10-30 11:49:00 +0000856 emit(0xFF);
Steve Block8defd9f2010-07-08 12:39:36 +0100857 emit_operand(0x2, op);
Steve Blocka7e24c12009-10-30 11:49:00 +0000858}
859
860
Steve Block3ce2e202009-11-05 08:53:23 +0000861void Assembler::clc() {
862 EnsureSpace ensure_space(this);
863 last_pc_ = pc_;
864 emit(0xF8);
865}
866
Steve Blocka7e24c12009-10-30 11:49:00 +0000867void Assembler::cdq() {
868 EnsureSpace ensure_space(this);
869 last_pc_ = pc_;
870 emit(0x99);
871}
872
873
874void Assembler::cmovq(Condition cc, Register dst, Register src) {
Steve Block3ce2e202009-11-05 08:53:23 +0000875 if (cc == always) {
876 movq(dst, src);
877 } else if (cc == never) {
878 return;
879 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000880 // No need to check CpuInfo for CMOV support, it's a required part of the
881 // 64-bit architecture.
882 ASSERT(cc >= 0); // Use mov for unconditional moves.
883 EnsureSpace ensure_space(this);
884 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000885 // Opcode: REX.W 0f 40 + cc /r.
Steve Blocka7e24c12009-10-30 11:49:00 +0000886 emit_rex_64(dst, src);
887 emit(0x0f);
888 emit(0x40 + cc);
889 emit_modrm(dst, src);
890}
891
892
893void Assembler::cmovq(Condition cc, Register dst, const Operand& src) {
Steve Block3ce2e202009-11-05 08:53:23 +0000894 if (cc == always) {
895 movq(dst, src);
896 } else if (cc == never) {
897 return;
898 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000899 ASSERT(cc >= 0);
900 EnsureSpace ensure_space(this);
901 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000902 // Opcode: REX.W 0f 40 + cc /r.
Steve Blocka7e24c12009-10-30 11:49:00 +0000903 emit_rex_64(dst, src);
904 emit(0x0f);
905 emit(0x40 + cc);
906 emit_operand(dst, src);
907}
908
909
910void Assembler::cmovl(Condition cc, Register dst, Register src) {
Steve Block3ce2e202009-11-05 08:53:23 +0000911 if (cc == always) {
912 movl(dst, src);
913 } else if (cc == never) {
914 return;
915 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000916 ASSERT(cc >= 0);
917 EnsureSpace ensure_space(this);
918 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000919 // Opcode: 0f 40 + cc /r.
Steve Blocka7e24c12009-10-30 11:49:00 +0000920 emit_optional_rex_32(dst, src);
921 emit(0x0f);
922 emit(0x40 + cc);
923 emit_modrm(dst, src);
924}
925
926
927void Assembler::cmovl(Condition cc, Register dst, const Operand& src) {
Steve Block3ce2e202009-11-05 08:53:23 +0000928 if (cc == always) {
929 movl(dst, src);
930 } else if (cc == never) {
931 return;
932 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000933 ASSERT(cc >= 0);
934 EnsureSpace ensure_space(this);
935 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000936 // Opcode: 0f 40 + cc /r.
Steve Blocka7e24c12009-10-30 11:49:00 +0000937 emit_optional_rex_32(dst, src);
938 emit(0x0f);
939 emit(0x40 + cc);
940 emit_operand(dst, src);
941}
942
943
944void Assembler::cmpb_al(Immediate imm8) {
945 ASSERT(is_int8(imm8.value_) || is_uint8(imm8.value_));
946 EnsureSpace ensure_space(this);
947 last_pc_ = pc_;
948 emit(0x3c);
949 emit(imm8.value_);
950}
951
952
953void Assembler::cpuid() {
Steve Blockd0582a62009-12-15 09:54:21 +0000954 ASSERT(CpuFeatures::IsEnabled(CPUID));
Steve Blocka7e24c12009-10-30 11:49:00 +0000955 EnsureSpace ensure_space(this);
956 last_pc_ = pc_;
957 emit(0x0F);
958 emit(0xA2);
959}
960
961
962void Assembler::cqo() {
963 EnsureSpace ensure_space(this);
964 last_pc_ = pc_;
965 emit_rex_64();
966 emit(0x99);
967}
968
969
970void Assembler::decq(Register dst) {
971 EnsureSpace ensure_space(this);
972 last_pc_ = pc_;
973 emit_rex_64(dst);
974 emit(0xFF);
975 emit_modrm(0x1, dst);
976}
977
978
979void Assembler::decq(const Operand& dst) {
980 EnsureSpace ensure_space(this);
981 last_pc_ = pc_;
982 emit_rex_64(dst);
983 emit(0xFF);
984 emit_operand(1, dst);
985}
986
987
988void Assembler::decl(Register dst) {
989 EnsureSpace ensure_space(this);
990 last_pc_ = pc_;
991 emit_optional_rex_32(dst);
992 emit(0xFF);
993 emit_modrm(0x1, dst);
994}
995
996
997void Assembler::decl(const Operand& dst) {
998 EnsureSpace ensure_space(this);
999 last_pc_ = pc_;
1000 emit_optional_rex_32(dst);
1001 emit(0xFF);
1002 emit_operand(1, dst);
1003}
1004
1005
Steve Block3ce2e202009-11-05 08:53:23 +00001006void Assembler::decb(Register dst) {
1007 EnsureSpace ensure_space(this);
1008 last_pc_ = pc_;
1009 if (dst.code() > 3) {
1010 // Register is not one of al, bl, cl, dl. Its encoding needs REX.
1011 emit_rex_32(dst);
1012 }
1013 emit(0xFE);
1014 emit_modrm(0x1, dst);
1015}
1016
1017
1018void Assembler::decb(const Operand& dst) {
1019 EnsureSpace ensure_space(this);
1020 last_pc_ = pc_;
1021 emit_optional_rex_32(dst);
1022 emit(0xFE);
1023 emit_operand(1, dst);
1024}
1025
1026
Steve Blocka7e24c12009-10-30 11:49:00 +00001027void Assembler::enter(Immediate size) {
1028 EnsureSpace ensure_space(this);
1029 last_pc_ = pc_;
1030 emit(0xC8);
1031 emitw(size.value_); // 16 bit operand, always.
1032 emit(0);
1033}
1034
1035
1036void Assembler::hlt() {
1037 EnsureSpace ensure_space(this);
1038 last_pc_ = pc_;
1039 emit(0xF4);
1040}
1041
1042
1043void Assembler::idivq(Register src) {
1044 EnsureSpace ensure_space(this);
1045 last_pc_ = pc_;
1046 emit_rex_64(src);
1047 emit(0xF7);
1048 emit_modrm(0x7, src);
1049}
1050
1051
1052void Assembler::idivl(Register src) {
1053 EnsureSpace ensure_space(this);
1054 last_pc_ = pc_;
1055 emit_optional_rex_32(src);
1056 emit(0xF7);
1057 emit_modrm(0x7, src);
1058}
1059
1060
1061void Assembler::imul(Register src) {
1062 EnsureSpace ensure_space(this);
1063 last_pc_ = pc_;
1064 emit_rex_64(src);
1065 emit(0xF7);
1066 emit_modrm(0x5, src);
1067}
1068
1069
1070void Assembler::imul(Register dst, Register src) {
1071 EnsureSpace ensure_space(this);
1072 last_pc_ = pc_;
1073 emit_rex_64(dst, src);
1074 emit(0x0F);
1075 emit(0xAF);
1076 emit_modrm(dst, src);
1077}
1078
1079
1080void Assembler::imul(Register dst, const Operand& src) {
1081 EnsureSpace ensure_space(this);
1082 last_pc_ = pc_;
1083 emit_rex_64(dst, src);
1084 emit(0x0F);
1085 emit(0xAF);
1086 emit_operand(dst, src);
1087}
1088
1089
1090void Assembler::imul(Register dst, Register src, Immediate imm) {
1091 EnsureSpace ensure_space(this);
1092 last_pc_ = pc_;
1093 emit_rex_64(dst, src);
1094 if (is_int8(imm.value_)) {
1095 emit(0x6B);
1096 emit_modrm(dst, src);
1097 emit(imm.value_);
1098 } else {
1099 emit(0x69);
1100 emit_modrm(dst, src);
1101 emitl(imm.value_);
1102 }
1103}
1104
1105
1106void Assembler::imull(Register dst, Register src) {
1107 EnsureSpace ensure_space(this);
1108 last_pc_ = pc_;
1109 emit_optional_rex_32(dst, src);
1110 emit(0x0F);
1111 emit(0xAF);
1112 emit_modrm(dst, src);
1113}
1114
1115
Steve Block6ded16b2010-05-10 14:33:55 +01001116void Assembler::imull(Register dst, Register src, Immediate imm) {
1117 EnsureSpace ensure_space(this);
1118 last_pc_ = pc_;
1119 emit_optional_rex_32(dst, src);
1120 if (is_int8(imm.value_)) {
1121 emit(0x6B);
1122 emit_modrm(dst, src);
1123 emit(imm.value_);
1124 } else {
1125 emit(0x69);
1126 emit_modrm(dst, src);
1127 emitl(imm.value_);
1128 }
1129}
1130
1131
Steve Blocka7e24c12009-10-30 11:49:00 +00001132void Assembler::incq(Register dst) {
1133 EnsureSpace ensure_space(this);
1134 last_pc_ = pc_;
1135 emit_rex_64(dst);
1136 emit(0xFF);
1137 emit_modrm(0x0, dst);
1138}
1139
1140
1141void Assembler::incq(const Operand& dst) {
1142 EnsureSpace ensure_space(this);
1143 last_pc_ = pc_;
1144 emit_rex_64(dst);
1145 emit(0xFF);
1146 emit_operand(0, dst);
1147}
1148
1149
1150void Assembler::incl(const Operand& dst) {
1151 EnsureSpace ensure_space(this);
1152 last_pc_ = pc_;
1153 emit_optional_rex_32(dst);
1154 emit(0xFF);
1155 emit_operand(0, dst);
1156}
1157
1158
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001159void Assembler::incl(Register dst) {
1160 EnsureSpace ensure_space(this);
1161 last_pc_ = pc_;
1162 emit_optional_rex_32(dst);
1163 emit(0xFF);
1164 emit_modrm(0, dst);
1165}
1166
1167
Steve Blocka7e24c12009-10-30 11:49:00 +00001168void Assembler::int3() {
1169 EnsureSpace ensure_space(this);
1170 last_pc_ = pc_;
1171 emit(0xCC);
1172}
1173
1174
1175void Assembler::j(Condition cc, Label* L) {
Steve Block3ce2e202009-11-05 08:53:23 +00001176 if (cc == always) {
1177 jmp(L);
1178 return;
1179 } else if (cc == never) {
1180 return;
1181 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001182 EnsureSpace ensure_space(this);
1183 last_pc_ = pc_;
1184 ASSERT(is_uint4(cc));
1185 if (L->is_bound()) {
1186 const int short_size = 2;
1187 const int long_size = 6;
1188 int offs = L->pos() - pc_offset();
1189 ASSERT(offs <= 0);
1190 if (is_int8(offs - short_size)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001191 // 0111 tttn #8-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001192 emit(0x70 | cc);
1193 emit((offs - short_size) & 0xFF);
1194 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00001195 // 0000 1111 1000 tttn #32-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001196 emit(0x0F);
1197 emit(0x80 | cc);
1198 emitl(offs - long_size);
1199 }
1200 } else if (L->is_linked()) {
Andrei Popescu31002712010-02-23 13:46:05 +00001201 // 0000 1111 1000 tttn #32-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001202 emit(0x0F);
1203 emit(0x80 | cc);
1204 emitl(L->pos());
1205 L->link_to(pc_offset() - sizeof(int32_t));
1206 } else {
1207 ASSERT(L->is_unused());
1208 emit(0x0F);
1209 emit(0x80 | cc);
1210 int32_t current = pc_offset();
1211 emitl(current);
1212 L->link_to(current);
1213 }
1214}
1215
1216
Steve Block3ce2e202009-11-05 08:53:23 +00001217void Assembler::j(Condition cc,
1218 Handle<Code> target,
1219 RelocInfo::Mode rmode) {
1220 EnsureSpace ensure_space(this);
1221 last_pc_ = pc_;
1222 ASSERT(is_uint4(cc));
Andrei Popescu31002712010-02-23 13:46:05 +00001223 // 0000 1111 1000 tttn #32-bit disp.
Steve Block3ce2e202009-11-05 08:53:23 +00001224 emit(0x0F);
1225 emit(0x80 | cc);
1226 emit_code_target(target, rmode);
1227}
1228
1229
Steve Blocka7e24c12009-10-30 11:49:00 +00001230void Assembler::jmp(Label* L) {
1231 EnsureSpace ensure_space(this);
1232 last_pc_ = pc_;
Steve Block6ded16b2010-05-10 14:33:55 +01001233 const int short_size = sizeof(int8_t);
1234 const int long_size = sizeof(int32_t);
Steve Blocka7e24c12009-10-30 11:49:00 +00001235 if (L->is_bound()) {
1236 int offs = L->pos() - pc_offset() - 1;
1237 ASSERT(offs <= 0);
Steve Block6ded16b2010-05-10 14:33:55 +01001238 if (is_int8(offs - short_size)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001239 // 1110 1011 #8-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001240 emit(0xEB);
Steve Block6ded16b2010-05-10 14:33:55 +01001241 emit((offs - short_size) & 0xFF);
Steve Blocka7e24c12009-10-30 11:49:00 +00001242 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00001243 // 1110 1001 #32-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001244 emit(0xE9);
Steve Block6ded16b2010-05-10 14:33:55 +01001245 emitl(offs - long_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00001246 }
1247 } else if (L->is_linked()) {
Andrei Popescu31002712010-02-23 13:46:05 +00001248 // 1110 1001 #32-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001249 emit(0xE9);
1250 emitl(L->pos());
Steve Block6ded16b2010-05-10 14:33:55 +01001251 L->link_to(pc_offset() - long_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00001252 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00001253 // 1110 1001 #32-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001254 ASSERT(L->is_unused());
1255 emit(0xE9);
1256 int32_t current = pc_offset();
1257 emitl(current);
1258 L->link_to(current);
1259 }
1260}
1261
1262
Steve Block3ce2e202009-11-05 08:53:23 +00001263void Assembler::jmp(Handle<Code> target, RelocInfo::Mode rmode) {
1264 EnsureSpace ensure_space(this);
1265 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +00001266 // 1110 1001 #32-bit disp.
Steve Block3ce2e202009-11-05 08:53:23 +00001267 emit(0xE9);
1268 emit_code_target(target, rmode);
1269}
1270
1271
Steve Blocka7e24c12009-10-30 11:49:00 +00001272void Assembler::jmp(Register target) {
1273 EnsureSpace ensure_space(this);
1274 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +00001275 // Opcode FF/4 r64.
Steve Block8defd9f2010-07-08 12:39:36 +01001276 emit_optional_rex_32(target);
Steve Blocka7e24c12009-10-30 11:49:00 +00001277 emit(0xFF);
1278 emit_modrm(0x4, target);
1279}
1280
1281
1282void Assembler::jmp(const Operand& src) {
1283 EnsureSpace ensure_space(this);
1284 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +00001285 // Opcode FF/4 m64.
Steve Blocka7e24c12009-10-30 11:49:00 +00001286 emit_optional_rex_32(src);
1287 emit(0xFF);
1288 emit_operand(0x4, src);
1289}
1290
1291
1292void Assembler::lea(Register dst, const Operand& src) {
1293 EnsureSpace ensure_space(this);
1294 last_pc_ = pc_;
1295 emit_rex_64(dst, src);
1296 emit(0x8D);
1297 emit_operand(dst, src);
1298}
1299
1300
Steve Block6ded16b2010-05-10 14:33:55 +01001301void Assembler::leal(Register dst, const Operand& src) {
1302 EnsureSpace ensure_space(this);
1303 last_pc_ = pc_;
1304 emit_optional_rex_32(dst, src);
1305 emit(0x8D);
1306 emit_operand(dst, src);
1307}
1308
1309
Steve Blocka7e24c12009-10-30 11:49:00 +00001310void Assembler::load_rax(void* value, RelocInfo::Mode mode) {
1311 EnsureSpace ensure_space(this);
1312 last_pc_ = pc_;
1313 emit(0x48); // REX.W
1314 emit(0xA1);
1315 emitq(reinterpret_cast<uintptr_t>(value), mode);
1316}
1317
1318
1319void Assembler::load_rax(ExternalReference ref) {
1320 load_rax(ref.address(), RelocInfo::EXTERNAL_REFERENCE);
1321}
1322
1323
1324void Assembler::leave() {
1325 EnsureSpace ensure_space(this);
1326 last_pc_ = pc_;
1327 emit(0xC9);
1328}
1329
1330
1331void Assembler::movb(Register dst, const Operand& src) {
1332 EnsureSpace ensure_space(this);
1333 last_pc_ = pc_;
1334 emit_rex_32(dst, src);
1335 emit(0x8A);
1336 emit_operand(dst, src);
1337}
1338
Steve Block6ded16b2010-05-10 14:33:55 +01001339
Steve Blocka7e24c12009-10-30 11:49:00 +00001340void Assembler::movb(Register dst, Immediate imm) {
1341 EnsureSpace ensure_space(this);
1342 last_pc_ = pc_;
1343 emit_rex_32(dst);
1344 emit(0xC6);
1345 emit_modrm(0x0, dst);
1346 emit(imm.value_);
1347}
1348
Steve Block6ded16b2010-05-10 14:33:55 +01001349
Steve Blocka7e24c12009-10-30 11:49:00 +00001350void Assembler::movb(const Operand& dst, Register src) {
1351 EnsureSpace ensure_space(this);
1352 last_pc_ = pc_;
1353 emit_rex_32(src, dst);
1354 emit(0x88);
1355 emit_operand(src, dst);
1356}
1357
Steve Block6ded16b2010-05-10 14:33:55 +01001358
Steve Block3ce2e202009-11-05 08:53:23 +00001359void Assembler::movw(const Operand& dst, Register src) {
1360 EnsureSpace ensure_space(this);
1361 last_pc_ = pc_;
1362 emit(0x66);
1363 emit_optional_rex_32(src, dst);
1364 emit(0x89);
1365 emit_operand(src, dst);
1366}
1367
Steve Block6ded16b2010-05-10 14:33:55 +01001368
Steve Blocka7e24c12009-10-30 11:49:00 +00001369void Assembler::movl(Register dst, const Operand& src) {
1370 EnsureSpace ensure_space(this);
1371 last_pc_ = pc_;
1372 emit_optional_rex_32(dst, src);
1373 emit(0x8B);
1374 emit_operand(dst, src);
1375}
1376
1377
1378void Assembler::movl(Register dst, Register src) {
1379 EnsureSpace ensure_space(this);
1380 last_pc_ = pc_;
Leon Clarkef7060e22010-06-03 12:02:55 +01001381 if (src.low_bits() == 4) {
1382 emit_optional_rex_32(src, dst);
1383 emit(0x89);
1384 emit_modrm(src, dst);
1385 } else {
1386 emit_optional_rex_32(dst, src);
1387 emit(0x8B);
1388 emit_modrm(dst, src);
1389 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001390}
1391
1392
1393void Assembler::movl(const Operand& dst, Register src) {
1394 EnsureSpace ensure_space(this);
1395 last_pc_ = pc_;
1396 emit_optional_rex_32(src, dst);
1397 emit(0x89);
1398 emit_operand(src, dst);
1399}
1400
1401
1402void Assembler::movl(const Operand& dst, Immediate value) {
1403 EnsureSpace ensure_space(this);
1404 last_pc_ = pc_;
1405 emit_optional_rex_32(dst);
1406 emit(0xC7);
1407 emit_operand(0x0, dst);
1408 emit(value); // Only 32-bit immediates are possible, not 8-bit immediates.
1409}
1410
1411
1412void Assembler::movl(Register dst, Immediate value) {
1413 EnsureSpace ensure_space(this);
1414 last_pc_ = pc_;
1415 emit_optional_rex_32(dst);
1416 emit(0xC7);
1417 emit_modrm(0x0, dst);
1418 emit(value); // Only 32-bit immediates are possible, not 8-bit immediates.
1419}
1420
1421
1422void Assembler::movq(Register dst, const Operand& src) {
1423 EnsureSpace ensure_space(this);
1424 last_pc_ = pc_;
1425 emit_rex_64(dst, src);
1426 emit(0x8B);
1427 emit_operand(dst, src);
1428}
1429
1430
1431void Assembler::movq(Register dst, Register src) {
1432 EnsureSpace ensure_space(this);
1433 last_pc_ = pc_;
Leon Clarkef7060e22010-06-03 12:02:55 +01001434 if (src.low_bits() == 4) {
1435 emit_rex_64(src, dst);
1436 emit(0x89);
1437 emit_modrm(src, dst);
1438 } else {
1439 emit_rex_64(dst, src);
1440 emit(0x8B);
1441 emit_modrm(dst, src);
1442 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001443}
1444
1445
1446void Assembler::movq(Register dst, Immediate value) {
1447 EnsureSpace ensure_space(this);
1448 last_pc_ = pc_;
1449 emit_rex_64(dst);
1450 emit(0xC7);
1451 emit_modrm(0x0, dst);
1452 emit(value); // Only 32-bit immediates are possible, not 8-bit immediates.
1453}
1454
1455
1456void Assembler::movq(const Operand& dst, Register src) {
1457 EnsureSpace ensure_space(this);
1458 last_pc_ = pc_;
1459 emit_rex_64(src, dst);
1460 emit(0x89);
1461 emit_operand(src, dst);
1462}
1463
1464
1465void Assembler::movq(Register dst, void* value, RelocInfo::Mode rmode) {
1466 // This method must not be used with heap object references. The stored
1467 // address is not GC safe. Use the handle version instead.
1468 ASSERT(rmode > RelocInfo::LAST_GCED_ENUM);
1469 EnsureSpace ensure_space(this);
1470 last_pc_ = pc_;
1471 emit_rex_64(dst);
1472 emit(0xB8 | dst.low_bits());
1473 emitq(reinterpret_cast<uintptr_t>(value), rmode);
1474}
1475
1476
1477void Assembler::movq(Register dst, int64_t value, RelocInfo::Mode rmode) {
1478 // Non-relocatable values might not need a 64-bit representation.
1479 if (rmode == RelocInfo::NONE) {
1480 // Sadly, there is no zero or sign extending move for 8-bit immediates.
1481 if (is_int32(value)) {
1482 movq(dst, Immediate(static_cast<int32_t>(value)));
1483 return;
1484 } else if (is_uint32(value)) {
1485 movl(dst, Immediate(static_cast<int32_t>(value)));
1486 return;
1487 }
1488 // Value cannot be represented by 32 bits, so do a full 64 bit immediate
1489 // value.
1490 }
1491 EnsureSpace ensure_space(this);
1492 last_pc_ = pc_;
1493 emit_rex_64(dst);
1494 emit(0xB8 | dst.low_bits());
1495 emitq(value, rmode);
1496}
1497
1498
1499void Assembler::movq(Register dst, ExternalReference ref) {
1500 EnsureSpace ensure_space(this);
1501 last_pc_ = pc_;
1502 emit_rex_64(dst);
1503 emit(0xB8 | dst.low_bits());
1504 emitq(reinterpret_cast<uintptr_t>(ref.address()),
1505 RelocInfo::EXTERNAL_REFERENCE);
1506}
1507
1508
1509void Assembler::movq(const Operand& dst, Immediate value) {
1510 EnsureSpace ensure_space(this);
1511 last_pc_ = pc_;
1512 emit_rex_64(dst);
1513 emit(0xC7);
1514 emit_operand(0, dst);
1515 emit(value);
1516}
1517
1518
Andrei Popescu31002712010-02-23 13:46:05 +00001519// Loads the ip-relative location of the src label into the target location
1520// (as a 32-bit offset sign extended to 64-bit).
Steve Blocka7e24c12009-10-30 11:49:00 +00001521void Assembler::movl(const Operand& dst, Label* src) {
1522 EnsureSpace ensure_space(this);
1523 last_pc_ = pc_;
1524 emit_optional_rex_32(dst);
1525 emit(0xC7);
1526 emit_operand(0, dst);
1527 if (src->is_bound()) {
1528 int offset = src->pos() - pc_offset() - sizeof(int32_t);
1529 ASSERT(offset <= 0);
1530 emitl(offset);
1531 } else if (src->is_linked()) {
1532 emitl(src->pos());
1533 src->link_to(pc_offset() - sizeof(int32_t));
1534 } else {
1535 ASSERT(src->is_unused());
1536 int32_t current = pc_offset();
1537 emitl(current);
1538 src->link_to(current);
1539 }
1540}
1541
1542
1543void Assembler::movq(Register dst, Handle<Object> value, RelocInfo::Mode mode) {
1544 // If there is no relocation info, emit the value of the handle efficiently
1545 // (possibly using less that 8 bytes for the value).
1546 if (mode == RelocInfo::NONE) {
1547 // There is no possible reason to store a heap pointer without relocation
1548 // info, so it must be a smi.
1549 ASSERT(value->IsSmi());
Steve Block3ce2e202009-11-05 08:53:23 +00001550 movq(dst, reinterpret_cast<int64_t>(*value), RelocInfo::NONE);
Steve Blocka7e24c12009-10-30 11:49:00 +00001551 } else {
1552 EnsureSpace ensure_space(this);
1553 last_pc_ = pc_;
1554 ASSERT(value->IsHeapObject());
1555 ASSERT(!Heap::InNewSpace(*value));
1556 emit_rex_64(dst);
1557 emit(0xB8 | dst.low_bits());
1558 emitq(reinterpret_cast<uintptr_t>(value.location()), mode);
1559 }
1560}
1561
1562
Steve Block3ce2e202009-11-05 08:53:23 +00001563void Assembler::movsxbq(Register dst, const Operand& src) {
1564 EnsureSpace ensure_space(this);
1565 last_pc_ = pc_;
Steve Block8defd9f2010-07-08 12:39:36 +01001566 emit_rex_64(dst, src);
Steve Block3ce2e202009-11-05 08:53:23 +00001567 emit(0x0F);
1568 emit(0xBE);
1569 emit_operand(dst, src);
1570}
1571
1572
1573void Assembler::movsxwq(Register dst, const Operand& src) {
1574 EnsureSpace ensure_space(this);
1575 last_pc_ = pc_;
1576 emit_rex_64(dst, src);
1577 emit(0x0F);
1578 emit(0xBF);
1579 emit_operand(dst, src);
1580}
1581
1582
Steve Blocka7e24c12009-10-30 11:49:00 +00001583void Assembler::movsxlq(Register dst, Register src) {
1584 EnsureSpace ensure_space(this);
1585 last_pc_ = pc_;
1586 emit_rex_64(dst, src);
1587 emit(0x63);
1588 emit_modrm(dst, src);
1589}
1590
1591
1592void Assembler::movsxlq(Register dst, const Operand& src) {
1593 EnsureSpace ensure_space(this);
1594 last_pc_ = pc_;
1595 emit_rex_64(dst, src);
1596 emit(0x63);
1597 emit_operand(dst, src);
1598}
1599
1600
1601void Assembler::movzxbq(Register dst, const Operand& src) {
1602 EnsureSpace ensure_space(this);
1603 last_pc_ = pc_;
Steve Block8defd9f2010-07-08 12:39:36 +01001604 emit_optional_rex_32(dst, src);
Steve Blocka7e24c12009-10-30 11:49:00 +00001605 emit(0x0F);
1606 emit(0xB6);
1607 emit_operand(dst, src);
1608}
1609
1610
1611void Assembler::movzxbl(Register dst, const Operand& src) {
1612 EnsureSpace ensure_space(this);
1613 last_pc_ = pc_;
1614 emit_optional_rex_32(dst, src);
1615 emit(0x0F);
1616 emit(0xB6);
1617 emit_operand(dst, src);
1618}
1619
1620
Steve Block3ce2e202009-11-05 08:53:23 +00001621void Assembler::movzxwq(Register dst, const Operand& src) {
1622 EnsureSpace ensure_space(this);
1623 last_pc_ = pc_;
Steve Block8defd9f2010-07-08 12:39:36 +01001624 emit_optional_rex_32(dst, src);
Steve Block3ce2e202009-11-05 08:53:23 +00001625 emit(0x0F);
1626 emit(0xB7);
1627 emit_operand(dst, src);
1628}
1629
1630
Steve Blocka7e24c12009-10-30 11:49:00 +00001631void Assembler::movzxwl(Register dst, const Operand& src) {
1632 EnsureSpace ensure_space(this);
1633 last_pc_ = pc_;
1634 emit_optional_rex_32(dst, src);
1635 emit(0x0F);
1636 emit(0xB7);
1637 emit_operand(dst, src);
1638}
1639
1640
Leon Clarked91b9f72010-01-27 17:25:45 +00001641void Assembler::repmovsb() {
1642 EnsureSpace ensure_space(this);
1643 last_pc_ = pc_;
1644 emit(0xF3);
1645 emit(0xA4);
1646}
1647
1648
1649void Assembler::repmovsw() {
1650 EnsureSpace ensure_space(this);
1651 last_pc_ = pc_;
1652 emit(0x66); // Operand size override.
1653 emit(0xF3);
1654 emit(0xA4);
1655}
1656
1657
1658void Assembler::repmovsl() {
1659 EnsureSpace ensure_space(this);
1660 last_pc_ = pc_;
1661 emit(0xF3);
1662 emit(0xA5);
1663}
1664
1665
1666void Assembler::repmovsq() {
1667 EnsureSpace ensure_space(this);
1668 last_pc_ = pc_;
1669 emit(0xF3);
1670 emit_rex_64();
1671 emit(0xA5);
1672}
1673
1674
Steve Blocka7e24c12009-10-30 11:49:00 +00001675void Assembler::mul(Register src) {
1676 EnsureSpace ensure_space(this);
1677 last_pc_ = pc_;
1678 emit_rex_64(src);
1679 emit(0xF7);
1680 emit_modrm(0x4, src);
1681}
1682
1683
1684void Assembler::neg(Register dst) {
1685 EnsureSpace ensure_space(this);
1686 last_pc_ = pc_;
1687 emit_rex_64(dst);
1688 emit(0xF7);
1689 emit_modrm(0x3, dst);
1690}
1691
1692
1693void Assembler::negl(Register dst) {
1694 EnsureSpace ensure_space(this);
1695 last_pc_ = pc_;
1696 emit_optional_rex_32(dst);
1697 emit(0xF7);
1698 emit_modrm(0x3, dst);
1699}
1700
1701
1702void Assembler::neg(const Operand& dst) {
1703 EnsureSpace ensure_space(this);
1704 last_pc_ = pc_;
1705 emit_rex_64(dst);
1706 emit(0xF7);
1707 emit_operand(3, dst);
1708}
1709
1710
1711void Assembler::nop() {
1712 EnsureSpace ensure_space(this);
1713 last_pc_ = pc_;
1714 emit(0x90);
1715}
1716
1717
1718void Assembler::not_(Register dst) {
1719 EnsureSpace ensure_space(this);
1720 last_pc_ = pc_;
1721 emit_rex_64(dst);
1722 emit(0xF7);
1723 emit_modrm(0x2, dst);
1724}
1725
1726
1727void Assembler::not_(const Operand& dst) {
1728 EnsureSpace ensure_space(this);
1729 last_pc_ = pc_;
1730 emit_rex_64(dst);
1731 emit(0xF7);
1732 emit_operand(2, dst);
1733}
1734
1735
Steve Block6ded16b2010-05-10 14:33:55 +01001736void Assembler::notl(Register dst) {
1737 EnsureSpace ensure_space(this);
1738 last_pc_ = pc_;
1739 emit_optional_rex_32(dst);
1740 emit(0xF7);
1741 emit_modrm(0x2, dst);
1742}
1743
1744
Steve Blocka7e24c12009-10-30 11:49:00 +00001745void Assembler::nop(int n) {
1746 // The recommended muti-byte sequences of NOP instructions from the Intel 64
1747 // and IA-32 Architectures Software Developer's Manual.
1748 //
1749 // Length Assembly Byte Sequence
1750 // 2 bytes 66 NOP 66 90H
1751 // 3 bytes NOP DWORD ptr [EAX] 0F 1F 00H
1752 // 4 bytes NOP DWORD ptr [EAX + 00H] 0F 1F 40 00H
1753 // 5 bytes NOP DWORD ptr [EAX + EAX*1 + 00H] 0F 1F 44 00 00H
1754 // 6 bytes 66 NOP DWORD ptr [EAX + EAX*1 + 00H] 66 0F 1F 44 00 00H
1755 // 7 bytes NOP DWORD ptr [EAX + 00000000H] 0F 1F 80 00 00 00 00H
1756 // 8 bytes NOP DWORD ptr [EAX + EAX*1 + 00000000H] 0F 1F 84 00 00 00 00 00H
1757 // 9 bytes 66 NOP DWORD ptr [EAX + EAX*1 + 66 0F 1F 84 00 00 00 00
1758 // 00000000H] 00H
1759
1760 ASSERT(1 <= n);
1761 ASSERT(n <= 9);
1762 EnsureSpace ensure_space(this);
1763 last_pc_ = pc_;
1764 switch (n) {
1765 case 1:
1766 emit(0x90);
1767 return;
1768 case 2:
1769 emit(0x66);
1770 emit(0x90);
1771 return;
1772 case 3:
1773 emit(0x0f);
1774 emit(0x1f);
1775 emit(0x00);
1776 return;
1777 case 4:
1778 emit(0x0f);
1779 emit(0x1f);
1780 emit(0x40);
1781 emit(0x00);
1782 return;
1783 case 5:
1784 emit(0x0f);
1785 emit(0x1f);
1786 emit(0x44);
1787 emit(0x00);
1788 emit(0x00);
1789 return;
1790 case 6:
1791 emit(0x66);
1792 emit(0x0f);
1793 emit(0x1f);
1794 emit(0x44);
1795 emit(0x00);
1796 emit(0x00);
1797 return;
1798 case 7:
1799 emit(0x0f);
1800 emit(0x1f);
1801 emit(0x80);
1802 emit(0x00);
1803 emit(0x00);
1804 emit(0x00);
1805 emit(0x00);
1806 return;
1807 case 8:
1808 emit(0x0f);
1809 emit(0x1f);
1810 emit(0x84);
1811 emit(0x00);
1812 emit(0x00);
1813 emit(0x00);
1814 emit(0x00);
1815 emit(0x00);
1816 return;
1817 case 9:
1818 emit(0x66);
1819 emit(0x0f);
1820 emit(0x1f);
1821 emit(0x84);
1822 emit(0x00);
1823 emit(0x00);
1824 emit(0x00);
1825 emit(0x00);
1826 emit(0x00);
1827 return;
1828 }
1829}
1830
1831
1832void Assembler::pop(Register dst) {
1833 EnsureSpace ensure_space(this);
1834 last_pc_ = pc_;
Steve Block8defd9f2010-07-08 12:39:36 +01001835 emit_optional_rex_32(dst);
Steve Blocka7e24c12009-10-30 11:49:00 +00001836 emit(0x58 | dst.low_bits());
1837}
1838
1839
1840void Assembler::pop(const Operand& dst) {
1841 EnsureSpace ensure_space(this);
1842 last_pc_ = pc_;
Steve Block8defd9f2010-07-08 12:39:36 +01001843 emit_optional_rex_32(dst);
Steve Blocka7e24c12009-10-30 11:49:00 +00001844 emit(0x8F);
1845 emit_operand(0, dst);
1846}
1847
1848
1849void Assembler::popfq() {
1850 EnsureSpace ensure_space(this);
1851 last_pc_ = pc_;
1852 emit(0x9D);
1853}
1854
1855
1856void Assembler::push(Register src) {
1857 EnsureSpace ensure_space(this);
1858 last_pc_ = pc_;
Steve Block8defd9f2010-07-08 12:39:36 +01001859 emit_optional_rex_32(src);
Steve Blocka7e24c12009-10-30 11:49:00 +00001860 emit(0x50 | src.low_bits());
1861}
1862
1863
1864void Assembler::push(const Operand& src) {
1865 EnsureSpace ensure_space(this);
1866 last_pc_ = pc_;
Steve Block8defd9f2010-07-08 12:39:36 +01001867 emit_optional_rex_32(src);
Steve Blocka7e24c12009-10-30 11:49:00 +00001868 emit(0xFF);
1869 emit_operand(6, src);
1870}
1871
1872
1873void Assembler::push(Immediate value) {
1874 EnsureSpace ensure_space(this);
1875 last_pc_ = pc_;
1876 if (is_int8(value.value_)) {
1877 emit(0x6A);
1878 emit(value.value_); // Emit low byte of value.
1879 } else {
1880 emit(0x68);
1881 emitl(value.value_);
1882 }
1883}
1884
1885
1886void Assembler::pushfq() {
1887 EnsureSpace ensure_space(this);
1888 last_pc_ = pc_;
1889 emit(0x9C);
1890}
1891
1892
Steve Blocka7e24c12009-10-30 11:49:00 +00001893void Assembler::rdtsc() {
1894 EnsureSpace ensure_space(this);
1895 last_pc_ = pc_;
1896 emit(0x0F);
1897 emit(0x31);
1898}
1899
1900
1901void Assembler::ret(int imm16) {
1902 EnsureSpace ensure_space(this);
1903 last_pc_ = pc_;
1904 ASSERT(is_uint16(imm16));
1905 if (imm16 == 0) {
1906 emit(0xC3);
1907 } else {
1908 emit(0xC2);
1909 emit(imm16 & 0xFF);
1910 emit((imm16 >> 8) & 0xFF);
1911 }
1912}
1913
1914
1915void Assembler::setcc(Condition cc, Register reg) {
Steve Block3ce2e202009-11-05 08:53:23 +00001916 if (cc > last_condition) {
1917 movb(reg, Immediate(cc == always ? 1 : 0));
1918 return;
1919 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001920 EnsureSpace ensure_space(this);
1921 last_pc_ = pc_;
1922 ASSERT(is_uint4(cc));
1923 if (reg.code() > 3) { // Use x64 byte registers, where different.
1924 emit_rex_32(reg);
1925 }
1926 emit(0x0F);
1927 emit(0x90 | cc);
1928 emit_modrm(0x0, reg);
1929}
1930
1931
1932void Assembler::shld(Register dst, Register src) {
1933 EnsureSpace ensure_space(this);
1934 last_pc_ = pc_;
1935 emit_rex_64(src, dst);
1936 emit(0x0F);
1937 emit(0xA5);
1938 emit_modrm(src, dst);
1939}
1940
1941
1942void Assembler::shrd(Register dst, Register src) {
1943 EnsureSpace ensure_space(this);
1944 last_pc_ = pc_;
1945 emit_rex_64(src, dst);
1946 emit(0x0F);
1947 emit(0xAD);
1948 emit_modrm(src, dst);
1949}
1950
1951
1952void Assembler::xchg(Register dst, Register src) {
1953 EnsureSpace ensure_space(this);
1954 last_pc_ = pc_;
1955 if (src.is(rax) || dst.is(rax)) { // Single-byte encoding
1956 Register other = src.is(rax) ? dst : src;
1957 emit_rex_64(other);
1958 emit(0x90 | other.low_bits());
Leon Clarkef7060e22010-06-03 12:02:55 +01001959 } else if (dst.low_bits() == 4) {
1960 emit_rex_64(dst, src);
1961 emit(0x87);
1962 emit_modrm(dst, src);
Steve Blocka7e24c12009-10-30 11:49:00 +00001963 } else {
1964 emit_rex_64(src, dst);
1965 emit(0x87);
1966 emit_modrm(src, dst);
1967 }
1968}
1969
1970
1971void Assembler::store_rax(void* dst, RelocInfo::Mode mode) {
1972 EnsureSpace ensure_space(this);
1973 last_pc_ = pc_;
1974 emit(0x48); // REX.W
1975 emit(0xA3);
1976 emitq(reinterpret_cast<uintptr_t>(dst), mode);
1977}
1978
1979
1980void Assembler::store_rax(ExternalReference ref) {
1981 store_rax(ref.address(), RelocInfo::EXTERNAL_REFERENCE);
1982}
1983
1984
Steve Block3ce2e202009-11-05 08:53:23 +00001985void Assembler::testb(Register dst, Register src) {
1986 EnsureSpace ensure_space(this);
1987 last_pc_ = pc_;
Leon Clarkef7060e22010-06-03 12:02:55 +01001988 if (src.low_bits() == 4) {
1989 emit_rex_32(src, dst);
1990 emit(0x84);
1991 emit_modrm(src, dst);
1992 } else {
1993 if (dst.code() > 3 || src.code() > 3) {
1994 // Register is not one of al, bl, cl, dl. Its encoding needs REX.
1995 emit_rex_32(dst, src);
1996 }
1997 emit(0x84);
1998 emit_modrm(dst, src);
Steve Block3ce2e202009-11-05 08:53:23 +00001999 }
Steve Block3ce2e202009-11-05 08:53:23 +00002000}
2001
2002
Steve Blocka7e24c12009-10-30 11:49:00 +00002003void Assembler::testb(Register reg, Immediate mask) {
2004 ASSERT(is_int8(mask.value_) || is_uint8(mask.value_));
2005 EnsureSpace ensure_space(this);
2006 last_pc_ = pc_;
2007 if (reg.is(rax)) {
2008 emit(0xA8);
2009 emit(mask.value_); // Low byte emitted.
2010 } else {
2011 if (reg.code() > 3) {
2012 // Register is not one of al, bl, cl, dl. Its encoding needs REX.
2013 emit_rex_32(reg);
2014 }
2015 emit(0xF6);
2016 emit_modrm(0x0, reg);
2017 emit(mask.value_); // Low byte emitted.
2018 }
2019}
2020
2021
2022void Assembler::testb(const Operand& op, Immediate mask) {
2023 ASSERT(is_int8(mask.value_) || is_uint8(mask.value_));
2024 EnsureSpace ensure_space(this);
2025 last_pc_ = pc_;
2026 emit_optional_rex_32(rax, op);
2027 emit(0xF6);
2028 emit_operand(rax, op); // Operation code 0
2029 emit(mask.value_); // Low byte emitted.
2030}
2031
2032
Leon Clarkee46be812010-01-19 14:06:41 +00002033void Assembler::testb(const Operand& op, Register reg) {
2034 EnsureSpace ensure_space(this);
2035 last_pc_ = pc_;
2036 if (reg.code() > 3) {
2037 // Register is not one of al, bl, cl, dl. Its encoding needs REX.
2038 emit_rex_32(reg, op);
2039 } else {
2040 emit_optional_rex_32(reg, op);
2041 }
2042 emit(0x84);
2043 emit_operand(reg, op);
2044}
2045
2046
Steve Blocka7e24c12009-10-30 11:49:00 +00002047void Assembler::testl(Register dst, Register src) {
2048 EnsureSpace ensure_space(this);
2049 last_pc_ = pc_;
Leon Clarkef7060e22010-06-03 12:02:55 +01002050 if (src.low_bits() == 4) {
2051 emit_optional_rex_32(src, dst);
2052 emit(0x85);
2053 emit_modrm(src, dst);
2054 } else {
2055 emit_optional_rex_32(dst, src);
2056 emit(0x85);
2057 emit_modrm(dst, src);
2058 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002059}
2060
2061
2062void Assembler::testl(Register reg, Immediate mask) {
2063 // testl with a mask that fits in the low byte is exactly testb.
2064 if (is_uint8(mask.value_)) {
2065 testb(reg, mask);
2066 return;
2067 }
2068 EnsureSpace ensure_space(this);
2069 last_pc_ = pc_;
2070 if (reg.is(rax)) {
2071 emit(0xA9);
2072 emit(mask);
2073 } else {
2074 emit_optional_rex_32(rax, reg);
2075 emit(0xF7);
2076 emit_modrm(0x0, reg);
2077 emit(mask);
2078 }
2079}
2080
2081
2082void Assembler::testl(const Operand& op, Immediate mask) {
2083 // testl with a mask that fits in the low byte is exactly testb.
2084 if (is_uint8(mask.value_)) {
2085 testb(op, mask);
2086 return;
2087 }
2088 EnsureSpace ensure_space(this);
2089 last_pc_ = pc_;
2090 emit_optional_rex_32(rax, op);
2091 emit(0xF7);
2092 emit_operand(rax, op); // Operation code 0
2093 emit(mask);
2094}
2095
2096
2097void Assembler::testq(const Operand& op, Register reg) {
2098 EnsureSpace ensure_space(this);
2099 last_pc_ = pc_;
2100 emit_rex_64(reg, op);
2101 emit(0x85);
2102 emit_operand(reg, op);
2103}
2104
2105
2106void Assembler::testq(Register dst, Register src) {
2107 EnsureSpace ensure_space(this);
2108 last_pc_ = pc_;
Leon Clarkef7060e22010-06-03 12:02:55 +01002109 if (src.low_bits() == 4) {
2110 emit_rex_64(src, dst);
2111 emit(0x85);
2112 emit_modrm(src, dst);
2113 } else {
2114 emit_rex_64(dst, src);
2115 emit(0x85);
2116 emit_modrm(dst, src);
2117 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002118}
2119
2120
2121void Assembler::testq(Register dst, Immediate mask) {
2122 EnsureSpace ensure_space(this);
2123 last_pc_ = pc_;
2124 if (dst.is(rax)) {
2125 emit_rex_64();
2126 emit(0xA9);
2127 emit(mask);
2128 } else {
2129 emit_rex_64(dst);
2130 emit(0xF7);
2131 emit_modrm(0, dst);
2132 emit(mask);
2133 }
2134}
2135
2136
Andrei Popescu31002712010-02-23 13:46:05 +00002137// FPU instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00002138
2139
2140void Assembler::fld(int i) {
2141 EnsureSpace ensure_space(this);
2142 last_pc_ = pc_;
2143 emit_farith(0xD9, 0xC0, i);
2144}
2145
2146
2147void Assembler::fld1() {
2148 EnsureSpace ensure_space(this);
2149 last_pc_ = pc_;
2150 emit(0xD9);
2151 emit(0xE8);
2152}
2153
2154
2155void Assembler::fldz() {
2156 EnsureSpace ensure_space(this);
2157 last_pc_ = pc_;
2158 emit(0xD9);
2159 emit(0xEE);
2160}
2161
2162
Steve Block6ded16b2010-05-10 14:33:55 +01002163void Assembler::fldpi() {
2164 EnsureSpace ensure_space(this);
2165 last_pc_ = pc_;
2166 emit(0xD9);
2167 emit(0xEB);
2168}
2169
2170
Steve Blocka7e24c12009-10-30 11:49:00 +00002171void Assembler::fld_s(const Operand& adr) {
2172 EnsureSpace ensure_space(this);
2173 last_pc_ = pc_;
2174 emit_optional_rex_32(adr);
2175 emit(0xD9);
2176 emit_operand(0, adr);
2177}
2178
2179
2180void Assembler::fld_d(const Operand& adr) {
2181 EnsureSpace ensure_space(this);
2182 last_pc_ = pc_;
2183 emit_optional_rex_32(adr);
2184 emit(0xDD);
2185 emit_operand(0, adr);
2186}
2187
2188
2189void Assembler::fstp_s(const Operand& adr) {
2190 EnsureSpace ensure_space(this);
2191 last_pc_ = pc_;
2192 emit_optional_rex_32(adr);
2193 emit(0xD9);
2194 emit_operand(3, adr);
2195}
2196
2197
2198void Assembler::fstp_d(const Operand& adr) {
2199 EnsureSpace ensure_space(this);
2200 last_pc_ = pc_;
2201 emit_optional_rex_32(adr);
2202 emit(0xDD);
2203 emit_operand(3, adr);
2204}
2205
2206
Steve Block3ce2e202009-11-05 08:53:23 +00002207void Assembler::fstp(int index) {
2208 ASSERT(is_uint3(index));
2209 EnsureSpace ensure_space(this);
2210 last_pc_ = pc_;
2211 emit_farith(0xDD, 0xD8, index);
2212}
2213
2214
Steve Blocka7e24c12009-10-30 11:49:00 +00002215void Assembler::fild_s(const Operand& adr) {
2216 EnsureSpace ensure_space(this);
2217 last_pc_ = pc_;
2218 emit_optional_rex_32(adr);
2219 emit(0xDB);
2220 emit_operand(0, adr);
2221}
2222
2223
2224void Assembler::fild_d(const Operand& adr) {
2225 EnsureSpace ensure_space(this);
2226 last_pc_ = pc_;
2227 emit_optional_rex_32(adr);
2228 emit(0xDF);
2229 emit_operand(5, adr);
2230}
2231
2232
2233void Assembler::fistp_s(const Operand& adr) {
2234 EnsureSpace ensure_space(this);
2235 last_pc_ = pc_;
2236 emit_optional_rex_32(adr);
2237 emit(0xDB);
2238 emit_operand(3, adr);
2239}
2240
2241
2242void Assembler::fisttp_s(const Operand& adr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002243 ASSERT(CpuFeatures::IsEnabled(SSE3));
Steve Blocka7e24c12009-10-30 11:49:00 +00002244 EnsureSpace ensure_space(this);
2245 last_pc_ = pc_;
2246 emit_optional_rex_32(adr);
2247 emit(0xDB);
2248 emit_operand(1, adr);
2249}
2250
2251
Leon Clarked91b9f72010-01-27 17:25:45 +00002252void Assembler::fisttp_d(const Operand& adr) {
2253 ASSERT(CpuFeatures::IsEnabled(SSE3));
2254 EnsureSpace ensure_space(this);
2255 last_pc_ = pc_;
2256 emit_optional_rex_32(adr);
2257 emit(0xDD);
2258 emit_operand(1, adr);
2259}
2260
2261
Steve Blocka7e24c12009-10-30 11:49:00 +00002262void Assembler::fist_s(const Operand& adr) {
2263 EnsureSpace ensure_space(this);
2264 last_pc_ = pc_;
2265 emit_optional_rex_32(adr);
2266 emit(0xDB);
2267 emit_operand(2, adr);
2268}
2269
2270
2271void Assembler::fistp_d(const Operand& adr) {
2272 EnsureSpace ensure_space(this);
2273 last_pc_ = pc_;
2274 emit_optional_rex_32(adr);
2275 emit(0xDF);
Steve Block3ce2e202009-11-05 08:53:23 +00002276 emit_operand(7, adr);
Steve Blocka7e24c12009-10-30 11:49:00 +00002277}
2278
2279
2280void Assembler::fabs() {
2281 EnsureSpace ensure_space(this);
2282 last_pc_ = pc_;
2283 emit(0xD9);
2284 emit(0xE1);
2285}
2286
2287
2288void Assembler::fchs() {
2289 EnsureSpace ensure_space(this);
2290 last_pc_ = pc_;
2291 emit(0xD9);
2292 emit(0xE0);
2293}
2294
2295
2296void Assembler::fcos() {
2297 EnsureSpace ensure_space(this);
2298 last_pc_ = pc_;
2299 emit(0xD9);
2300 emit(0xFF);
2301}
2302
2303
2304void Assembler::fsin() {
2305 EnsureSpace ensure_space(this);
2306 last_pc_ = pc_;
2307 emit(0xD9);
2308 emit(0xFE);
2309}
2310
2311
2312void Assembler::fadd(int i) {
2313 EnsureSpace ensure_space(this);
2314 last_pc_ = pc_;
2315 emit_farith(0xDC, 0xC0, i);
2316}
2317
2318
2319void Assembler::fsub(int i) {
2320 EnsureSpace ensure_space(this);
2321 last_pc_ = pc_;
2322 emit_farith(0xDC, 0xE8, i);
2323}
2324
2325
2326void Assembler::fisub_s(const Operand& adr) {
2327 EnsureSpace ensure_space(this);
2328 last_pc_ = pc_;
2329 emit_optional_rex_32(adr);
2330 emit(0xDA);
2331 emit_operand(4, adr);
2332}
2333
2334
2335void Assembler::fmul(int i) {
2336 EnsureSpace ensure_space(this);
2337 last_pc_ = pc_;
2338 emit_farith(0xDC, 0xC8, i);
2339}
2340
2341
2342void Assembler::fdiv(int i) {
2343 EnsureSpace ensure_space(this);
2344 last_pc_ = pc_;
2345 emit_farith(0xDC, 0xF8, i);
2346}
2347
2348
2349void Assembler::faddp(int i) {
2350 EnsureSpace ensure_space(this);
2351 last_pc_ = pc_;
2352 emit_farith(0xDE, 0xC0, i);
2353}
2354
2355
2356void Assembler::fsubp(int i) {
2357 EnsureSpace ensure_space(this);
2358 last_pc_ = pc_;
2359 emit_farith(0xDE, 0xE8, i);
2360}
2361
2362
2363void Assembler::fsubrp(int i) {
2364 EnsureSpace ensure_space(this);
2365 last_pc_ = pc_;
2366 emit_farith(0xDE, 0xE0, i);
2367}
2368
2369
2370void Assembler::fmulp(int i) {
2371 EnsureSpace ensure_space(this);
2372 last_pc_ = pc_;
2373 emit_farith(0xDE, 0xC8, i);
2374}
2375
2376
2377void Assembler::fdivp(int i) {
2378 EnsureSpace ensure_space(this);
2379 last_pc_ = pc_;
2380 emit_farith(0xDE, 0xF8, i);
2381}
2382
2383
2384void Assembler::fprem() {
2385 EnsureSpace ensure_space(this);
2386 last_pc_ = pc_;
2387 emit(0xD9);
2388 emit(0xF8);
2389}
2390
2391
2392void Assembler::fprem1() {
2393 EnsureSpace ensure_space(this);
2394 last_pc_ = pc_;
2395 emit(0xD9);
2396 emit(0xF5);
2397}
2398
2399
2400void Assembler::fxch(int i) {
2401 EnsureSpace ensure_space(this);
2402 last_pc_ = pc_;
2403 emit_farith(0xD9, 0xC8, i);
2404}
2405
2406
2407void Assembler::fincstp() {
2408 EnsureSpace ensure_space(this);
2409 last_pc_ = pc_;
2410 emit(0xD9);
2411 emit(0xF7);
2412}
2413
2414
2415void Assembler::ffree(int i) {
2416 EnsureSpace ensure_space(this);
2417 last_pc_ = pc_;
2418 emit_farith(0xDD, 0xC0, i);
2419}
2420
2421
2422void Assembler::ftst() {
2423 EnsureSpace ensure_space(this);
2424 last_pc_ = pc_;
2425 emit(0xD9);
2426 emit(0xE4);
2427}
2428
2429
2430void Assembler::fucomp(int i) {
2431 EnsureSpace ensure_space(this);
2432 last_pc_ = pc_;
2433 emit_farith(0xDD, 0xE8, i);
2434}
2435
2436
2437void Assembler::fucompp() {
2438 EnsureSpace ensure_space(this);
2439 last_pc_ = pc_;
2440 emit(0xDA);
2441 emit(0xE9);
2442}
2443
2444
Steve Block3ce2e202009-11-05 08:53:23 +00002445void Assembler::fucomi(int i) {
2446 EnsureSpace ensure_space(this);
2447 last_pc_ = pc_;
2448 emit(0xDB);
2449 emit(0xE8 + i);
2450}
2451
2452
2453void Assembler::fucomip() {
2454 EnsureSpace ensure_space(this);
2455 last_pc_ = pc_;
2456 emit(0xDF);
2457 emit(0xE9);
2458}
2459
2460
Steve Blocka7e24c12009-10-30 11:49:00 +00002461void Assembler::fcompp() {
2462 EnsureSpace ensure_space(this);
2463 last_pc_ = pc_;
2464 emit(0xDE);
2465 emit(0xD9);
2466}
2467
2468
2469void Assembler::fnstsw_ax() {
2470 EnsureSpace ensure_space(this);
2471 last_pc_ = pc_;
2472 emit(0xDF);
2473 emit(0xE0);
2474}
2475
2476
2477void Assembler::fwait() {
2478 EnsureSpace ensure_space(this);
2479 last_pc_ = pc_;
2480 emit(0x9B);
2481}
2482
2483
2484void Assembler::frndint() {
2485 EnsureSpace ensure_space(this);
2486 last_pc_ = pc_;
2487 emit(0xD9);
2488 emit(0xFC);
2489}
2490
2491
2492void Assembler::fnclex() {
2493 EnsureSpace ensure_space(this);
2494 last_pc_ = pc_;
2495 emit(0xDB);
2496 emit(0xE2);
2497}
2498
2499
2500void Assembler::sahf() {
2501 // TODO(X64): Test for presence. Not all 64-bit intel CPU's have sahf
2502 // in 64-bit mode. Test CpuID.
2503 EnsureSpace ensure_space(this);
2504 last_pc_ = pc_;
2505 emit(0x9E);
2506}
2507
2508
2509void Assembler::emit_farith(int b1, int b2, int i) {
2510 ASSERT(is_uint8(b1) && is_uint8(b2)); // wrong opcode
2511 ASSERT(is_uint3(i)); // illegal stack offset
2512 emit(b1);
2513 emit(b2 + i);
2514}
2515
Andrei Popescu31002712010-02-23 13:46:05 +00002516// SSE 2 operations.
Steve Blocka7e24c12009-10-30 11:49:00 +00002517
Steve Block6ded16b2010-05-10 14:33:55 +01002518void Assembler::movd(XMMRegister dst, Register src) {
2519 EnsureSpace ensure_space(this);
2520 last_pc_ = pc_;
2521 emit(0x66);
2522 emit_optional_rex_32(dst, src);
2523 emit(0x0F);
2524 emit(0x6E);
2525 emit_sse_operand(dst, src);
2526}
2527
2528
2529void Assembler::movd(Register dst, XMMRegister src) {
2530 EnsureSpace ensure_space(this);
2531 last_pc_ = pc_;
2532 emit(0x66);
2533 emit_optional_rex_32(dst, src);
2534 emit(0x0F);
2535 emit(0x7E);
2536 emit_sse_operand(dst, src);
2537}
2538
2539
2540void Assembler::movq(XMMRegister dst, Register src) {
2541 EnsureSpace ensure_space(this);
2542 last_pc_ = pc_;
2543 emit(0x66);
2544 emit_rex_64(dst, src);
2545 emit(0x0F);
2546 emit(0x6E);
2547 emit_sse_operand(dst, src);
2548}
2549
2550
2551void Assembler::movq(Register dst, XMMRegister src) {
2552 EnsureSpace ensure_space(this);
2553 last_pc_ = pc_;
2554 emit(0x66);
2555 emit_rex_64(dst, src);
2556 emit(0x0F);
2557 emit(0x7E);
2558 emit_sse_operand(dst, src);
2559}
2560
2561
2562void Assembler::extractps(Register dst, XMMRegister src, byte imm8) {
2563 ASSERT(is_uint2(imm8));
2564 EnsureSpace ensure_space(this);
2565 last_pc_ = pc_;
2566 emit(0x66);
2567 emit_optional_rex_32(dst, src);
2568 emit(0x0F);
2569 emit(0x3A);
2570 emit(0x17);
2571 emit_sse_operand(dst, src);
2572 emit(imm8);
2573}
2574
2575
Steve Blocka7e24c12009-10-30 11:49:00 +00002576void Assembler::movsd(const Operand& dst, XMMRegister src) {
2577 EnsureSpace ensure_space(this);
2578 last_pc_ = pc_;
2579 emit(0xF2); // double
2580 emit_optional_rex_32(src, dst);
2581 emit(0x0F);
2582 emit(0x11); // store
2583 emit_sse_operand(src, dst);
2584}
2585
2586
Steve Block3ce2e202009-11-05 08:53:23 +00002587void Assembler::movsd(XMMRegister dst, XMMRegister src) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002588 EnsureSpace ensure_space(this);
2589 last_pc_ = pc_;
2590 emit(0xF2); // double
2591 emit_optional_rex_32(dst, src);
2592 emit(0x0F);
2593 emit(0x10); // load
2594 emit_sse_operand(dst, src);
2595}
2596
2597
2598void Assembler::movsd(XMMRegister dst, const Operand& src) {
2599 EnsureSpace ensure_space(this);
2600 last_pc_ = pc_;
2601 emit(0xF2); // double
2602 emit_optional_rex_32(dst, src);
2603 emit(0x0F);
2604 emit(0x10); // load
2605 emit_sse_operand(dst, src);
2606}
2607
2608
Steve Block8defd9f2010-07-08 12:39:36 +01002609void Assembler::movss(XMMRegister dst, const Operand& src) {
2610 EnsureSpace ensure_space(this);
2611 last_pc_ = pc_;
2612 emit(0xF3); // single
2613 emit_optional_rex_32(dst, src);
2614 emit(0x0F);
2615 emit(0x10); // load
2616 emit_sse_operand(dst, src);
2617}
2618
2619
2620void Assembler::movss(const Operand& src, XMMRegister dst) {
2621 EnsureSpace ensure_space(this);
2622 last_pc_ = pc_;
2623 emit(0xF3); // single
2624 emit_optional_rex_32(dst, src);
2625 emit(0x0F);
2626 emit(0x11); // store
2627 emit_sse_operand(dst, src);
2628}
2629
2630
Steve Blocka7e24c12009-10-30 11:49:00 +00002631void Assembler::cvttss2si(Register dst, const Operand& src) {
2632 EnsureSpace ensure_space(this);
2633 last_pc_ = pc_;
2634 emit(0xF3);
2635 emit_optional_rex_32(dst, src);
2636 emit(0x0F);
2637 emit(0x2C);
2638 emit_operand(dst, src);
2639}
2640
2641
2642void Assembler::cvttsd2si(Register dst, const Operand& src) {
2643 EnsureSpace ensure_space(this);
2644 last_pc_ = pc_;
2645 emit(0xF2);
2646 emit_optional_rex_32(dst, src);
2647 emit(0x0F);
2648 emit(0x2C);
2649 emit_operand(dst, src);
2650}
2651
2652
Kristian Monsen25f61362010-05-21 11:50:48 +01002653void Assembler::cvttsd2siq(Register dst, XMMRegister src) {
2654 EnsureSpace ensure_space(this);
2655 last_pc_ = pc_;
2656 emit(0xF2);
2657 emit_rex_64(dst, src);
2658 emit(0x0F);
2659 emit(0x2C);
2660 emit_sse_operand(dst, src);
2661}
2662
2663
Steve Blocka7e24c12009-10-30 11:49:00 +00002664void Assembler::cvtlsi2sd(XMMRegister dst, const Operand& src) {
2665 EnsureSpace ensure_space(this);
2666 last_pc_ = pc_;
2667 emit(0xF2);
2668 emit_optional_rex_32(dst, src);
2669 emit(0x0F);
2670 emit(0x2A);
2671 emit_sse_operand(dst, src);
2672}
2673
2674
2675void Assembler::cvtlsi2sd(XMMRegister dst, Register src) {
2676 EnsureSpace ensure_space(this);
2677 last_pc_ = pc_;
2678 emit(0xF2);
2679 emit_optional_rex_32(dst, src);
2680 emit(0x0F);
2681 emit(0x2A);
2682 emit_sse_operand(dst, src);
2683}
2684
2685
Steve Block8defd9f2010-07-08 12:39:36 +01002686void Assembler::cvtlsi2ss(XMMRegister dst, Register src) {
2687 EnsureSpace ensure_space(this);
2688 last_pc_ = pc_;
2689 emit(0xF3);
2690 emit_optional_rex_32(dst, src);
2691 emit(0x0F);
2692 emit(0x2A);
2693 emit_sse_operand(dst, src);
2694}
2695
2696
Steve Blocka7e24c12009-10-30 11:49:00 +00002697void Assembler::cvtqsi2sd(XMMRegister dst, Register src) {
2698 EnsureSpace ensure_space(this);
2699 last_pc_ = pc_;
2700 emit(0xF2);
2701 emit_rex_64(dst, src);
2702 emit(0x0F);
2703 emit(0x2A);
2704 emit_sse_operand(dst, src);
2705}
2706
2707
Steve Block6ded16b2010-05-10 14:33:55 +01002708void Assembler::cvtss2sd(XMMRegister dst, XMMRegister src) {
2709 EnsureSpace ensure_space(this);
2710 last_pc_ = pc_;
2711 emit(0xF3);
2712 emit_optional_rex_32(dst, src);
2713 emit(0x0F);
2714 emit(0x5A);
2715 emit_sse_operand(dst, src);
2716}
2717
2718
Steve Block8defd9f2010-07-08 12:39:36 +01002719void Assembler::cvtss2sd(XMMRegister dst, const Operand& src) {
2720 EnsureSpace ensure_space(this);
2721 last_pc_ = pc_;
2722 emit(0xF3);
2723 emit_optional_rex_32(dst, src);
2724 emit(0x0F);
2725 emit(0x5A);
2726 emit_sse_operand(dst, src);
2727}
2728
2729
2730void Assembler::cvtsd2ss(XMMRegister dst, XMMRegister src) {
2731 EnsureSpace ensure_space(this);
2732 last_pc_ = pc_;
2733 emit(0xF2);
2734 emit_optional_rex_32(dst, src);
2735 emit(0x0F);
2736 emit(0x5A);
2737 emit_sse_operand(dst, src);
2738}
2739
2740
2741void Assembler::cvtsd2si(Register dst, XMMRegister src) {
2742 EnsureSpace ensure_space(this);
2743 last_pc_ = pc_;
2744 emit(0xF2);
2745 emit_optional_rex_32(dst, src);
2746 emit(0x0F);
2747 emit(0x2D);
2748 emit_sse_operand(dst, src);
2749}
2750
2751
2752void Assembler::cvtsd2siq(Register dst, XMMRegister src) {
2753 EnsureSpace ensure_space(this);
2754 last_pc_ = pc_;
2755 emit(0xF2);
2756 emit_rex_64(dst, src);
2757 emit(0x0F);
2758 emit(0x2D);
2759 emit_sse_operand(dst, src);
2760}
2761
2762
Steve Blocka7e24c12009-10-30 11:49:00 +00002763void Assembler::addsd(XMMRegister dst, XMMRegister src) {
2764 EnsureSpace ensure_space(this);
2765 last_pc_ = pc_;
2766 emit(0xF2);
2767 emit_optional_rex_32(dst, src);
2768 emit(0x0F);
2769 emit(0x58);
2770 emit_sse_operand(dst, src);
2771}
2772
2773
2774void Assembler::mulsd(XMMRegister dst, XMMRegister src) {
2775 EnsureSpace ensure_space(this);
2776 last_pc_ = pc_;
2777 emit(0xF2);
2778 emit_optional_rex_32(dst, src);
2779 emit(0x0F);
2780 emit(0x59);
2781 emit_sse_operand(dst, src);
2782}
2783
2784
2785void Assembler::subsd(XMMRegister dst, XMMRegister src) {
2786 EnsureSpace ensure_space(this);
2787 last_pc_ = pc_;
2788 emit(0xF2);
2789 emit_optional_rex_32(dst, src);
2790 emit(0x0F);
2791 emit(0x5C);
2792 emit_sse_operand(dst, src);
2793}
2794
2795
2796void Assembler::divsd(XMMRegister dst, XMMRegister src) {
2797 EnsureSpace ensure_space(this);
2798 last_pc_ = pc_;
2799 emit(0xF2);
2800 emit_optional_rex_32(dst, src);
2801 emit(0x0F);
2802 emit(0x5E);
2803 emit_sse_operand(dst, src);
2804}
2805
2806
Andrei Popescu402d9372010-02-26 13:31:12 +00002807void Assembler::xorpd(XMMRegister dst, XMMRegister src) {
2808 EnsureSpace ensure_space(this);
2809 last_pc_ = pc_;
2810 emit(0x66);
2811 emit_optional_rex_32(dst, src);
Steve Block6ded16b2010-05-10 14:33:55 +01002812 emit(0x0F);
Andrei Popescu402d9372010-02-26 13:31:12 +00002813 emit(0x57);
2814 emit_sse_operand(dst, src);
2815}
2816
2817
Steve Block6ded16b2010-05-10 14:33:55 +01002818void Assembler::sqrtsd(XMMRegister dst, XMMRegister src) {
2819 EnsureSpace ensure_space(this);
2820 last_pc_ = pc_;
2821 emit(0xF2);
2822 emit_optional_rex_32(dst, src);
2823 emit(0x0F);
2824 emit(0x51);
2825 emit_sse_operand(dst, src);
2826}
2827
2828
Andrei Popescu402d9372010-02-26 13:31:12 +00002829void Assembler::ucomisd(XMMRegister dst, XMMRegister src) {
2830 EnsureSpace ensure_space(this);
2831 last_pc_ = pc_;
2832 emit(0x66);
2833 emit_optional_rex_32(dst, src);
2834 emit(0x0f);
2835 emit(0x2e);
2836 emit_sse_operand(dst, src);
2837}
2838
Steve Blocka7e24c12009-10-30 11:49:00 +00002839
Steve Block8defd9f2010-07-08 12:39:36 +01002840void Assembler::ucomisd(XMMRegister dst, const Operand& src) {
2841 EnsureSpace ensure_space(this);
2842 last_pc_ = pc_;
2843 emit(0x66);
2844 emit_optional_rex_32(dst, src);
2845 emit(0x0f);
2846 emit(0x2e);
2847 emit_sse_operand(dst, src);
2848}
2849
2850
2851
Steve Blocka7e24c12009-10-30 11:49:00 +00002852void Assembler::emit_sse_operand(XMMRegister reg, const Operand& adr) {
2853 Register ireg = { reg.code() };
2854 emit_operand(ireg, adr);
2855}
2856
2857
2858void Assembler::emit_sse_operand(XMMRegister dst, XMMRegister src) {
2859 emit(0xC0 | (dst.low_bits() << 3) | src.low_bits());
2860}
2861
2862void Assembler::emit_sse_operand(XMMRegister dst, Register src) {
2863 emit(0xC0 | (dst.low_bits() << 3) | src.low_bits());
2864}
2865
Steve Block6ded16b2010-05-10 14:33:55 +01002866void Assembler::emit_sse_operand(Register dst, XMMRegister src) {
2867 emit(0xC0 | (dst.low_bits() << 3) | src.low_bits());
2868}
2869
Steve Blocka7e24c12009-10-30 11:49:00 +00002870
Andrei Popescu31002712010-02-23 13:46:05 +00002871// Relocation information implementations.
Steve Blocka7e24c12009-10-30 11:49:00 +00002872
2873void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
2874 ASSERT(rmode != RelocInfo::NONE);
2875 // Don't record external references unless the heap will be serialized.
2876 if (rmode == RelocInfo::EXTERNAL_REFERENCE &&
2877 !Serializer::enabled() &&
2878 !FLAG_debug_code) {
2879 return;
2880 }
2881 RelocInfo rinfo(pc_, rmode, data);
2882 reloc_info_writer.Write(&rinfo);
2883}
2884
2885void Assembler::RecordJSReturn() {
2886 WriteRecordedPositions();
2887 EnsureSpace ensure_space(this);
2888 RecordRelocInfo(RelocInfo::JS_RETURN);
2889}
2890
2891
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002892void Assembler::RecordDebugBreakSlot() {
2893 WriteRecordedPositions();
2894 EnsureSpace ensure_space(this);
2895 RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
2896}
2897
2898
Steve Blocka7e24c12009-10-30 11:49:00 +00002899void Assembler::RecordComment(const char* msg) {
2900 if (FLAG_debug_code) {
2901 EnsureSpace ensure_space(this);
2902 RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg));
2903 }
2904}
2905
2906
2907void Assembler::RecordPosition(int pos) {
2908 ASSERT(pos != RelocInfo::kNoPosition);
2909 ASSERT(pos >= 0);
2910 current_position_ = pos;
2911}
2912
2913
2914void Assembler::RecordStatementPosition(int pos) {
2915 ASSERT(pos != RelocInfo::kNoPosition);
2916 ASSERT(pos >= 0);
2917 current_statement_position_ = pos;
2918}
2919
2920
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002921bool Assembler::WriteRecordedPositions() {
2922 bool written = false;
2923
Steve Blocka7e24c12009-10-30 11:49:00 +00002924 // Write the statement position if it is different from what was written last
2925 // time.
2926 if (current_statement_position_ != written_statement_position_) {
2927 EnsureSpace ensure_space(this);
2928 RecordRelocInfo(RelocInfo::STATEMENT_POSITION, current_statement_position_);
2929 written_statement_position_ = current_statement_position_;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002930 written = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00002931 }
2932
2933 // Write the position if it is different from what was written last time and
2934 // also different from the written statement position.
2935 if (current_position_ != written_position_ &&
2936 current_position_ != written_statement_position_) {
2937 EnsureSpace ensure_space(this);
2938 RecordRelocInfo(RelocInfo::POSITION, current_position_);
2939 written_position_ = current_position_;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002940 written = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00002941 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002942
2943 // Return whether something was written.
2944 return written;
Steve Blocka7e24c12009-10-30 11:49:00 +00002945}
2946
2947
Steve Block3ce2e202009-11-05 08:53:23 +00002948const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask |
2949 1 << RelocInfo::INTERNAL_REFERENCE |
2950 1 << RelocInfo::JS_RETURN;
Steve Blocka7e24c12009-10-30 11:49:00 +00002951
Leon Clarkef7060e22010-06-03 12:02:55 +01002952
2953bool RelocInfo::IsCodedSpecially() {
2954 // The deserializer needs to know whether a pointer is specially coded. Being
2955 // specially coded on x64 means that it is a relative 32 bit address, as used
2956 // by branch instructions.
2957 return (1 << rmode_) & kApplyMask;
2958}
2959
2960
2961
Steve Blocka7e24c12009-10-30 11:49:00 +00002962} } // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01002963
2964#endif // V8_TARGET_ARCH_X64