blob: e665385c69be6e667b6d58212bdbbc58657ef159 [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));
379 while ((pc_offset() & (m - 1)) != 0) {
380 nop();
381 }
382}
383
384
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100385void Assembler::CodeTargetAlign() {
386 Align(16); // Preferred alignment of jump targets on x64.
387}
388
389
Steve Blocka7e24c12009-10-30 11:49:00 +0000390void Assembler::bind_to(Label* L, int pos) {
391 ASSERT(!L->is_bound()); // Label may only be bound once.
392 last_pc_ = NULL;
393 ASSERT(0 <= pos && pos <= pc_offset()); // Position must be valid.
394 if (L->is_linked()) {
395 int current = L->pos();
396 int next = long_at(current);
397 while (next != current) {
Andrei Popescu31002712010-02-23 13:46:05 +0000398 // Relative address, relative to point after address.
Steve Blocka7e24c12009-10-30 11:49:00 +0000399 int imm32 = pos - (current + sizeof(int32_t));
400 long_at_put(current, imm32);
401 current = next;
402 next = long_at(next);
403 }
404 // Fix up last fixup on linked list.
405 int last_imm32 = pos - (current + sizeof(int32_t));
406 long_at_put(current, last_imm32);
407 }
408 L->bind_to(pos);
409}
410
411
412void Assembler::bind(Label* L) {
413 bind_to(L, pc_offset());
414}
415
416
417void Assembler::GrowBuffer() {
Andrei Popescu31002712010-02-23 13:46:05 +0000418 ASSERT(buffer_overflow());
Steve Blocka7e24c12009-10-30 11:49:00 +0000419 if (!own_buffer_) FATAL("external code buffer is too small");
420
Andrei Popescu31002712010-02-23 13:46:05 +0000421 // Compute new buffer size.
Steve Blocka7e24c12009-10-30 11:49:00 +0000422 CodeDesc desc; // the new buffer
423 if (buffer_size_ < 4*KB) {
424 desc.buffer_size = 4*KB;
425 } else {
426 desc.buffer_size = 2*buffer_size_;
427 }
428 // Some internal data structures overflow for very large buffers,
429 // they must ensure that kMaximalBufferSize is not too large.
430 if ((desc.buffer_size > kMaximalBufferSize) ||
Steve Block3ce2e202009-11-05 08:53:23 +0000431 (desc.buffer_size > Heap::MaxOldGenerationSize())) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000432 V8::FatalProcessOutOfMemory("Assembler::GrowBuffer");
433 }
434
Andrei Popescu31002712010-02-23 13:46:05 +0000435 // Setup new buffer.
Steve Blocka7e24c12009-10-30 11:49:00 +0000436 desc.buffer = NewArray<byte>(desc.buffer_size);
437 desc.instr_size = pc_offset();
Steve Blockd0582a62009-12-15 09:54:21 +0000438 desc.reloc_size =
439 static_cast<int>((buffer_ + buffer_size_) - (reloc_info_writer.pos()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000440
441 // Clear the buffer in debug mode. Use 'int3' instructions to make
442 // sure to get into problems if we ever run uninitialized code.
443#ifdef DEBUG
444 memset(desc.buffer, 0xCC, desc.buffer_size);
445#endif
446
Andrei Popescu31002712010-02-23 13:46:05 +0000447 // Copy the data.
Steve Blocka7e24c12009-10-30 11:49:00 +0000448 intptr_t pc_delta = desc.buffer - buffer_;
449 intptr_t rc_delta = (desc.buffer + desc.buffer_size) -
450 (buffer_ + buffer_size_);
451 memmove(desc.buffer, buffer_, desc.instr_size);
452 memmove(rc_delta + reloc_info_writer.pos(),
453 reloc_info_writer.pos(), desc.reloc_size);
454
Andrei Popescu31002712010-02-23 13:46:05 +0000455 // Switch buffers.
Steve Blocka7e24c12009-10-30 11:49:00 +0000456 if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) {
457 spare_buffer_ = buffer_;
458 } else {
459 DeleteArray(buffer_);
460 }
461 buffer_ = desc.buffer;
462 buffer_size_ = desc.buffer_size;
463 pc_ += pc_delta;
464 if (last_pc_ != NULL) {
465 last_pc_ += pc_delta;
466 }
467 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
468 reloc_info_writer.last_pc() + pc_delta);
469
Andrei Popescu31002712010-02-23 13:46:05 +0000470 // Relocate runtime entries.
Steve Blocka7e24c12009-10-30 11:49:00 +0000471 for (RelocIterator it(desc); !it.done(); it.next()) {
472 RelocInfo::Mode rmode = it.rinfo()->rmode();
473 if (rmode == RelocInfo::INTERNAL_REFERENCE) {
474 intptr_t* p = reinterpret_cast<intptr_t*>(it.rinfo()->pc());
475 if (*p != 0) { // 0 means uninitialized.
476 *p += pc_delta;
477 }
478 }
479 }
480
481 ASSERT(!buffer_overflow());
482}
483
484
485void Assembler::emit_operand(int code, const Operand& adr) {
486 ASSERT(is_uint3(code));
487 const unsigned length = adr.len_;
488 ASSERT(length > 0);
489
490 // Emit updated ModR/M byte containing the given register.
491 ASSERT((adr.buf_[0] & 0x38) == 0);
492 pc_[0] = adr.buf_[0] | code << 3;
493
494 // Emit the rest of the encoded operand.
495 for (unsigned i = 1; i < length; i++) pc_[i] = adr.buf_[i];
496 pc_ += length;
497}
498
499
Andrei Popescu31002712010-02-23 13:46:05 +0000500// Assembler Instruction implementations.
Steve Blocka7e24c12009-10-30 11:49:00 +0000501
502void Assembler::arithmetic_op(byte opcode, Register reg, const Operand& op) {
503 EnsureSpace ensure_space(this);
504 last_pc_ = pc_;
505 emit_rex_64(reg, op);
506 emit(opcode);
507 emit_operand(reg, op);
508}
509
510
511void Assembler::arithmetic_op(byte opcode, Register reg, Register rm_reg) {
512 EnsureSpace ensure_space(this);
513 last_pc_ = pc_;
Leon Clarkef7060e22010-06-03 12:02:55 +0100514 ASSERT((opcode & 0xC6) == 2);
515 if (rm_reg.low_bits() == 4) { // Forces SIB byte.
516 // Swap reg and rm_reg and change opcode operand order.
517 emit_rex_64(rm_reg, reg);
518 emit(opcode ^ 0x02);
519 emit_modrm(rm_reg, reg);
520 } else {
521 emit_rex_64(reg, rm_reg);
522 emit(opcode);
523 emit_modrm(reg, rm_reg);
524 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000525}
526
527
528void Assembler::arithmetic_op_16(byte opcode, Register reg, Register rm_reg) {
529 EnsureSpace ensure_space(this);
530 last_pc_ = pc_;
Leon Clarkef7060e22010-06-03 12:02:55 +0100531 ASSERT((opcode & 0xC6) == 2);
532 if (rm_reg.low_bits() == 4) { // Forces SIB byte.
533 // Swap reg and rm_reg and change opcode operand order.
534 emit(0x66);
535 emit_optional_rex_32(rm_reg, reg);
536 emit(opcode ^ 0x02);
537 emit_modrm(rm_reg, reg);
538 } else {
539 emit(0x66);
540 emit_optional_rex_32(reg, rm_reg);
541 emit(opcode);
542 emit_modrm(reg, rm_reg);
543 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000544}
545
546
547void Assembler::arithmetic_op_16(byte opcode,
548 Register reg,
549 const Operand& rm_reg) {
550 EnsureSpace ensure_space(this);
551 last_pc_ = pc_;
552 emit(0x66);
553 emit_optional_rex_32(reg, rm_reg);
554 emit(opcode);
555 emit_operand(reg, rm_reg);
556}
557
558
559void Assembler::arithmetic_op_32(byte opcode, Register reg, Register rm_reg) {
560 EnsureSpace ensure_space(this);
561 last_pc_ = pc_;
Leon Clarkef7060e22010-06-03 12:02:55 +0100562 ASSERT((opcode & 0xC6) == 2);
563 if (rm_reg.low_bits() == 4) { // Forces SIB byte.
564 // Swap reg and rm_reg and change opcode operand order.
565 emit_optional_rex_32(rm_reg, reg);
566 emit(opcode ^ 0x02); // E.g. 0x03 -> 0x01 for ADD.
567 emit_modrm(rm_reg, reg);
568 } else {
569 emit_optional_rex_32(reg, rm_reg);
570 emit(opcode);
571 emit_modrm(reg, rm_reg);
572 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000573}
574
575
576void Assembler::arithmetic_op_32(byte opcode,
577 Register reg,
578 const Operand& rm_reg) {
579 EnsureSpace ensure_space(this);
580 last_pc_ = pc_;
581 emit_optional_rex_32(reg, rm_reg);
582 emit(opcode);
583 emit_operand(reg, rm_reg);
584}
585
586
587void Assembler::immediate_arithmetic_op(byte subcode,
588 Register dst,
589 Immediate src) {
590 EnsureSpace ensure_space(this);
591 last_pc_ = pc_;
592 emit_rex_64(dst);
593 if (is_int8(src.value_)) {
594 emit(0x83);
595 emit_modrm(subcode, dst);
596 emit(src.value_);
597 } else if (dst.is(rax)) {
598 emit(0x05 | (subcode << 3));
599 emitl(src.value_);
600 } else {
601 emit(0x81);
602 emit_modrm(subcode, dst);
603 emitl(src.value_);
604 }
605}
606
607void Assembler::immediate_arithmetic_op(byte subcode,
608 const Operand& dst,
609 Immediate src) {
610 EnsureSpace ensure_space(this);
611 last_pc_ = pc_;
612 emit_rex_64(dst);
613 if (is_int8(src.value_)) {
614 emit(0x83);
615 emit_operand(subcode, dst);
616 emit(src.value_);
617 } else {
618 emit(0x81);
619 emit_operand(subcode, dst);
620 emitl(src.value_);
621 }
622}
623
624
625void Assembler::immediate_arithmetic_op_16(byte subcode,
626 Register dst,
627 Immediate src) {
628 EnsureSpace ensure_space(this);
629 last_pc_ = pc_;
630 emit(0x66); // Operand size override prefix.
631 emit_optional_rex_32(dst);
632 if (is_int8(src.value_)) {
633 emit(0x83);
634 emit_modrm(subcode, dst);
635 emit(src.value_);
636 } else if (dst.is(rax)) {
637 emit(0x05 | (subcode << 3));
Steve Block3ce2e202009-11-05 08:53:23 +0000638 emitw(src.value_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000639 } else {
640 emit(0x81);
641 emit_modrm(subcode, dst);
Steve Block3ce2e202009-11-05 08:53:23 +0000642 emitw(src.value_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000643 }
644}
645
646
647void Assembler::immediate_arithmetic_op_16(byte subcode,
648 const Operand& dst,
649 Immediate src) {
650 EnsureSpace ensure_space(this);
651 last_pc_ = pc_;
652 emit(0x66); // Operand size override prefix.
653 emit_optional_rex_32(dst);
654 if (is_int8(src.value_)) {
655 emit(0x83);
656 emit_operand(subcode, dst);
657 emit(src.value_);
658 } else {
659 emit(0x81);
660 emit_operand(subcode, dst);
Steve Block3ce2e202009-11-05 08:53:23 +0000661 emitw(src.value_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000662 }
663}
664
665
666void Assembler::immediate_arithmetic_op_32(byte subcode,
667 Register dst,
668 Immediate src) {
669 EnsureSpace ensure_space(this);
670 last_pc_ = pc_;
671 emit_optional_rex_32(dst);
672 if (is_int8(src.value_)) {
673 emit(0x83);
674 emit_modrm(subcode, dst);
675 emit(src.value_);
676 } else if (dst.is(rax)) {
677 emit(0x05 | (subcode << 3));
678 emitl(src.value_);
679 } else {
680 emit(0x81);
681 emit_modrm(subcode, dst);
682 emitl(src.value_);
683 }
684}
685
686
687void Assembler::immediate_arithmetic_op_32(byte subcode,
688 const Operand& dst,
689 Immediate src) {
690 EnsureSpace ensure_space(this);
691 last_pc_ = pc_;
692 emit_optional_rex_32(dst);
693 if (is_int8(src.value_)) {
694 emit(0x83);
695 emit_operand(subcode, dst);
696 emit(src.value_);
697 } else {
698 emit(0x81);
699 emit_operand(subcode, dst);
700 emitl(src.value_);
701 }
702}
703
704
705void Assembler::immediate_arithmetic_op_8(byte subcode,
706 const Operand& dst,
707 Immediate src) {
708 EnsureSpace ensure_space(this);
709 last_pc_ = pc_;
710 emit_optional_rex_32(dst);
711 ASSERT(is_int8(src.value_) || is_uint8(src.value_));
712 emit(0x80);
713 emit_operand(subcode, dst);
714 emit(src.value_);
715}
716
717
718void Assembler::immediate_arithmetic_op_8(byte subcode,
719 Register dst,
720 Immediate src) {
721 EnsureSpace ensure_space(this);
722 last_pc_ = pc_;
723 if (dst.code() > 3) {
724 // Use 64-bit mode byte registers.
725 emit_rex_64(dst);
726 }
727 ASSERT(is_int8(src.value_) || is_uint8(src.value_));
728 emit(0x80);
729 emit_modrm(subcode, dst);
730 emit(src.value_);
731}
732
733
734void Assembler::shift(Register dst, Immediate shift_amount, int subcode) {
735 EnsureSpace ensure_space(this);
736 last_pc_ = pc_;
737 ASSERT(is_uint6(shift_amount.value_)); // illegal shift count
738 if (shift_amount.value_ == 1) {
739 emit_rex_64(dst);
740 emit(0xD1);
741 emit_modrm(subcode, dst);
742 } else {
743 emit_rex_64(dst);
744 emit(0xC1);
745 emit_modrm(subcode, dst);
746 emit(shift_amount.value_);
747 }
748}
749
750
751void Assembler::shift(Register dst, int subcode) {
752 EnsureSpace ensure_space(this);
753 last_pc_ = pc_;
754 emit_rex_64(dst);
755 emit(0xD3);
756 emit_modrm(subcode, dst);
757}
758
759
760void Assembler::shift_32(Register dst, int subcode) {
761 EnsureSpace ensure_space(this);
762 last_pc_ = pc_;
763 emit_optional_rex_32(dst);
764 emit(0xD3);
765 emit_modrm(subcode, dst);
766}
767
768
769void Assembler::shift_32(Register dst, Immediate shift_amount, int subcode) {
770 EnsureSpace ensure_space(this);
771 last_pc_ = pc_;
Steve Block3ce2e202009-11-05 08:53:23 +0000772 ASSERT(is_uint5(shift_amount.value_)); // illegal shift count
Steve Blocka7e24c12009-10-30 11:49:00 +0000773 if (shift_amount.value_ == 1) {
774 emit_optional_rex_32(dst);
775 emit(0xD1);
776 emit_modrm(subcode, dst);
777 } else {
778 emit_optional_rex_32(dst);
779 emit(0xC1);
780 emit_modrm(subcode, dst);
781 emit(shift_amount.value_);
782 }
783}
784
785
786void Assembler::bt(const Operand& dst, Register src) {
787 EnsureSpace ensure_space(this);
788 last_pc_ = pc_;
789 emit_rex_64(src, dst);
790 emit(0x0F);
791 emit(0xA3);
792 emit_operand(src, dst);
793}
794
795
796void Assembler::bts(const Operand& dst, Register src) {
797 EnsureSpace ensure_space(this);
798 last_pc_ = pc_;
799 emit_rex_64(src, dst);
800 emit(0x0F);
801 emit(0xAB);
802 emit_operand(src, dst);
803}
804
805
806void Assembler::call(Label* L) {
807 EnsureSpace ensure_space(this);
808 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000809 // 1110 1000 #32-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +0000810 emit(0xE8);
811 if (L->is_bound()) {
812 int offset = L->pos() - pc_offset() - sizeof(int32_t);
813 ASSERT(offset <= 0);
814 emitl(offset);
815 } else if (L->is_linked()) {
816 emitl(L->pos());
817 L->link_to(pc_offset() - sizeof(int32_t));
818 } else {
819 ASSERT(L->is_unused());
820 int32_t current = pc_offset();
821 emitl(current);
822 L->link_to(current);
823 }
824}
825
826
Steve Block3ce2e202009-11-05 08:53:23 +0000827void Assembler::call(Handle<Code> target, RelocInfo::Mode rmode) {
828 EnsureSpace ensure_space(this);
829 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000830 // 1110 1000 #32-bit disp.
Steve Block3ce2e202009-11-05 08:53:23 +0000831 emit(0xE8);
832 emit_code_target(target, rmode);
833}
834
835
Steve Blocka7e24c12009-10-30 11:49:00 +0000836void Assembler::call(Register adr) {
837 EnsureSpace ensure_space(this);
838 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000839 // Opcode: FF /2 r64.
Steve Blocka7e24c12009-10-30 11:49:00 +0000840 if (adr.high_bit()) {
841 emit_rex_64(adr);
842 }
843 emit(0xFF);
844 emit_modrm(0x2, adr);
845}
846
847
848void Assembler::call(const Operand& op) {
849 EnsureSpace ensure_space(this);
850 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000851 // Opcode: FF /2 m64.
Steve Blocka7e24c12009-10-30 11:49:00 +0000852 emit_rex_64(op);
853 emit(0xFF);
854 emit_operand(2, op);
855}
856
857
Steve Block3ce2e202009-11-05 08:53:23 +0000858void Assembler::clc() {
859 EnsureSpace ensure_space(this);
860 last_pc_ = pc_;
861 emit(0xF8);
862}
863
Steve Blocka7e24c12009-10-30 11:49:00 +0000864void Assembler::cdq() {
865 EnsureSpace ensure_space(this);
866 last_pc_ = pc_;
867 emit(0x99);
868}
869
870
871void Assembler::cmovq(Condition cc, Register dst, Register src) {
Steve Block3ce2e202009-11-05 08:53:23 +0000872 if (cc == always) {
873 movq(dst, src);
874 } else if (cc == never) {
875 return;
876 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000877 // No need to check CpuInfo for CMOV support, it's a required part of the
878 // 64-bit architecture.
879 ASSERT(cc >= 0); // Use mov for unconditional moves.
880 EnsureSpace ensure_space(this);
881 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000882 // Opcode: REX.W 0f 40 + cc /r.
Steve Blocka7e24c12009-10-30 11:49:00 +0000883 emit_rex_64(dst, src);
884 emit(0x0f);
885 emit(0x40 + cc);
886 emit_modrm(dst, src);
887}
888
889
890void Assembler::cmovq(Condition cc, Register dst, const Operand& src) {
Steve Block3ce2e202009-11-05 08:53:23 +0000891 if (cc == always) {
892 movq(dst, src);
893 } else if (cc == never) {
894 return;
895 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000896 ASSERT(cc >= 0);
897 EnsureSpace ensure_space(this);
898 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000899 // Opcode: REX.W 0f 40 + cc /r.
Steve Blocka7e24c12009-10-30 11:49:00 +0000900 emit_rex_64(dst, src);
901 emit(0x0f);
902 emit(0x40 + cc);
903 emit_operand(dst, src);
904}
905
906
907void Assembler::cmovl(Condition cc, Register dst, Register src) {
Steve Block3ce2e202009-11-05 08:53:23 +0000908 if (cc == always) {
909 movl(dst, src);
910 } else if (cc == never) {
911 return;
912 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000913 ASSERT(cc >= 0);
914 EnsureSpace ensure_space(this);
915 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000916 // Opcode: 0f 40 + cc /r.
Steve Blocka7e24c12009-10-30 11:49:00 +0000917 emit_optional_rex_32(dst, src);
918 emit(0x0f);
919 emit(0x40 + cc);
920 emit_modrm(dst, src);
921}
922
923
924void Assembler::cmovl(Condition cc, Register dst, const Operand& src) {
Steve Block3ce2e202009-11-05 08:53:23 +0000925 if (cc == always) {
926 movl(dst, src);
927 } else if (cc == never) {
928 return;
929 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000930 ASSERT(cc >= 0);
931 EnsureSpace ensure_space(this);
932 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +0000933 // Opcode: 0f 40 + cc /r.
Steve Blocka7e24c12009-10-30 11:49:00 +0000934 emit_optional_rex_32(dst, src);
935 emit(0x0f);
936 emit(0x40 + cc);
937 emit_operand(dst, src);
938}
939
940
941void Assembler::cmpb_al(Immediate imm8) {
942 ASSERT(is_int8(imm8.value_) || is_uint8(imm8.value_));
943 EnsureSpace ensure_space(this);
944 last_pc_ = pc_;
945 emit(0x3c);
946 emit(imm8.value_);
947}
948
949
950void Assembler::cpuid() {
Steve Blockd0582a62009-12-15 09:54:21 +0000951 ASSERT(CpuFeatures::IsEnabled(CPUID));
Steve Blocka7e24c12009-10-30 11:49:00 +0000952 EnsureSpace ensure_space(this);
953 last_pc_ = pc_;
954 emit(0x0F);
955 emit(0xA2);
956}
957
958
959void Assembler::cqo() {
960 EnsureSpace ensure_space(this);
961 last_pc_ = pc_;
962 emit_rex_64();
963 emit(0x99);
964}
965
966
967void Assembler::decq(Register dst) {
968 EnsureSpace ensure_space(this);
969 last_pc_ = pc_;
970 emit_rex_64(dst);
971 emit(0xFF);
972 emit_modrm(0x1, dst);
973}
974
975
976void Assembler::decq(const Operand& dst) {
977 EnsureSpace ensure_space(this);
978 last_pc_ = pc_;
979 emit_rex_64(dst);
980 emit(0xFF);
981 emit_operand(1, dst);
982}
983
984
985void Assembler::decl(Register dst) {
986 EnsureSpace ensure_space(this);
987 last_pc_ = pc_;
988 emit_optional_rex_32(dst);
989 emit(0xFF);
990 emit_modrm(0x1, dst);
991}
992
993
994void Assembler::decl(const Operand& dst) {
995 EnsureSpace ensure_space(this);
996 last_pc_ = pc_;
997 emit_optional_rex_32(dst);
998 emit(0xFF);
999 emit_operand(1, dst);
1000}
1001
1002
Steve Block3ce2e202009-11-05 08:53:23 +00001003void Assembler::decb(Register dst) {
1004 EnsureSpace ensure_space(this);
1005 last_pc_ = pc_;
1006 if (dst.code() > 3) {
1007 // Register is not one of al, bl, cl, dl. Its encoding needs REX.
1008 emit_rex_32(dst);
1009 }
1010 emit(0xFE);
1011 emit_modrm(0x1, dst);
1012}
1013
1014
1015void Assembler::decb(const Operand& dst) {
1016 EnsureSpace ensure_space(this);
1017 last_pc_ = pc_;
1018 emit_optional_rex_32(dst);
1019 emit(0xFE);
1020 emit_operand(1, dst);
1021}
1022
1023
Steve Blocka7e24c12009-10-30 11:49:00 +00001024void Assembler::enter(Immediate size) {
1025 EnsureSpace ensure_space(this);
1026 last_pc_ = pc_;
1027 emit(0xC8);
1028 emitw(size.value_); // 16 bit operand, always.
1029 emit(0);
1030}
1031
1032
1033void Assembler::hlt() {
1034 EnsureSpace ensure_space(this);
1035 last_pc_ = pc_;
1036 emit(0xF4);
1037}
1038
1039
1040void Assembler::idivq(Register src) {
1041 EnsureSpace ensure_space(this);
1042 last_pc_ = pc_;
1043 emit_rex_64(src);
1044 emit(0xF7);
1045 emit_modrm(0x7, src);
1046}
1047
1048
1049void Assembler::idivl(Register src) {
1050 EnsureSpace ensure_space(this);
1051 last_pc_ = pc_;
1052 emit_optional_rex_32(src);
1053 emit(0xF7);
1054 emit_modrm(0x7, src);
1055}
1056
1057
1058void Assembler::imul(Register src) {
1059 EnsureSpace ensure_space(this);
1060 last_pc_ = pc_;
1061 emit_rex_64(src);
1062 emit(0xF7);
1063 emit_modrm(0x5, src);
1064}
1065
1066
1067void Assembler::imul(Register dst, Register src) {
1068 EnsureSpace ensure_space(this);
1069 last_pc_ = pc_;
1070 emit_rex_64(dst, src);
1071 emit(0x0F);
1072 emit(0xAF);
1073 emit_modrm(dst, src);
1074}
1075
1076
1077void Assembler::imul(Register dst, const Operand& src) {
1078 EnsureSpace ensure_space(this);
1079 last_pc_ = pc_;
1080 emit_rex_64(dst, src);
1081 emit(0x0F);
1082 emit(0xAF);
1083 emit_operand(dst, src);
1084}
1085
1086
1087void Assembler::imul(Register dst, Register src, Immediate imm) {
1088 EnsureSpace ensure_space(this);
1089 last_pc_ = pc_;
1090 emit_rex_64(dst, src);
1091 if (is_int8(imm.value_)) {
1092 emit(0x6B);
1093 emit_modrm(dst, src);
1094 emit(imm.value_);
1095 } else {
1096 emit(0x69);
1097 emit_modrm(dst, src);
1098 emitl(imm.value_);
1099 }
1100}
1101
1102
1103void Assembler::imull(Register dst, Register src) {
1104 EnsureSpace ensure_space(this);
1105 last_pc_ = pc_;
1106 emit_optional_rex_32(dst, src);
1107 emit(0x0F);
1108 emit(0xAF);
1109 emit_modrm(dst, src);
1110}
1111
1112
Steve Block6ded16b2010-05-10 14:33:55 +01001113void Assembler::imull(Register dst, Register src, Immediate imm) {
1114 EnsureSpace ensure_space(this);
1115 last_pc_ = pc_;
1116 emit_optional_rex_32(dst, src);
1117 if (is_int8(imm.value_)) {
1118 emit(0x6B);
1119 emit_modrm(dst, src);
1120 emit(imm.value_);
1121 } else {
1122 emit(0x69);
1123 emit_modrm(dst, src);
1124 emitl(imm.value_);
1125 }
1126}
1127
1128
Steve Blocka7e24c12009-10-30 11:49:00 +00001129void Assembler::incq(Register dst) {
1130 EnsureSpace ensure_space(this);
1131 last_pc_ = pc_;
1132 emit_rex_64(dst);
1133 emit(0xFF);
1134 emit_modrm(0x0, dst);
1135}
1136
1137
1138void Assembler::incq(const Operand& dst) {
1139 EnsureSpace ensure_space(this);
1140 last_pc_ = pc_;
1141 emit_rex_64(dst);
1142 emit(0xFF);
1143 emit_operand(0, dst);
1144}
1145
1146
1147void Assembler::incl(const Operand& dst) {
1148 EnsureSpace ensure_space(this);
1149 last_pc_ = pc_;
1150 emit_optional_rex_32(dst);
1151 emit(0xFF);
1152 emit_operand(0, dst);
1153}
1154
1155
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001156void Assembler::incl(Register dst) {
1157 EnsureSpace ensure_space(this);
1158 last_pc_ = pc_;
1159 emit_optional_rex_32(dst);
1160 emit(0xFF);
1161 emit_modrm(0, dst);
1162}
1163
1164
Steve Blocka7e24c12009-10-30 11:49:00 +00001165void Assembler::int3() {
1166 EnsureSpace ensure_space(this);
1167 last_pc_ = pc_;
1168 emit(0xCC);
1169}
1170
1171
1172void Assembler::j(Condition cc, Label* L) {
Steve Block3ce2e202009-11-05 08:53:23 +00001173 if (cc == always) {
1174 jmp(L);
1175 return;
1176 } else if (cc == never) {
1177 return;
1178 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001179 EnsureSpace ensure_space(this);
1180 last_pc_ = pc_;
1181 ASSERT(is_uint4(cc));
1182 if (L->is_bound()) {
1183 const int short_size = 2;
1184 const int long_size = 6;
1185 int offs = L->pos() - pc_offset();
1186 ASSERT(offs <= 0);
1187 if (is_int8(offs - short_size)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001188 // 0111 tttn #8-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001189 emit(0x70 | cc);
1190 emit((offs - short_size) & 0xFF);
1191 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00001192 // 0000 1111 1000 tttn #32-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001193 emit(0x0F);
1194 emit(0x80 | cc);
1195 emitl(offs - long_size);
1196 }
1197 } else if (L->is_linked()) {
Andrei Popescu31002712010-02-23 13:46:05 +00001198 // 0000 1111 1000 tttn #32-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001199 emit(0x0F);
1200 emit(0x80 | cc);
1201 emitl(L->pos());
1202 L->link_to(pc_offset() - sizeof(int32_t));
1203 } else {
1204 ASSERT(L->is_unused());
1205 emit(0x0F);
1206 emit(0x80 | cc);
1207 int32_t current = pc_offset();
1208 emitl(current);
1209 L->link_to(current);
1210 }
1211}
1212
1213
Steve Block3ce2e202009-11-05 08:53:23 +00001214void Assembler::j(Condition cc,
1215 Handle<Code> target,
1216 RelocInfo::Mode rmode) {
1217 EnsureSpace ensure_space(this);
1218 last_pc_ = pc_;
1219 ASSERT(is_uint4(cc));
Andrei Popescu31002712010-02-23 13:46:05 +00001220 // 0000 1111 1000 tttn #32-bit disp.
Steve Block3ce2e202009-11-05 08:53:23 +00001221 emit(0x0F);
1222 emit(0x80 | cc);
1223 emit_code_target(target, rmode);
1224}
1225
1226
Steve Blocka7e24c12009-10-30 11:49:00 +00001227void Assembler::jmp(Label* L) {
1228 EnsureSpace ensure_space(this);
1229 last_pc_ = pc_;
Steve Block6ded16b2010-05-10 14:33:55 +01001230 const int short_size = sizeof(int8_t);
1231 const int long_size = sizeof(int32_t);
Steve Blocka7e24c12009-10-30 11:49:00 +00001232 if (L->is_bound()) {
1233 int offs = L->pos() - pc_offset() - 1;
1234 ASSERT(offs <= 0);
Steve Block6ded16b2010-05-10 14:33:55 +01001235 if (is_int8(offs - short_size)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001236 // 1110 1011 #8-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001237 emit(0xEB);
Steve Block6ded16b2010-05-10 14:33:55 +01001238 emit((offs - short_size) & 0xFF);
Steve Blocka7e24c12009-10-30 11:49:00 +00001239 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00001240 // 1110 1001 #32-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001241 emit(0xE9);
Steve Block6ded16b2010-05-10 14:33:55 +01001242 emitl(offs - long_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00001243 }
1244 } else if (L->is_linked()) {
Andrei Popescu31002712010-02-23 13:46:05 +00001245 // 1110 1001 #32-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001246 emit(0xE9);
1247 emitl(L->pos());
Steve Block6ded16b2010-05-10 14:33:55 +01001248 L->link_to(pc_offset() - long_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00001249 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00001250 // 1110 1001 #32-bit disp.
Steve Blocka7e24c12009-10-30 11:49:00 +00001251 ASSERT(L->is_unused());
1252 emit(0xE9);
1253 int32_t current = pc_offset();
1254 emitl(current);
1255 L->link_to(current);
1256 }
1257}
1258
1259
Steve Block3ce2e202009-11-05 08:53:23 +00001260void Assembler::jmp(Handle<Code> target, RelocInfo::Mode rmode) {
1261 EnsureSpace ensure_space(this);
1262 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +00001263 // 1110 1001 #32-bit disp.
Steve Block3ce2e202009-11-05 08:53:23 +00001264 emit(0xE9);
1265 emit_code_target(target, rmode);
1266}
1267
1268
Steve Blocka7e24c12009-10-30 11:49:00 +00001269void Assembler::jmp(Register target) {
1270 EnsureSpace ensure_space(this);
1271 last_pc_ = pc_;
Andrei Popescu31002712010-02-23 13:46:05 +00001272 // Opcode FF/4 r64.
Steve Blocka7e24c12009-10-30 11:49:00 +00001273 if (target.high_bit()) {
1274 emit_rex_64(target);
1275 }
1276 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) {
1499 EnsureSpace ensure_space(this);
1500 last_pc_ = pc_;
1501 emit_rex_64(dst);
1502 emit(0xB8 | dst.low_bits());
1503 emitq(reinterpret_cast<uintptr_t>(ref.address()),
1504 RelocInfo::EXTERNAL_REFERENCE);
1505}
1506
1507
1508void Assembler::movq(const Operand& dst, Immediate value) {
1509 EnsureSpace ensure_space(this);
1510 last_pc_ = pc_;
1511 emit_rex_64(dst);
1512 emit(0xC7);
1513 emit_operand(0, dst);
1514 emit(value);
1515}
1516
1517
Andrei Popescu31002712010-02-23 13:46:05 +00001518// Loads the ip-relative location of the src label into the target location
1519// (as a 32-bit offset sign extended to 64-bit).
Steve Blocka7e24c12009-10-30 11:49:00 +00001520void Assembler::movl(const Operand& dst, Label* src) {
1521 EnsureSpace ensure_space(this);
1522 last_pc_ = pc_;
1523 emit_optional_rex_32(dst);
1524 emit(0xC7);
1525 emit_operand(0, dst);
1526 if (src->is_bound()) {
1527 int offset = src->pos() - pc_offset() - sizeof(int32_t);
1528 ASSERT(offset <= 0);
1529 emitl(offset);
1530 } else if (src->is_linked()) {
1531 emitl(src->pos());
1532 src->link_to(pc_offset() - sizeof(int32_t));
1533 } else {
1534 ASSERT(src->is_unused());
1535 int32_t current = pc_offset();
1536 emitl(current);
1537 src->link_to(current);
1538 }
1539}
1540
1541
1542void Assembler::movq(Register dst, Handle<Object> value, RelocInfo::Mode mode) {
1543 // If there is no relocation info, emit the value of the handle efficiently
1544 // (possibly using less that 8 bytes for the value).
1545 if (mode == RelocInfo::NONE) {
1546 // There is no possible reason to store a heap pointer without relocation
1547 // info, so it must be a smi.
1548 ASSERT(value->IsSmi());
Steve Block3ce2e202009-11-05 08:53:23 +00001549 movq(dst, reinterpret_cast<int64_t>(*value), RelocInfo::NONE);
Steve Blocka7e24c12009-10-30 11:49:00 +00001550 } else {
1551 EnsureSpace ensure_space(this);
1552 last_pc_ = pc_;
1553 ASSERT(value->IsHeapObject());
1554 ASSERT(!Heap::InNewSpace(*value));
1555 emit_rex_64(dst);
1556 emit(0xB8 | dst.low_bits());
1557 emitq(reinterpret_cast<uintptr_t>(value.location()), mode);
1558 }
1559}
1560
1561
Steve Block3ce2e202009-11-05 08:53:23 +00001562void Assembler::movsxbq(Register dst, const Operand& src) {
1563 EnsureSpace ensure_space(this);
1564 last_pc_ = pc_;
1565 emit_rex_32(dst, src);
1566 emit(0x0F);
1567 emit(0xBE);
1568 emit_operand(dst, src);
1569}
1570
1571
1572void Assembler::movsxwq(Register dst, const Operand& src) {
1573 EnsureSpace ensure_space(this);
1574 last_pc_ = pc_;
1575 emit_rex_64(dst, src);
1576 emit(0x0F);
1577 emit(0xBF);
1578 emit_operand(dst, src);
1579}
1580
1581
Steve Blocka7e24c12009-10-30 11:49:00 +00001582void Assembler::movsxlq(Register dst, Register src) {
1583 EnsureSpace ensure_space(this);
1584 last_pc_ = pc_;
1585 emit_rex_64(dst, src);
1586 emit(0x63);
1587 emit_modrm(dst, src);
1588}
1589
1590
1591void Assembler::movsxlq(Register dst, const Operand& src) {
1592 EnsureSpace ensure_space(this);
1593 last_pc_ = pc_;
1594 emit_rex_64(dst, src);
1595 emit(0x63);
1596 emit_operand(dst, src);
1597}
1598
1599
1600void Assembler::movzxbq(Register dst, const Operand& src) {
1601 EnsureSpace ensure_space(this);
1602 last_pc_ = pc_;
1603 emit_rex_64(dst, src);
1604 emit(0x0F);
1605 emit(0xB6);
1606 emit_operand(dst, src);
1607}
1608
1609
1610void Assembler::movzxbl(Register dst, const Operand& src) {
1611 EnsureSpace ensure_space(this);
1612 last_pc_ = pc_;
1613 emit_optional_rex_32(dst, src);
1614 emit(0x0F);
1615 emit(0xB6);
1616 emit_operand(dst, src);
1617}
1618
1619
Steve Block3ce2e202009-11-05 08:53:23 +00001620void Assembler::movzxwq(Register dst, const Operand& src) {
1621 EnsureSpace ensure_space(this);
1622 last_pc_ = pc_;
1623 emit_rex_64(dst, src);
1624 emit(0x0F);
1625 emit(0xB7);
1626 emit_operand(dst, src);
1627}
1628
1629
Steve Blocka7e24c12009-10-30 11:49:00 +00001630void Assembler::movzxwl(Register dst, const Operand& src) {
1631 EnsureSpace ensure_space(this);
1632 last_pc_ = pc_;
1633 emit_optional_rex_32(dst, src);
1634 emit(0x0F);
1635 emit(0xB7);
1636 emit_operand(dst, src);
1637}
1638
1639
Leon Clarked91b9f72010-01-27 17:25:45 +00001640void Assembler::repmovsb() {
1641 EnsureSpace ensure_space(this);
1642 last_pc_ = pc_;
1643 emit(0xF3);
1644 emit(0xA4);
1645}
1646
1647
1648void Assembler::repmovsw() {
1649 EnsureSpace ensure_space(this);
1650 last_pc_ = pc_;
1651 emit(0x66); // Operand size override.
1652 emit(0xF3);
1653 emit(0xA4);
1654}
1655
1656
1657void Assembler::repmovsl() {
1658 EnsureSpace ensure_space(this);
1659 last_pc_ = pc_;
1660 emit(0xF3);
1661 emit(0xA5);
1662}
1663
1664
1665void Assembler::repmovsq() {
1666 EnsureSpace ensure_space(this);
1667 last_pc_ = pc_;
1668 emit(0xF3);
1669 emit_rex_64();
1670 emit(0xA5);
1671}
1672
1673
Steve Blocka7e24c12009-10-30 11:49:00 +00001674void Assembler::mul(Register src) {
1675 EnsureSpace ensure_space(this);
1676 last_pc_ = pc_;
1677 emit_rex_64(src);
1678 emit(0xF7);
1679 emit_modrm(0x4, src);
1680}
1681
1682
1683void Assembler::neg(Register dst) {
1684 EnsureSpace ensure_space(this);
1685 last_pc_ = pc_;
1686 emit_rex_64(dst);
1687 emit(0xF7);
1688 emit_modrm(0x3, dst);
1689}
1690
1691
1692void Assembler::negl(Register dst) {
1693 EnsureSpace ensure_space(this);
1694 last_pc_ = pc_;
1695 emit_optional_rex_32(dst);
1696 emit(0xF7);
1697 emit_modrm(0x3, dst);
1698}
1699
1700
1701void Assembler::neg(const Operand& dst) {
1702 EnsureSpace ensure_space(this);
1703 last_pc_ = pc_;
1704 emit_rex_64(dst);
1705 emit(0xF7);
1706 emit_operand(3, dst);
1707}
1708
1709
1710void Assembler::nop() {
1711 EnsureSpace ensure_space(this);
1712 last_pc_ = pc_;
1713 emit(0x90);
1714}
1715
1716
1717void Assembler::not_(Register dst) {
1718 EnsureSpace ensure_space(this);
1719 last_pc_ = pc_;
1720 emit_rex_64(dst);
1721 emit(0xF7);
1722 emit_modrm(0x2, dst);
1723}
1724
1725
1726void Assembler::not_(const Operand& dst) {
1727 EnsureSpace ensure_space(this);
1728 last_pc_ = pc_;
1729 emit_rex_64(dst);
1730 emit(0xF7);
1731 emit_operand(2, dst);
1732}
1733
1734
Steve Block6ded16b2010-05-10 14:33:55 +01001735void Assembler::notl(Register dst) {
1736 EnsureSpace ensure_space(this);
1737 last_pc_ = pc_;
1738 emit_optional_rex_32(dst);
1739 emit(0xF7);
1740 emit_modrm(0x2, dst);
1741}
1742
1743
Steve Blocka7e24c12009-10-30 11:49:00 +00001744void Assembler::nop(int n) {
1745 // The recommended muti-byte sequences of NOP instructions from the Intel 64
1746 // and IA-32 Architectures Software Developer's Manual.
1747 //
1748 // Length Assembly Byte Sequence
1749 // 2 bytes 66 NOP 66 90H
1750 // 3 bytes NOP DWORD ptr [EAX] 0F 1F 00H
1751 // 4 bytes NOP DWORD ptr [EAX + 00H] 0F 1F 40 00H
1752 // 5 bytes NOP DWORD ptr [EAX + EAX*1 + 00H] 0F 1F 44 00 00H
1753 // 6 bytes 66 NOP DWORD ptr [EAX + EAX*1 + 00H] 66 0F 1F 44 00 00H
1754 // 7 bytes NOP DWORD ptr [EAX + 00000000H] 0F 1F 80 00 00 00 00H
1755 // 8 bytes NOP DWORD ptr [EAX + EAX*1 + 00000000H] 0F 1F 84 00 00 00 00 00H
1756 // 9 bytes 66 NOP DWORD ptr [EAX + EAX*1 + 66 0F 1F 84 00 00 00 00
1757 // 00000000H] 00H
1758
1759 ASSERT(1 <= n);
1760 ASSERT(n <= 9);
1761 EnsureSpace ensure_space(this);
1762 last_pc_ = pc_;
1763 switch (n) {
1764 case 1:
1765 emit(0x90);
1766 return;
1767 case 2:
1768 emit(0x66);
1769 emit(0x90);
1770 return;
1771 case 3:
1772 emit(0x0f);
1773 emit(0x1f);
1774 emit(0x00);
1775 return;
1776 case 4:
1777 emit(0x0f);
1778 emit(0x1f);
1779 emit(0x40);
1780 emit(0x00);
1781 return;
1782 case 5:
1783 emit(0x0f);
1784 emit(0x1f);
1785 emit(0x44);
1786 emit(0x00);
1787 emit(0x00);
1788 return;
1789 case 6:
1790 emit(0x66);
1791 emit(0x0f);
1792 emit(0x1f);
1793 emit(0x44);
1794 emit(0x00);
1795 emit(0x00);
1796 return;
1797 case 7:
1798 emit(0x0f);
1799 emit(0x1f);
1800 emit(0x80);
1801 emit(0x00);
1802 emit(0x00);
1803 emit(0x00);
1804 emit(0x00);
1805 return;
1806 case 8:
1807 emit(0x0f);
1808 emit(0x1f);
1809 emit(0x84);
1810 emit(0x00);
1811 emit(0x00);
1812 emit(0x00);
1813 emit(0x00);
1814 emit(0x00);
1815 return;
1816 case 9:
1817 emit(0x66);
1818 emit(0x0f);
1819 emit(0x1f);
1820 emit(0x84);
1821 emit(0x00);
1822 emit(0x00);
1823 emit(0x00);
1824 emit(0x00);
1825 emit(0x00);
1826 return;
1827 }
1828}
1829
1830
1831void Assembler::pop(Register dst) {
1832 EnsureSpace ensure_space(this);
1833 last_pc_ = pc_;
1834 if (dst.high_bit()) {
1835 emit_rex_64(dst);
1836 }
1837 emit(0x58 | dst.low_bits());
1838}
1839
1840
1841void Assembler::pop(const Operand& dst) {
1842 EnsureSpace ensure_space(this);
1843 last_pc_ = pc_;
1844 emit_rex_64(dst); // Could be omitted in some cases.
1845 emit(0x8F);
1846 emit_operand(0, dst);
1847}
1848
1849
1850void Assembler::popfq() {
1851 EnsureSpace ensure_space(this);
1852 last_pc_ = pc_;
1853 emit(0x9D);
1854}
1855
1856
1857void Assembler::push(Register src) {
1858 EnsureSpace ensure_space(this);
1859 last_pc_ = pc_;
1860 if (src.high_bit()) {
1861 emit_rex_64(src);
1862 }
1863 emit(0x50 | src.low_bits());
1864}
1865
1866
1867void Assembler::push(const Operand& src) {
1868 EnsureSpace ensure_space(this);
1869 last_pc_ = pc_;
1870 emit_rex_64(src); // Could be omitted in some cases.
1871 emit(0xFF);
1872 emit_operand(6, src);
1873}
1874
1875
1876void Assembler::push(Immediate value) {
1877 EnsureSpace ensure_space(this);
1878 last_pc_ = pc_;
1879 if (is_int8(value.value_)) {
1880 emit(0x6A);
1881 emit(value.value_); // Emit low byte of value.
1882 } else {
1883 emit(0x68);
1884 emitl(value.value_);
1885 }
1886}
1887
1888
1889void Assembler::pushfq() {
1890 EnsureSpace ensure_space(this);
1891 last_pc_ = pc_;
1892 emit(0x9C);
1893}
1894
1895
Steve Blocka7e24c12009-10-30 11:49:00 +00001896void Assembler::rdtsc() {
1897 EnsureSpace ensure_space(this);
1898 last_pc_ = pc_;
1899 emit(0x0F);
1900 emit(0x31);
1901}
1902
1903
1904void Assembler::ret(int imm16) {
1905 EnsureSpace ensure_space(this);
1906 last_pc_ = pc_;
1907 ASSERT(is_uint16(imm16));
1908 if (imm16 == 0) {
1909 emit(0xC3);
1910 } else {
1911 emit(0xC2);
1912 emit(imm16 & 0xFF);
1913 emit((imm16 >> 8) & 0xFF);
1914 }
1915}
1916
1917
1918void Assembler::setcc(Condition cc, Register reg) {
Steve Block3ce2e202009-11-05 08:53:23 +00001919 if (cc > last_condition) {
1920 movb(reg, Immediate(cc == always ? 1 : 0));
1921 return;
1922 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001923 EnsureSpace ensure_space(this);
1924 last_pc_ = pc_;
1925 ASSERT(is_uint4(cc));
1926 if (reg.code() > 3) { // Use x64 byte registers, where different.
1927 emit_rex_32(reg);
1928 }
1929 emit(0x0F);
1930 emit(0x90 | cc);
1931 emit_modrm(0x0, reg);
1932}
1933
1934
1935void Assembler::shld(Register dst, Register src) {
1936 EnsureSpace ensure_space(this);
1937 last_pc_ = pc_;
1938 emit_rex_64(src, dst);
1939 emit(0x0F);
1940 emit(0xA5);
1941 emit_modrm(src, dst);
1942}
1943
1944
1945void Assembler::shrd(Register dst, Register src) {
1946 EnsureSpace ensure_space(this);
1947 last_pc_ = pc_;
1948 emit_rex_64(src, dst);
1949 emit(0x0F);
1950 emit(0xAD);
1951 emit_modrm(src, dst);
1952}
1953
1954
1955void Assembler::xchg(Register dst, Register src) {
1956 EnsureSpace ensure_space(this);
1957 last_pc_ = pc_;
1958 if (src.is(rax) || dst.is(rax)) { // Single-byte encoding
1959 Register other = src.is(rax) ? dst : src;
1960 emit_rex_64(other);
1961 emit(0x90 | other.low_bits());
Leon Clarkef7060e22010-06-03 12:02:55 +01001962 } else if (dst.low_bits() == 4) {
1963 emit_rex_64(dst, src);
1964 emit(0x87);
1965 emit_modrm(dst, src);
Steve Blocka7e24c12009-10-30 11:49:00 +00001966 } else {
1967 emit_rex_64(src, dst);
1968 emit(0x87);
1969 emit_modrm(src, dst);
1970 }
1971}
1972
1973
1974void Assembler::store_rax(void* dst, RelocInfo::Mode mode) {
1975 EnsureSpace ensure_space(this);
1976 last_pc_ = pc_;
1977 emit(0x48); // REX.W
1978 emit(0xA3);
1979 emitq(reinterpret_cast<uintptr_t>(dst), mode);
1980}
1981
1982
1983void Assembler::store_rax(ExternalReference ref) {
1984 store_rax(ref.address(), RelocInfo::EXTERNAL_REFERENCE);
1985}
1986
1987
Steve Block3ce2e202009-11-05 08:53:23 +00001988void Assembler::testb(Register dst, Register src) {
1989 EnsureSpace ensure_space(this);
1990 last_pc_ = pc_;
Leon Clarkef7060e22010-06-03 12:02:55 +01001991 if (src.low_bits() == 4) {
1992 emit_rex_32(src, dst);
1993 emit(0x84);
1994 emit_modrm(src, dst);
1995 } else {
1996 if (dst.code() > 3 || src.code() > 3) {
1997 // Register is not one of al, bl, cl, dl. Its encoding needs REX.
1998 emit_rex_32(dst, src);
1999 }
2000 emit(0x84);
2001 emit_modrm(dst, src);
Steve Block3ce2e202009-11-05 08:53:23 +00002002 }
Steve Block3ce2e202009-11-05 08:53:23 +00002003}
2004
2005
Steve Blocka7e24c12009-10-30 11:49:00 +00002006void Assembler::testb(Register reg, Immediate mask) {
2007 ASSERT(is_int8(mask.value_) || is_uint8(mask.value_));
2008 EnsureSpace ensure_space(this);
2009 last_pc_ = pc_;
2010 if (reg.is(rax)) {
2011 emit(0xA8);
2012 emit(mask.value_); // Low byte emitted.
2013 } else {
2014 if (reg.code() > 3) {
2015 // Register is not one of al, bl, cl, dl. Its encoding needs REX.
2016 emit_rex_32(reg);
2017 }
2018 emit(0xF6);
2019 emit_modrm(0x0, reg);
2020 emit(mask.value_); // Low byte emitted.
2021 }
2022}
2023
2024
2025void Assembler::testb(const Operand& op, Immediate mask) {
2026 ASSERT(is_int8(mask.value_) || is_uint8(mask.value_));
2027 EnsureSpace ensure_space(this);
2028 last_pc_ = pc_;
2029 emit_optional_rex_32(rax, op);
2030 emit(0xF6);
2031 emit_operand(rax, op); // Operation code 0
2032 emit(mask.value_); // Low byte emitted.
2033}
2034
2035
Leon Clarkee46be812010-01-19 14:06:41 +00002036void Assembler::testb(const Operand& op, Register reg) {
2037 EnsureSpace ensure_space(this);
2038 last_pc_ = pc_;
2039 if (reg.code() > 3) {
2040 // Register is not one of al, bl, cl, dl. Its encoding needs REX.
2041 emit_rex_32(reg, op);
2042 } else {
2043 emit_optional_rex_32(reg, op);
2044 }
2045 emit(0x84);
2046 emit_operand(reg, op);
2047}
2048
2049
Steve Blocka7e24c12009-10-30 11:49:00 +00002050void Assembler::testl(Register dst, Register src) {
2051 EnsureSpace ensure_space(this);
2052 last_pc_ = pc_;
Leon Clarkef7060e22010-06-03 12:02:55 +01002053 if (src.low_bits() == 4) {
2054 emit_optional_rex_32(src, dst);
2055 emit(0x85);
2056 emit_modrm(src, dst);
2057 } else {
2058 emit_optional_rex_32(dst, src);
2059 emit(0x85);
2060 emit_modrm(dst, src);
2061 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002062}
2063
2064
2065void Assembler::testl(Register reg, Immediate mask) {
2066 // testl with a mask that fits in the low byte is exactly testb.
2067 if (is_uint8(mask.value_)) {
2068 testb(reg, mask);
2069 return;
2070 }
2071 EnsureSpace ensure_space(this);
2072 last_pc_ = pc_;
2073 if (reg.is(rax)) {
2074 emit(0xA9);
2075 emit(mask);
2076 } else {
2077 emit_optional_rex_32(rax, reg);
2078 emit(0xF7);
2079 emit_modrm(0x0, reg);
2080 emit(mask);
2081 }
2082}
2083
2084
2085void Assembler::testl(const Operand& op, Immediate mask) {
2086 // testl with a mask that fits in the low byte is exactly testb.
2087 if (is_uint8(mask.value_)) {
2088 testb(op, mask);
2089 return;
2090 }
2091 EnsureSpace ensure_space(this);
2092 last_pc_ = pc_;
2093 emit_optional_rex_32(rax, op);
2094 emit(0xF7);
2095 emit_operand(rax, op); // Operation code 0
2096 emit(mask);
2097}
2098
2099
2100void Assembler::testq(const Operand& op, Register reg) {
2101 EnsureSpace ensure_space(this);
2102 last_pc_ = pc_;
2103 emit_rex_64(reg, op);
2104 emit(0x85);
2105 emit_operand(reg, op);
2106}
2107
2108
2109void Assembler::testq(Register dst, Register src) {
2110 EnsureSpace ensure_space(this);
2111 last_pc_ = pc_;
Leon Clarkef7060e22010-06-03 12:02:55 +01002112 if (src.low_bits() == 4) {
2113 emit_rex_64(src, dst);
2114 emit(0x85);
2115 emit_modrm(src, dst);
2116 } else {
2117 emit_rex_64(dst, src);
2118 emit(0x85);
2119 emit_modrm(dst, src);
2120 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002121}
2122
2123
2124void Assembler::testq(Register dst, Immediate mask) {
2125 EnsureSpace ensure_space(this);
2126 last_pc_ = pc_;
2127 if (dst.is(rax)) {
2128 emit_rex_64();
2129 emit(0xA9);
2130 emit(mask);
2131 } else {
2132 emit_rex_64(dst);
2133 emit(0xF7);
2134 emit_modrm(0, dst);
2135 emit(mask);
2136 }
2137}
2138
2139
Andrei Popescu31002712010-02-23 13:46:05 +00002140// FPU instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00002141
2142
2143void Assembler::fld(int i) {
2144 EnsureSpace ensure_space(this);
2145 last_pc_ = pc_;
2146 emit_farith(0xD9, 0xC0, i);
2147}
2148
2149
2150void Assembler::fld1() {
2151 EnsureSpace ensure_space(this);
2152 last_pc_ = pc_;
2153 emit(0xD9);
2154 emit(0xE8);
2155}
2156
2157
2158void Assembler::fldz() {
2159 EnsureSpace ensure_space(this);
2160 last_pc_ = pc_;
2161 emit(0xD9);
2162 emit(0xEE);
2163}
2164
2165
Steve Block6ded16b2010-05-10 14:33:55 +01002166void Assembler::fldpi() {
2167 EnsureSpace ensure_space(this);
2168 last_pc_ = pc_;
2169 emit(0xD9);
2170 emit(0xEB);
2171}
2172
2173
Steve Blocka7e24c12009-10-30 11:49:00 +00002174void Assembler::fld_s(const Operand& adr) {
2175 EnsureSpace ensure_space(this);
2176 last_pc_ = pc_;
2177 emit_optional_rex_32(adr);
2178 emit(0xD9);
2179 emit_operand(0, adr);
2180}
2181
2182
2183void Assembler::fld_d(const Operand& adr) {
2184 EnsureSpace ensure_space(this);
2185 last_pc_ = pc_;
2186 emit_optional_rex_32(adr);
2187 emit(0xDD);
2188 emit_operand(0, adr);
2189}
2190
2191
2192void Assembler::fstp_s(const Operand& adr) {
2193 EnsureSpace ensure_space(this);
2194 last_pc_ = pc_;
2195 emit_optional_rex_32(adr);
2196 emit(0xD9);
2197 emit_operand(3, adr);
2198}
2199
2200
2201void Assembler::fstp_d(const Operand& adr) {
2202 EnsureSpace ensure_space(this);
2203 last_pc_ = pc_;
2204 emit_optional_rex_32(adr);
2205 emit(0xDD);
2206 emit_operand(3, adr);
2207}
2208
2209
Steve Block3ce2e202009-11-05 08:53:23 +00002210void Assembler::fstp(int index) {
2211 ASSERT(is_uint3(index));
2212 EnsureSpace ensure_space(this);
2213 last_pc_ = pc_;
2214 emit_farith(0xDD, 0xD8, index);
2215}
2216
2217
Steve Blocka7e24c12009-10-30 11:49:00 +00002218void Assembler::fild_s(const Operand& adr) {
2219 EnsureSpace ensure_space(this);
2220 last_pc_ = pc_;
2221 emit_optional_rex_32(adr);
2222 emit(0xDB);
2223 emit_operand(0, adr);
2224}
2225
2226
2227void Assembler::fild_d(const Operand& adr) {
2228 EnsureSpace ensure_space(this);
2229 last_pc_ = pc_;
2230 emit_optional_rex_32(adr);
2231 emit(0xDF);
2232 emit_operand(5, adr);
2233}
2234
2235
2236void Assembler::fistp_s(const Operand& adr) {
2237 EnsureSpace ensure_space(this);
2238 last_pc_ = pc_;
2239 emit_optional_rex_32(adr);
2240 emit(0xDB);
2241 emit_operand(3, adr);
2242}
2243
2244
2245void Assembler::fisttp_s(const Operand& adr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002246 ASSERT(CpuFeatures::IsEnabled(SSE3));
Steve Blocka7e24c12009-10-30 11:49:00 +00002247 EnsureSpace ensure_space(this);
2248 last_pc_ = pc_;
2249 emit_optional_rex_32(adr);
2250 emit(0xDB);
2251 emit_operand(1, adr);
2252}
2253
2254
Leon Clarked91b9f72010-01-27 17:25:45 +00002255void Assembler::fisttp_d(const Operand& adr) {
2256 ASSERT(CpuFeatures::IsEnabled(SSE3));
2257 EnsureSpace ensure_space(this);
2258 last_pc_ = pc_;
2259 emit_optional_rex_32(adr);
2260 emit(0xDD);
2261 emit_operand(1, adr);
2262}
2263
2264
Steve Blocka7e24c12009-10-30 11:49:00 +00002265void Assembler::fist_s(const Operand& adr) {
2266 EnsureSpace ensure_space(this);
2267 last_pc_ = pc_;
2268 emit_optional_rex_32(adr);
2269 emit(0xDB);
2270 emit_operand(2, adr);
2271}
2272
2273
2274void Assembler::fistp_d(const Operand& adr) {
2275 EnsureSpace ensure_space(this);
2276 last_pc_ = pc_;
2277 emit_optional_rex_32(adr);
2278 emit(0xDF);
Steve Block3ce2e202009-11-05 08:53:23 +00002279 emit_operand(7, adr);
Steve Blocka7e24c12009-10-30 11:49:00 +00002280}
2281
2282
2283void Assembler::fabs() {
2284 EnsureSpace ensure_space(this);
2285 last_pc_ = pc_;
2286 emit(0xD9);
2287 emit(0xE1);
2288}
2289
2290
2291void Assembler::fchs() {
2292 EnsureSpace ensure_space(this);
2293 last_pc_ = pc_;
2294 emit(0xD9);
2295 emit(0xE0);
2296}
2297
2298
2299void Assembler::fcos() {
2300 EnsureSpace ensure_space(this);
2301 last_pc_ = pc_;
2302 emit(0xD9);
2303 emit(0xFF);
2304}
2305
2306
2307void Assembler::fsin() {
2308 EnsureSpace ensure_space(this);
2309 last_pc_ = pc_;
2310 emit(0xD9);
2311 emit(0xFE);
2312}
2313
2314
2315void Assembler::fadd(int i) {
2316 EnsureSpace ensure_space(this);
2317 last_pc_ = pc_;
2318 emit_farith(0xDC, 0xC0, i);
2319}
2320
2321
2322void Assembler::fsub(int i) {
2323 EnsureSpace ensure_space(this);
2324 last_pc_ = pc_;
2325 emit_farith(0xDC, 0xE8, i);
2326}
2327
2328
2329void Assembler::fisub_s(const Operand& adr) {
2330 EnsureSpace ensure_space(this);
2331 last_pc_ = pc_;
2332 emit_optional_rex_32(adr);
2333 emit(0xDA);
2334 emit_operand(4, adr);
2335}
2336
2337
2338void Assembler::fmul(int i) {
2339 EnsureSpace ensure_space(this);
2340 last_pc_ = pc_;
2341 emit_farith(0xDC, 0xC8, i);
2342}
2343
2344
2345void Assembler::fdiv(int i) {
2346 EnsureSpace ensure_space(this);
2347 last_pc_ = pc_;
2348 emit_farith(0xDC, 0xF8, i);
2349}
2350
2351
2352void Assembler::faddp(int i) {
2353 EnsureSpace ensure_space(this);
2354 last_pc_ = pc_;
2355 emit_farith(0xDE, 0xC0, i);
2356}
2357
2358
2359void Assembler::fsubp(int i) {
2360 EnsureSpace ensure_space(this);
2361 last_pc_ = pc_;
2362 emit_farith(0xDE, 0xE8, i);
2363}
2364
2365
2366void Assembler::fsubrp(int i) {
2367 EnsureSpace ensure_space(this);
2368 last_pc_ = pc_;
2369 emit_farith(0xDE, 0xE0, i);
2370}
2371
2372
2373void Assembler::fmulp(int i) {
2374 EnsureSpace ensure_space(this);
2375 last_pc_ = pc_;
2376 emit_farith(0xDE, 0xC8, i);
2377}
2378
2379
2380void Assembler::fdivp(int i) {
2381 EnsureSpace ensure_space(this);
2382 last_pc_ = pc_;
2383 emit_farith(0xDE, 0xF8, i);
2384}
2385
2386
2387void Assembler::fprem() {
2388 EnsureSpace ensure_space(this);
2389 last_pc_ = pc_;
2390 emit(0xD9);
2391 emit(0xF8);
2392}
2393
2394
2395void Assembler::fprem1() {
2396 EnsureSpace ensure_space(this);
2397 last_pc_ = pc_;
2398 emit(0xD9);
2399 emit(0xF5);
2400}
2401
2402
2403void Assembler::fxch(int i) {
2404 EnsureSpace ensure_space(this);
2405 last_pc_ = pc_;
2406 emit_farith(0xD9, 0xC8, i);
2407}
2408
2409
2410void Assembler::fincstp() {
2411 EnsureSpace ensure_space(this);
2412 last_pc_ = pc_;
2413 emit(0xD9);
2414 emit(0xF7);
2415}
2416
2417
2418void Assembler::ffree(int i) {
2419 EnsureSpace ensure_space(this);
2420 last_pc_ = pc_;
2421 emit_farith(0xDD, 0xC0, i);
2422}
2423
2424
2425void Assembler::ftst() {
2426 EnsureSpace ensure_space(this);
2427 last_pc_ = pc_;
2428 emit(0xD9);
2429 emit(0xE4);
2430}
2431
2432
2433void Assembler::fucomp(int i) {
2434 EnsureSpace ensure_space(this);
2435 last_pc_ = pc_;
2436 emit_farith(0xDD, 0xE8, i);
2437}
2438
2439
2440void Assembler::fucompp() {
2441 EnsureSpace ensure_space(this);
2442 last_pc_ = pc_;
2443 emit(0xDA);
2444 emit(0xE9);
2445}
2446
2447
Steve Block3ce2e202009-11-05 08:53:23 +00002448void Assembler::fucomi(int i) {
2449 EnsureSpace ensure_space(this);
2450 last_pc_ = pc_;
2451 emit(0xDB);
2452 emit(0xE8 + i);
2453}
2454
2455
2456void Assembler::fucomip() {
2457 EnsureSpace ensure_space(this);
2458 last_pc_ = pc_;
2459 emit(0xDF);
2460 emit(0xE9);
2461}
2462
2463
Steve Blocka7e24c12009-10-30 11:49:00 +00002464void Assembler::fcompp() {
2465 EnsureSpace ensure_space(this);
2466 last_pc_ = pc_;
2467 emit(0xDE);
2468 emit(0xD9);
2469}
2470
2471
2472void Assembler::fnstsw_ax() {
2473 EnsureSpace ensure_space(this);
2474 last_pc_ = pc_;
2475 emit(0xDF);
2476 emit(0xE0);
2477}
2478
2479
2480void Assembler::fwait() {
2481 EnsureSpace ensure_space(this);
2482 last_pc_ = pc_;
2483 emit(0x9B);
2484}
2485
2486
2487void Assembler::frndint() {
2488 EnsureSpace ensure_space(this);
2489 last_pc_ = pc_;
2490 emit(0xD9);
2491 emit(0xFC);
2492}
2493
2494
2495void Assembler::fnclex() {
2496 EnsureSpace ensure_space(this);
2497 last_pc_ = pc_;
2498 emit(0xDB);
2499 emit(0xE2);
2500}
2501
2502
2503void Assembler::sahf() {
2504 // TODO(X64): Test for presence. Not all 64-bit intel CPU's have sahf
2505 // in 64-bit mode. Test CpuID.
2506 EnsureSpace ensure_space(this);
2507 last_pc_ = pc_;
2508 emit(0x9E);
2509}
2510
2511
2512void Assembler::emit_farith(int b1, int b2, int i) {
2513 ASSERT(is_uint8(b1) && is_uint8(b2)); // wrong opcode
2514 ASSERT(is_uint3(i)); // illegal stack offset
2515 emit(b1);
2516 emit(b2 + i);
2517}
2518
Andrei Popescu31002712010-02-23 13:46:05 +00002519// SSE 2 operations.
Steve Blocka7e24c12009-10-30 11:49:00 +00002520
Steve Block6ded16b2010-05-10 14:33:55 +01002521void Assembler::movd(XMMRegister dst, Register src) {
2522 EnsureSpace ensure_space(this);
2523 last_pc_ = pc_;
2524 emit(0x66);
2525 emit_optional_rex_32(dst, src);
2526 emit(0x0F);
2527 emit(0x6E);
2528 emit_sse_operand(dst, src);
2529}
2530
2531
2532void Assembler::movd(Register dst, XMMRegister src) {
2533 EnsureSpace ensure_space(this);
2534 last_pc_ = pc_;
2535 emit(0x66);
2536 emit_optional_rex_32(dst, src);
2537 emit(0x0F);
2538 emit(0x7E);
2539 emit_sse_operand(dst, src);
2540}
2541
2542
2543void Assembler::movq(XMMRegister dst, Register src) {
2544 EnsureSpace ensure_space(this);
2545 last_pc_ = pc_;
2546 emit(0x66);
2547 emit_rex_64(dst, src);
2548 emit(0x0F);
2549 emit(0x6E);
2550 emit_sse_operand(dst, src);
2551}
2552
2553
2554void Assembler::movq(Register dst, XMMRegister src) {
2555 EnsureSpace ensure_space(this);
2556 last_pc_ = pc_;
2557 emit(0x66);
2558 emit_rex_64(dst, src);
2559 emit(0x0F);
2560 emit(0x7E);
2561 emit_sse_operand(dst, src);
2562}
2563
2564
2565void Assembler::extractps(Register dst, XMMRegister src, byte imm8) {
2566 ASSERT(is_uint2(imm8));
2567 EnsureSpace ensure_space(this);
2568 last_pc_ = pc_;
2569 emit(0x66);
2570 emit_optional_rex_32(dst, src);
2571 emit(0x0F);
2572 emit(0x3A);
2573 emit(0x17);
2574 emit_sse_operand(dst, src);
2575 emit(imm8);
2576}
2577
2578
Steve Blocka7e24c12009-10-30 11:49:00 +00002579void Assembler::movsd(const Operand& dst, XMMRegister src) {
2580 EnsureSpace ensure_space(this);
2581 last_pc_ = pc_;
2582 emit(0xF2); // double
2583 emit_optional_rex_32(src, dst);
2584 emit(0x0F);
2585 emit(0x11); // store
2586 emit_sse_operand(src, dst);
2587}
2588
2589
Steve Block3ce2e202009-11-05 08:53:23 +00002590void Assembler::movsd(XMMRegister dst, XMMRegister src) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002591 EnsureSpace ensure_space(this);
2592 last_pc_ = pc_;
2593 emit(0xF2); // double
2594 emit_optional_rex_32(dst, src);
2595 emit(0x0F);
2596 emit(0x10); // load
2597 emit_sse_operand(dst, src);
2598}
2599
2600
2601void Assembler::movsd(XMMRegister dst, const Operand& src) {
2602 EnsureSpace ensure_space(this);
2603 last_pc_ = pc_;
2604 emit(0xF2); // double
2605 emit_optional_rex_32(dst, src);
2606 emit(0x0F);
2607 emit(0x10); // load
2608 emit_sse_operand(dst, src);
2609}
2610
2611
2612void Assembler::cvttss2si(Register dst, const Operand& src) {
2613 EnsureSpace ensure_space(this);
2614 last_pc_ = pc_;
2615 emit(0xF3);
2616 emit_optional_rex_32(dst, src);
2617 emit(0x0F);
2618 emit(0x2C);
2619 emit_operand(dst, src);
2620}
2621
2622
2623void Assembler::cvttsd2si(Register dst, const Operand& src) {
2624 EnsureSpace ensure_space(this);
2625 last_pc_ = pc_;
2626 emit(0xF2);
2627 emit_optional_rex_32(dst, src);
2628 emit(0x0F);
2629 emit(0x2C);
2630 emit_operand(dst, src);
2631}
2632
2633
Kristian Monsen25f61362010-05-21 11:50:48 +01002634void Assembler::cvttsd2siq(Register dst, XMMRegister src) {
2635 EnsureSpace ensure_space(this);
2636 last_pc_ = pc_;
2637 emit(0xF2);
2638 emit_rex_64(dst, src);
2639 emit(0x0F);
2640 emit(0x2C);
2641 emit_sse_operand(dst, src);
2642}
2643
2644
Steve Blocka7e24c12009-10-30 11:49:00 +00002645void Assembler::cvtlsi2sd(XMMRegister dst, const Operand& src) {
2646 EnsureSpace ensure_space(this);
2647 last_pc_ = pc_;
2648 emit(0xF2);
2649 emit_optional_rex_32(dst, src);
2650 emit(0x0F);
2651 emit(0x2A);
2652 emit_sse_operand(dst, src);
2653}
2654
2655
2656void Assembler::cvtlsi2sd(XMMRegister dst, Register src) {
2657 EnsureSpace ensure_space(this);
2658 last_pc_ = pc_;
2659 emit(0xF2);
2660 emit_optional_rex_32(dst, src);
2661 emit(0x0F);
2662 emit(0x2A);
2663 emit_sse_operand(dst, src);
2664}
2665
2666
2667void Assembler::cvtqsi2sd(XMMRegister dst, Register src) {
2668 EnsureSpace ensure_space(this);
2669 last_pc_ = pc_;
2670 emit(0xF2);
2671 emit_rex_64(dst, src);
2672 emit(0x0F);
2673 emit(0x2A);
2674 emit_sse_operand(dst, src);
2675}
2676
2677
Steve Block6ded16b2010-05-10 14:33:55 +01002678void Assembler::cvtss2sd(XMMRegister dst, XMMRegister src) {
2679 EnsureSpace ensure_space(this);
2680 last_pc_ = pc_;
2681 emit(0xF3);
2682 emit_optional_rex_32(dst, src);
2683 emit(0x0F);
2684 emit(0x5A);
2685 emit_sse_operand(dst, src);
2686}
2687
2688
Steve Blocka7e24c12009-10-30 11:49:00 +00002689void Assembler::addsd(XMMRegister dst, XMMRegister src) {
2690 EnsureSpace ensure_space(this);
2691 last_pc_ = pc_;
2692 emit(0xF2);
2693 emit_optional_rex_32(dst, src);
2694 emit(0x0F);
2695 emit(0x58);
2696 emit_sse_operand(dst, src);
2697}
2698
2699
2700void Assembler::mulsd(XMMRegister dst, XMMRegister src) {
2701 EnsureSpace ensure_space(this);
2702 last_pc_ = pc_;
2703 emit(0xF2);
2704 emit_optional_rex_32(dst, src);
2705 emit(0x0F);
2706 emit(0x59);
2707 emit_sse_operand(dst, src);
2708}
2709
2710
2711void Assembler::subsd(XMMRegister dst, XMMRegister src) {
2712 EnsureSpace ensure_space(this);
2713 last_pc_ = pc_;
2714 emit(0xF2);
2715 emit_optional_rex_32(dst, src);
2716 emit(0x0F);
2717 emit(0x5C);
2718 emit_sse_operand(dst, src);
2719}
2720
2721
2722void Assembler::divsd(XMMRegister dst, XMMRegister src) {
2723 EnsureSpace ensure_space(this);
2724 last_pc_ = pc_;
2725 emit(0xF2);
2726 emit_optional_rex_32(dst, src);
2727 emit(0x0F);
2728 emit(0x5E);
2729 emit_sse_operand(dst, src);
2730}
2731
2732
Andrei Popescu402d9372010-02-26 13:31:12 +00002733void Assembler::xorpd(XMMRegister dst, XMMRegister src) {
2734 EnsureSpace ensure_space(this);
2735 last_pc_ = pc_;
2736 emit(0x66);
2737 emit_optional_rex_32(dst, src);
Steve Block6ded16b2010-05-10 14:33:55 +01002738 emit(0x0F);
Andrei Popescu402d9372010-02-26 13:31:12 +00002739 emit(0x57);
2740 emit_sse_operand(dst, src);
2741}
2742
2743
Steve Block6ded16b2010-05-10 14:33:55 +01002744void Assembler::sqrtsd(XMMRegister dst, XMMRegister src) {
2745 EnsureSpace ensure_space(this);
2746 last_pc_ = pc_;
2747 emit(0xF2);
2748 emit_optional_rex_32(dst, src);
2749 emit(0x0F);
2750 emit(0x51);
2751 emit_sse_operand(dst, src);
2752}
2753
2754
Andrei Popescu402d9372010-02-26 13:31:12 +00002755void Assembler::ucomisd(XMMRegister dst, XMMRegister src) {
2756 EnsureSpace ensure_space(this);
2757 last_pc_ = pc_;
2758 emit(0x66);
2759 emit_optional_rex_32(dst, src);
2760 emit(0x0f);
2761 emit(0x2e);
2762 emit_sse_operand(dst, src);
2763}
2764
Steve Blocka7e24c12009-10-30 11:49:00 +00002765
2766void Assembler::emit_sse_operand(XMMRegister reg, const Operand& adr) {
2767 Register ireg = { reg.code() };
2768 emit_operand(ireg, adr);
2769}
2770
2771
2772void Assembler::emit_sse_operand(XMMRegister dst, XMMRegister src) {
2773 emit(0xC0 | (dst.low_bits() << 3) | src.low_bits());
2774}
2775
2776void Assembler::emit_sse_operand(XMMRegister dst, Register src) {
2777 emit(0xC0 | (dst.low_bits() << 3) | src.low_bits());
2778}
2779
Steve Block6ded16b2010-05-10 14:33:55 +01002780void Assembler::emit_sse_operand(Register dst, XMMRegister src) {
2781 emit(0xC0 | (dst.low_bits() << 3) | src.low_bits());
2782}
2783
Steve Blocka7e24c12009-10-30 11:49:00 +00002784
Andrei Popescu31002712010-02-23 13:46:05 +00002785// Relocation information implementations.
Steve Blocka7e24c12009-10-30 11:49:00 +00002786
2787void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
2788 ASSERT(rmode != RelocInfo::NONE);
2789 // Don't record external references unless the heap will be serialized.
2790 if (rmode == RelocInfo::EXTERNAL_REFERENCE &&
2791 !Serializer::enabled() &&
2792 !FLAG_debug_code) {
2793 return;
2794 }
2795 RelocInfo rinfo(pc_, rmode, data);
2796 reloc_info_writer.Write(&rinfo);
2797}
2798
2799void Assembler::RecordJSReturn() {
2800 WriteRecordedPositions();
2801 EnsureSpace ensure_space(this);
2802 RecordRelocInfo(RelocInfo::JS_RETURN);
2803}
2804
2805
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002806void Assembler::RecordDebugBreakSlot() {
2807 WriteRecordedPositions();
2808 EnsureSpace ensure_space(this);
2809 RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
2810}
2811
2812
Steve Blocka7e24c12009-10-30 11:49:00 +00002813void Assembler::RecordComment(const char* msg) {
2814 if (FLAG_debug_code) {
2815 EnsureSpace ensure_space(this);
2816 RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg));
2817 }
2818}
2819
2820
2821void Assembler::RecordPosition(int pos) {
2822 ASSERT(pos != RelocInfo::kNoPosition);
2823 ASSERT(pos >= 0);
2824 current_position_ = pos;
2825}
2826
2827
2828void Assembler::RecordStatementPosition(int pos) {
2829 ASSERT(pos != RelocInfo::kNoPosition);
2830 ASSERT(pos >= 0);
2831 current_statement_position_ = pos;
2832}
2833
2834
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002835bool Assembler::WriteRecordedPositions() {
2836 bool written = false;
2837
Steve Blocka7e24c12009-10-30 11:49:00 +00002838 // Write the statement position if it is different from what was written last
2839 // time.
2840 if (current_statement_position_ != written_statement_position_) {
2841 EnsureSpace ensure_space(this);
2842 RecordRelocInfo(RelocInfo::STATEMENT_POSITION, current_statement_position_);
2843 written_statement_position_ = current_statement_position_;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002844 written = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00002845 }
2846
2847 // Write the position if it is different from what was written last time and
2848 // also different from the written statement position.
2849 if (current_position_ != written_position_ &&
2850 current_position_ != written_statement_position_) {
2851 EnsureSpace ensure_space(this);
2852 RecordRelocInfo(RelocInfo::POSITION, current_position_);
2853 written_position_ = current_position_;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002854 written = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00002855 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002856
2857 // Return whether something was written.
2858 return written;
Steve Blocka7e24c12009-10-30 11:49:00 +00002859}
2860
2861
Steve Block3ce2e202009-11-05 08:53:23 +00002862const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask |
2863 1 << RelocInfo::INTERNAL_REFERENCE |
2864 1 << RelocInfo::JS_RETURN;
Steve Blocka7e24c12009-10-30 11:49:00 +00002865
Leon Clarkef7060e22010-06-03 12:02:55 +01002866
2867bool RelocInfo::IsCodedSpecially() {
2868 // The deserializer needs to know whether a pointer is specially coded. Being
2869 // specially coded on x64 means that it is a relative 32 bit address, as used
2870 // by branch instructions.
2871 return (1 << rmode_) & kApplyMask;
2872}
2873
2874
2875
Steve Blocka7e24c12009-10-30 11:49:00 +00002876} } // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01002877
2878#endif // V8_TARGET_ARCH_X64