blob: c23eb168978a1438032776cb1b453ce5a91e0b46 [file] [log] [blame]
ager@chromium.org9085a012009-05-11 19:22:57 +00001// Copyright (c) 1994-2006 Sun Microsystems Inc.
2// All Rights Reserved.
3//
ager@chromium.org5ec48922009-05-05 07:25:34 +00004// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
ager@chromium.org9085a012009-05-11 19:22:57 +00008// - Redistributions of source code must retain the above copyright notice,
9// this list of conditions and the following disclaimer.
ager@chromium.org5ec48922009-05-05 07:25:34 +000010//
ager@chromium.org9085a012009-05-11 19:22:57 +000011// - Redistribution in binary form must reproduce the above copyright
12// notice, this list of conditions and the following disclaimer in the
13// documentation and/or other materials provided with the distribution.
14//
15// - Neither the name of Sun Microsystems or the names of contributors may
16// be used to endorse or promote products derived from this software without
17// specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ager@chromium.org5ec48922009-05-05 07:25:34 +000030
ager@chromium.org9085a012009-05-11 19:22:57 +000031// The original source code covered by the above license above has been
32// modified significantly by Google Inc.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000033// Copyright 2011 the V8 project authors. All rights reserved.
ager@chromium.org9085a012009-05-11 19:22:57 +000034
35// A lightweight X64 Assembler.
36
37#ifndef V8_X64_ASSEMBLER_X64_H_
38#define V8_X64_ASSEMBLER_X64_H_
39
ager@chromium.orgc4c92722009-11-18 14:12:51 +000040#include "serialize.h"
41
kasperl@chromium.org71affb52009-05-26 05:44:31 +000042namespace v8 {
43namespace internal {
ager@chromium.org9085a012009-05-11 19:22:57 +000044
ager@chromium.orge2902be2009-06-08 12:21:35 +000045// Utility functions
46
47// Test whether a 64-bit value is in a specific range.
48static inline bool is_uint32(int64_t x) {
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000049 static const uint64_t kMaxUInt32 = V8_UINT64_C(0xffffffff);
50 return static_cast<uint64_t>(x) <= kMaxUInt32;
ager@chromium.orge2902be2009-06-08 12:21:35 +000051}
52
53static inline bool is_int32(int64_t x) {
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000054 static const int64_t kMinInt32 = -V8_INT64_C(0x80000000);
55 return is_uint32(x - kMinInt32);
ager@chromium.orge2902be2009-06-08 12:21:35 +000056}
57
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +000058static inline bool uint_is_int32(uint64_t x) {
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000059 static const uint64_t kMaxInt32 = V8_UINT64_C(0x7fffffff);
60 return x <= kMaxInt32;
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +000061}
62
63static inline bool is_uint32(uint64_t x) {
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000064 static const uint64_t kMaxUInt32 = V8_UINT64_C(0xffffffff);
65 return x <= kMaxUInt32;
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +000066}
67
ager@chromium.org9085a012009-05-11 19:22:57 +000068// CPU Registers.
69//
70// 1) We would prefer to use an enum, but enum values are assignment-
71// compatible with int, which has caused code-generation bugs.
72//
73// 2) We would prefer to use a class instead of a struct but we don't like
74// the register initialization to depend on the particular initialization
75// order (which appears to be different on OS X, Linux, and Windows for the
76// installed versions of C++ we tried). Using a struct permits C-style
77// "initialization". Also, the Register objects cannot be const as this
78// forces initialization stubs in MSVC, making us dependent on initialization
79// order.
80//
81// 3) By not using an enum, we are possibly preventing the compiler from
82// doing certain constant folds, which may significantly reduce the
83// code generated for some assembly instructions (because they boil down
84// to a few constants). If this is a problem, we could change the code
85// such that we use an enum in optimized mode, and the struct in debug
86// mode. This way we get the compile-time error checking in debug mode
87// and best performance in optimized code.
88//
ager@chromium.org9085a012009-05-11 19:22:57 +000089
90struct Register {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000091 // The non-allocatable registers are:
92 // rsp - stack pointer
93 // rbp - frame pointer
94 // rsi - context register
95 // r10 - fixed scratch register
whesse@chromium.orgb08986c2011-03-14 16:13:42 +000096 // r12 - smi constant register
kasperl@chromium.orga5551262010-12-07 12:49:48 +000097 // r13 - root register
kasperl@chromium.orga5551262010-12-07 12:49:48 +000098 static const int kNumRegisters = 16;
99 static const int kNumAllocatableRegisters = 10;
100
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000101 static int ToAllocationIndex(Register reg) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000102 return kAllocationIndexByRegisterCode[reg.code()];
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000103 }
104
105 static Register FromAllocationIndex(int index) {
106 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000107 Register result = { kRegisterCodeByAllocationIndex[index] };
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000108 return result;
109 }
110
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000111 static const char* AllocationIndexToString(int index) {
112 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
113 const char* const names[] = {
114 "rax",
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000115 "rbx",
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000116 "rdx",
117 "rcx",
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000118 "rdi",
119 "r8",
120 "r9",
121 "r11",
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000122 "r14",
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000123 "r15"
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000124 };
125 return names[index];
126 }
127
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000128 static Register from_code(int code) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000129 Register r = { code };
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000130 return r;
131 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000132 bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000133 bool is(Register reg) const { return code_ == reg.code_; }
134 int code() const {
ager@chromium.org9085a012009-05-11 19:22:57 +0000135 ASSERT(is_valid());
136 return code_;
137 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000138 int bit() const {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000139 return 1 << code_;
ager@chromium.org9085a012009-05-11 19:22:57 +0000140 }
141
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000142 // Return the high bit of the register code as a 0 or 1. Used often
143 // when constructing the REX prefix byte.
144 int high_bit() const {
145 return code_ >> 3;
146 }
147 // Return the 3 low bits of the register code. Used when encoding registers
148 // in modR/M, SIB, and opcode bytes.
149 int low_bits() const {
150 return code_ & 0x7;
151 }
152
ager@chromium.org5c838252010-02-19 08:53:10 +0000153 // Unfortunately we can't make this private in a struct when initializing
154 // by assignment.
ager@chromium.org9085a012009-05-11 19:22:57 +0000155 int code_;
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000156
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000157 private:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000158 static const int kRegisterCodeByAllocationIndex[kNumAllocatableRegisters];
159 static const int kAllocationIndexByRegisterCode[kNumRegisters];
ager@chromium.org9085a012009-05-11 19:22:57 +0000160};
161
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +0000162const Register rax = { 0 };
163const Register rcx = { 1 };
164const Register rdx = { 2 };
165const Register rbx = { 3 };
166const Register rsp = { 4 };
167const Register rbp = { 5 };
168const Register rsi = { 6 };
169const Register rdi = { 7 };
170const Register r8 = { 8 };
171const Register r9 = { 9 };
172const Register r10 = { 10 };
173const Register r11 = { 11 };
174const Register r12 = { 12 };
175const Register r13 = { 13 };
176const Register r14 = { 14 };
177const Register r15 = { 15 };
178const Register no_reg = { -1 };
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000179
180
ager@chromium.org9085a012009-05-11 19:22:57 +0000181struct XMMRegister {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000182 static const int kNumRegisters = 16;
183 static const int kNumAllocatableRegisters = 15;
184
185 static int ToAllocationIndex(XMMRegister reg) {
186 ASSERT(reg.code() != 0);
187 return reg.code() - 1;
188 }
189
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000190 static XMMRegister FromAllocationIndex(int index) {
191 ASSERT(0 <= index && index < kNumAllocatableRegisters);
192 XMMRegister result = { index + 1 };
193 return result;
194 }
195
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000196 static const char* AllocationIndexToString(int index) {
197 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
198 const char* const names[] = {
199 "xmm1",
200 "xmm2",
201 "xmm3",
202 "xmm4",
203 "xmm5",
204 "xmm6",
205 "xmm7",
206 "xmm8",
207 "xmm9",
208 "xmm10",
209 "xmm11",
210 "xmm12",
211 "xmm13",
212 "xmm14",
213 "xmm15"
214 };
215 return names[index];
216 }
217
218 bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000219 bool is(XMMRegister reg) const { return code_ == reg.code_; }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000220 int code() const {
ager@chromium.org9085a012009-05-11 19:22:57 +0000221 ASSERT(is_valid());
222 return code_;
223 }
224
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000225 // Return the high bit of the register code as a 0 or 1. Used often
226 // when constructing the REX prefix byte.
227 int high_bit() const {
228 return code_ >> 3;
229 }
230 // Return the 3 low bits of the register code. Used when encoding registers
231 // in modR/M, SIB, and opcode bytes.
232 int low_bits() const {
233 return code_ & 0x7;
234 }
235
ager@chromium.org9085a012009-05-11 19:22:57 +0000236 int code_;
237};
238
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +0000239const XMMRegister xmm0 = { 0 };
240const XMMRegister xmm1 = { 1 };
241const XMMRegister xmm2 = { 2 };
242const XMMRegister xmm3 = { 3 };
243const XMMRegister xmm4 = { 4 };
244const XMMRegister xmm5 = { 5 };
245const XMMRegister xmm6 = { 6 };
246const XMMRegister xmm7 = { 7 };
247const XMMRegister xmm8 = { 8 };
248const XMMRegister xmm9 = { 9 };
249const XMMRegister xmm10 = { 10 };
250const XMMRegister xmm11 = { 11 };
251const XMMRegister xmm12 = { 12 };
252const XMMRegister xmm13 = { 13 };
253const XMMRegister xmm14 = { 14 };
254const XMMRegister xmm15 = { 15 };
ager@chromium.org9085a012009-05-11 19:22:57 +0000255
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000256
257typedef XMMRegister DoubleRegister;
258
259
ager@chromium.org9085a012009-05-11 19:22:57 +0000260enum Condition {
261 // any value < 0 is considered no_condition
262 no_condition = -1,
263
264 overflow = 0,
265 no_overflow = 1,
266 below = 2,
267 above_equal = 3,
268 equal = 4,
269 not_equal = 5,
270 below_equal = 6,
271 above = 7,
272 negative = 8,
273 positive = 9,
274 parity_even = 10,
275 parity_odd = 11,
276 less = 12,
277 greater_equal = 13,
278 less_equal = 14,
279 greater = 15,
280
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000281 // Fake conditions that are handled by the
282 // opcodes using them.
283 always = 16,
284 never = 17,
ager@chromium.org9085a012009-05-11 19:22:57 +0000285 // aliases
286 carry = below,
287 not_carry = above_equal,
288 zero = equal,
289 not_zero = not_equal,
290 sign = negative,
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000291 not_sign = positive,
292 last_condition = greater
ager@chromium.org9085a012009-05-11 19:22:57 +0000293};
294
295
296// Returns the equivalent of !cc.
297// Negation of the default no_condition (-1) results in a non-default
298// no_condition value (-2). As long as tests for no_condition check
299// for condition < 0, this will work as expected.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000300inline Condition NegateCondition(Condition cc) {
301 return static_cast<Condition>(cc ^ 1);
302}
303
ager@chromium.org9085a012009-05-11 19:22:57 +0000304
305// Corresponds to transposing the operands of a comparison.
306inline Condition ReverseCondition(Condition cc) {
307 switch (cc) {
308 case below:
309 return above;
310 case above:
311 return below;
312 case above_equal:
313 return below_equal;
314 case below_equal:
315 return above_equal;
316 case less:
317 return greater;
318 case greater:
319 return less;
320 case greater_equal:
321 return less_equal;
322 case less_equal:
323 return greater_equal;
324 default:
325 return cc;
326 };
327}
328
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000329
ager@chromium.org9085a012009-05-11 19:22:57 +0000330// -----------------------------------------------------------------------------
331// Machine instruction Immediates
332
333class Immediate BASE_EMBEDDED {
334 public:
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000335 explicit Immediate(int32_t value) : value_(value) {}
ager@chromium.org9085a012009-05-11 19:22:57 +0000336
ager@chromium.org9085a012009-05-11 19:22:57 +0000337 private:
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000338 int32_t value_;
ager@chromium.org9085a012009-05-11 19:22:57 +0000339
340 friend class Assembler;
341};
342
343
344// -----------------------------------------------------------------------------
345// Machine instruction Operands
346
347enum ScaleFactor {
ager@chromium.org3e875802009-06-29 08:26:34 +0000348 times_1 = 0,
349 times_2 = 1,
350 times_4 = 2,
351 times_8 = 3,
352 times_int_size = times_4,
353 times_pointer_size = times_8
ager@chromium.org9085a012009-05-11 19:22:57 +0000354};
355
356
357class Operand BASE_EMBEDDED {
358 public:
ager@chromium.org9085a012009-05-11 19:22:57 +0000359 // [base + disp/r]
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000360 Operand(Register base, int32_t disp);
ager@chromium.org9085a012009-05-11 19:22:57 +0000361
362 // [base + index*scale + disp/r]
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000363 Operand(Register base,
364 Register index,
365 ScaleFactor scale,
366 int32_t disp);
ager@chromium.org9085a012009-05-11 19:22:57 +0000367
368 // [index*scale + disp/r]
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000369 Operand(Register index,
370 ScaleFactor scale,
371 int32_t disp);
ager@chromium.org9085a012009-05-11 19:22:57 +0000372
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000373 // Offset from existing memory operand.
374 // Offset is added to existing displacement as 32-bit signed values and
375 // this must not overflow.
376 Operand(const Operand& base, int32_t offset);
377
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000378 // Checks whether either base or index register is the given register.
379 // Does not check the "reg" part of the Operand.
380 bool AddressUsesRegister(Register reg) const;
381
ricow@chromium.orgeb96f4f2011-03-09 13:41:48 +0000382 // Queries related to the size of the generated instruction.
383 // Whether the generated instruction will have a REX prefix.
384 bool requires_rex() const { return rex_ != 0; }
385 // Size of the ModR/M, SIB and displacement parts of the generated
386 // instruction.
387 int operand_size() const { return len_; }
388
ager@chromium.org9085a012009-05-11 19:22:57 +0000389 private:
390 byte rex_;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000391 byte buf_[6];
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000392 // The number of bytes of buf_ in use.
393 byte len_;
ager@chromium.org9085a012009-05-11 19:22:57 +0000394
ager@chromium.orge2902be2009-06-08 12:21:35 +0000395 // Set the ModR/M byte without an encoded 'reg' register. The
ager@chromium.org9085a012009-05-11 19:22:57 +0000396 // register is encoded later as part of the emit_operand operation.
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000397 // set_modrm can be called before or after set_sib and set_disp*.
ager@chromium.org9085a012009-05-11 19:22:57 +0000398 inline void set_modrm(int mod, Register rm);
399
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000400 // Set the SIB byte if one is needed. Sets the length to 2 rather than 1.
ager@chromium.org9085a012009-05-11 19:22:57 +0000401 inline void set_sib(ScaleFactor scale, Register index, Register base);
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000402
403 // Adds operand displacement fields (offsets added to the memory address).
404 // Needs to be called after set_sib, not before it.
405 inline void set_disp8(int disp);
406 inline void set_disp32(int disp);
ager@chromium.org9085a012009-05-11 19:22:57 +0000407
408 friend class Assembler;
409};
410
ager@chromium.org9085a012009-05-11 19:22:57 +0000411
412// CpuFeatures keeps track of which features are supported by the target CPU.
413// Supported features must be enabled by a Scope before use.
414// Example:
ager@chromium.org3e875802009-06-29 08:26:34 +0000415// if (CpuFeatures::IsSupported(SSE3)) {
416// CpuFeatures::Scope fscope(SSE3);
417// // Generate SSE3 floating point code.
ager@chromium.org9085a012009-05-11 19:22:57 +0000418// } else {
ager@chromium.org3e875802009-06-29 08:26:34 +0000419// // Generate standard x87 or SSE2 floating point code.
ager@chromium.org9085a012009-05-11 19:22:57 +0000420// }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000421class CpuFeatures : public AllStatic {
ager@chromium.org9085a012009-05-11 19:22:57 +0000422 public:
ager@chromium.org9085a012009-05-11 19:22:57 +0000423 // Detect features of the target CPU. Set safe defaults if the serializer
424 // is enabled (snapshots must be portable).
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000425 static void Probe();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000426
ager@chromium.org9085a012009-05-11 19:22:57 +0000427 // Check whether a feature is supported by the target CPU.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000428 static bool IsSupported(CpuFeature f) {
429 ASSERT(initialized_);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000430 if (f == SSE2 && !FLAG_enable_sse2) return false;
431 if (f == SSE3 && !FLAG_enable_sse3) return false;
432 if (f == CMOV && !FLAG_enable_cmov) return false;
433 if (f == RDTSC && !FLAG_enable_rdtsc) return false;
434 if (f == SAHF && !FLAG_enable_sahf) return false;
ager@chromium.orge2902be2009-06-08 12:21:35 +0000435 return (supported_ & (V8_UINT64_C(1) << f)) != 0;
ager@chromium.org9085a012009-05-11 19:22:57 +0000436 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000437
438#ifdef DEBUG
ager@chromium.org9085a012009-05-11 19:22:57 +0000439 // Check whether a feature is currently enabled.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000440 static bool IsEnabled(CpuFeature f) {
441 ASSERT(initialized_);
442 Isolate* isolate = Isolate::UncheckedCurrent();
443 if (isolate == NULL) {
444 // When no isolate is available, work as if we're running in
445 // release mode.
446 return IsSupported(f);
447 }
448 uint64_t enabled = isolate->enabled_cpu_features();
449 return (enabled & (V8_UINT64_C(1) << f)) != 0;
ager@chromium.org9085a012009-05-11 19:22:57 +0000450 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000451#endif
452
ager@chromium.org9085a012009-05-11 19:22:57 +0000453 // Enable a specified feature within a scope.
454 class Scope BASE_EMBEDDED {
455#ifdef DEBUG
456 public:
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000457 explicit Scope(CpuFeature f) {
458 uint64_t mask = V8_UINT64_C(1) << f;
459 ASSERT(CpuFeatures::IsSupported(f));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000460 ASSERT(!Serializer::enabled() ||
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000461 (CpuFeatures::found_by_runtime_probing_ & mask) == 0);
462 isolate_ = Isolate::UncheckedCurrent();
463 old_enabled_ = 0;
464 if (isolate_ != NULL) {
465 old_enabled_ = isolate_->enabled_cpu_features();
466 isolate_->set_enabled_cpu_features(old_enabled_ | mask);
467 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000468 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000469 ~Scope() {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000470 ASSERT_EQ(Isolate::UncheckedCurrent(), isolate_);
471 if (isolate_ != NULL) {
472 isolate_->set_enabled_cpu_features(old_enabled_);
473 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000474 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000475 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000476 Isolate* isolate_;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000477 uint64_t old_enabled_;
ager@chromium.org9085a012009-05-11 19:22:57 +0000478#else
479 public:
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000480 explicit Scope(CpuFeature f) {}
ager@chromium.org9085a012009-05-11 19:22:57 +0000481#endif
482 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000483
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000484 private:
ager@chromium.org3e875802009-06-29 08:26:34 +0000485 // Safe defaults include SSE2 and CMOV for X64. It is always available, if
486 // anyone checks, but they shouldn't need to check.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000487 // The required user mode extensions in X64 are (from AMD64 ABI Table A.1):
488 // fpu, tsc, cx8, cmov, mmx, sse, sse2, fxsr, syscall
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000489 static const uint64_t kDefaultCpuFeatures = (1 << SSE2 | 1 << CMOV);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000490
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000491#ifdef DEBUG
492 static bool initialized_;
493#endif
494 static uint64_t supported_;
495 static uint64_t found_by_runtime_probing_;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000496
497 DISALLOW_COPY_AND_ASSIGN(CpuFeatures);
ager@chromium.org9085a012009-05-11 19:22:57 +0000498};
499
500
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000501class Assembler : public AssemblerBase {
ager@chromium.org9085a012009-05-11 19:22:57 +0000502 private:
ager@chromium.org3e875802009-06-29 08:26:34 +0000503 // We check before assembling an instruction that there is sufficient
504 // space to write an instruction and its relocation information.
505 // The relocation writer's position must be kGap bytes above the end of
ager@chromium.org9085a012009-05-11 19:22:57 +0000506 // the generated instructions. This leaves enough space for the
ager@chromium.org3e875802009-06-29 08:26:34 +0000507 // longest possible x64 instruction, 15 bytes, and the longest possible
508 // relocation information encoding, RelocInfoWriter::kMaxLength == 16.
509 // (There is a 15 byte limit on x64 instruction length that rules out some
510 // otherwise valid instructions.)
511 // This allows for a single, fast space check per instruction.
ager@chromium.org9085a012009-05-11 19:22:57 +0000512 static const int kGap = 32;
513
514 public:
515 // Create an assembler. Instructions and relocation information are emitted
516 // into a buffer, with the instructions starting from the beginning and the
517 // relocation information starting from the end of the buffer. See CodeDesc
518 // for a detailed comment on the layout (globals.h).
519 //
520 // If the provided buffer is NULL, the assembler allocates and grows its own
521 // buffer, and buffer_size determines the initial buffer size. The buffer is
522 // owned by the assembler and deallocated upon destruction of the assembler.
523 //
524 // If the provided buffer is not NULL, the assembler uses the provided buffer
525 // for code generation and assumes its size to be buffer_size. If the buffer
526 // is too small, a fatal error occurs. No deallocation of the buffer is done
527 // upon destruction of the assembler.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000528 Assembler(Isolate* isolate, void* buffer, int buffer_size);
ager@chromium.org9085a012009-05-11 19:22:57 +0000529 ~Assembler();
530
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000531 // Overrides the default provided by FLAG_debug_code.
532 void set_emit_debug_code(bool value) { emit_debug_code_ = value; }
533
ager@chromium.org9085a012009-05-11 19:22:57 +0000534 // GetCode emits any pending (non-emitted) code and fills the descriptor
535 // desc. GetCode() is idempotent; it returns the same result if no other
536 // Assembler functions are invoked in between GetCode() calls.
537 void GetCode(CodeDesc* desc);
538
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000539 // Read/Modify the code target in the relative branch/call instruction at pc.
540 // On the x64 architecture, we use relative jumps with a 32-bit displacement
541 // to jump to other Code objects in the Code space in the heap.
542 // Jumps to C functions are done indirectly through a 64-bit register holding
543 // the absolute address of the target.
544 // These functions convert between absolute Addresses of Code objects and
545 // the relative displacements stored in the code.
ager@chromium.orge2902be2009-06-08 12:21:35 +0000546 static inline Address target_address_at(Address pc);
547 static inline void set_target_address_at(Address pc, Address target);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000548
ager@chromium.org3811b432009-10-28 14:53:37 +0000549 // This sets the branch destination (which is in the instruction on x64).
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000550 // This is for calls and branches within generated code.
ager@chromium.org3811b432009-10-28 14:53:37 +0000551 inline static void set_target_at(Address instruction_payload,
552 Address target) {
553 set_target_address_at(instruction_payload, target);
554 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000555
556 // This sets the branch destination (which is a load instruction on x64).
557 // This is for calls and branches to runtime code.
558 inline static void set_external_target_at(Address instruction_payload,
559 Address target) {
560 *reinterpret_cast<Address*>(instruction_payload) = target;
561 }
562
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000563 inline Handle<Object> code_target_object_handle_at(Address pc);
ager@chromium.org3811b432009-10-28 14:53:37 +0000564 // Number of bytes taken up by the branch target in the code.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000565 static const int kCallTargetSize = 4; // Use 32-bit displacement.
566 static const int kExternalTargetSize = 8; // Use 64-bit absolute.
ager@chromium.org9085a012009-05-11 19:22:57 +0000567 // Distance between the address of the code target in the call instruction
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000568 // and the return address pushed on the stack.
569 static const int kCallTargetAddressOffset = 4; // Use 32-bit displacement.
570 // Distance between the start of the JS return sequence and where the
571 // 32-bit displacement of a near call would be, relative to the pushed
572 // return address. TODO: Use return sequence length instead.
573 // Should equal Debug::kX64JSReturnSequenceLength - kCallTargetAddressOffset;
574 static const int kPatchReturnSequenceAddressOffset = 13 - 4;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000575 // Distance between start of patched debug break slot and where the
576 // 32-bit displacement of a near call would be, relative to the pushed
577 // return address. TODO: Use return sequence length instead.
578 // Should equal Debug::kX64JSReturnSequenceLength - kCallTargetAddressOffset;
579 static const int kPatchDebugBreakSlotAddressOffset = 13 - 4;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000580 // TODO(X64): Rename this, removing the "Real", after changing the above.
581 static const int kRealPatchReturnSequenceAddressOffset = 2;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000582
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000583 // Some x64 JS code is padded with int3 to make it large
584 // enough to hold an instruction when the debugger patches it.
585 static const int kJumpInstructionLength = 13;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000586 static const int kCallInstructionLength = 13;
587 static const int kJSReturnSequenceLength = 13;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000588 static const int kShortCallInstructionLength = 5;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000589
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000590 // The debug break slot must be able to contain a call instruction.
591 static const int kDebugBreakSlotLength = kCallInstructionLength;
592
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000593 // One byte opcode for test eax,0xXXXXXXXX.
594 static const byte kTestEaxByte = 0xA9;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000595 // One byte opcode for test al, 0xXX.
596 static const byte kTestAlByte = 0xA8;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000597 // One byte opcode for nop.
598 static const byte kNopByte = 0x90;
599
600 // One byte prefix for a short conditional jump.
601 static const byte kJccShortPrefix = 0x70;
602 static const byte kJncShortOpcode = kJccShortPrefix | not_carry;
603 static const byte kJcShortOpcode = kJccShortPrefix | carry;
604
605
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000606
ager@chromium.org9085a012009-05-11 19:22:57 +0000607 // ---------------------------------------------------------------------------
608 // Code generation
609 //
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000610 // Function names correspond one-to-one to x64 instruction mnemonics.
611 // Unless specified otherwise, instructions operate on 64-bit operands.
612 //
613 // If we need versions of an assembly instruction that operate on different
614 // width arguments, we add a single-letter suffix specifying the width.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000615 // This is done for the following instructions: mov, cmp, inc, dec,
616 // add, sub, and test.
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000617 // There are no versions of these instructions without the suffix.
618 // - Instructions on 8-bit (byte) operands/registers have a trailing 'b'.
619 // - Instructions on 16-bit (word) operands/registers have a trailing 'w'.
620 // - Instructions on 32-bit (doubleword) operands/registers use 'l'.
621 // - Instructions on 64-bit (quadword) operands/registers use 'q'.
622 //
623 // Some mnemonics, such as "and", are the same as C++ keywords.
624 // Naming conflicts with C++ keywords are resolved by adding a trailing '_'.
ager@chromium.org9085a012009-05-11 19:22:57 +0000625
626 // Insert the smallest number of nop instructions
627 // possible to align the pc offset to a multiple
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000628 // of m, where m must be a power of 2.
ager@chromium.org9085a012009-05-11 19:22:57 +0000629 void Align(int m);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000630 // Aligns code to something that's optimal for a jump target for the platform.
631 void CodeTargetAlign();
ager@chromium.org9085a012009-05-11 19:22:57 +0000632
633 // Stack
ager@chromium.orge2902be2009-06-08 12:21:35 +0000634 void pushfq();
635 void popfq();
ager@chromium.org9085a012009-05-11 19:22:57 +0000636
ager@chromium.orge2902be2009-06-08 12:21:35 +0000637 void push(Immediate value);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000638 // Push a 32 bit integer, and guarantee that it is actually pushed as a
639 // 32 bit value, the normal push will optimize the 8 bit case.
640 void push_imm32(int32_t imm32);
ager@chromium.org9085a012009-05-11 19:22:57 +0000641 void push(Register src);
642 void push(const Operand& src);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000643 void push(Handle<Object> handle);
ager@chromium.org9085a012009-05-11 19:22:57 +0000644
645 void pop(Register dst);
646 void pop(const Operand& dst);
647
ager@chromium.orge2902be2009-06-08 12:21:35 +0000648 void enter(Immediate size);
ager@chromium.org9085a012009-05-11 19:22:57 +0000649 void leave();
650
651 // Moves
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000652 void movb(Register dst, const Operand& src);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000653 void movb(Register dst, Immediate imm);
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000654 void movb(const Operand& dst, Register src);
ager@chromium.org9085a012009-05-11 19:22:57 +0000655
ager@chromium.org3811b432009-10-28 14:53:37 +0000656 // Move the low 16 bits of a 64-bit register value to a 16-bit
657 // memory location.
658 void movw(const Operand& dst, Register src);
659
ager@chromium.orge2902be2009-06-08 12:21:35 +0000660 void movl(Register dst, Register src);
661 void movl(Register dst, const Operand& src);
662 void movl(const Operand& dst, Register src);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000663 void movl(const Operand& dst, Immediate imm);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000664 // Load a 32-bit immediate value, zero-extended to 64 bits.
665 void movl(Register dst, Immediate imm32);
666
ager@chromium.orge2902be2009-06-08 12:21:35 +0000667 // Move 64 bit register value to 64-bit memory location.
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000668 void movq(const Operand& dst, Register src);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000669 // Move 64 bit memory location to 64-bit register value.
670 void movq(Register dst, const Operand& src);
671 void movq(Register dst, Register src);
672 // Sign extends immediate 32-bit value to 64 bits.
673 void movq(Register dst, Immediate x);
674 // Move the offset of the label location relative to the current
675 // position (after the move) to the destination.
676 void movl(const Operand& dst, Label* src);
677
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000678 // Move sign extended immediate to memory location.
679 void movq(const Operand& dst, Immediate value);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000680 // Instructions to load a 64-bit immediate into a register.
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000681 // All 64-bit immediates must have a relocation mode.
682 void movq(Register dst, void* ptr, RelocInfo::Mode rmode);
683 void movq(Register dst, int64_t value, RelocInfo::Mode rmode);
684 void movq(Register dst, const char* s, RelocInfo::Mode rmode);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000685 // Moves the address of the external reference into the register.
686 void movq(Register dst, ExternalReference ext);
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000687 void movq(Register dst, Handle<Object> handle, RelocInfo::Mode rmode);
688
ager@chromium.org3811b432009-10-28 14:53:37 +0000689 void movsxbq(Register dst, const Operand& src);
690 void movsxwq(Register dst, const Operand& src);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000691 void movsxlq(Register dst, Register src);
ager@chromium.org3e875802009-06-29 08:26:34 +0000692 void movsxlq(Register dst, const Operand& src);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000693 void movzxbq(Register dst, const Operand& src);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000694 void movzxbl(Register dst, const Operand& src);
ager@chromium.org3811b432009-10-28 14:53:37 +0000695 void movzxwq(Register dst, const Operand& src);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000696 void movzxwl(Register dst, const Operand& src);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000697
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000698 // Repeated moves.
699
700 void repmovsb();
701 void repmovsw();
702 void repmovsl();
703 void repmovsq();
704
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000705 // Instruction to load from an immediate 64-bit pointer into RAX.
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000706 void load_rax(void* ptr, RelocInfo::Mode rmode);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000707 void load_rax(ExternalReference ext);
ager@chromium.org9085a012009-05-11 19:22:57 +0000708
ager@chromium.org3e875802009-06-29 08:26:34 +0000709 // Conditional moves.
710 void cmovq(Condition cc, Register dst, Register src);
711 void cmovq(Condition cc, Register dst, const Operand& src);
712 void cmovl(Condition cc, Register dst, Register src);
713 void cmovl(Condition cc, Register dst, const Operand& src);
ager@chromium.org9085a012009-05-11 19:22:57 +0000714
715 // Exchange two registers
716 void xchg(Register dst, Register src);
717
718 // Arithmetics
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000719 void addl(Register dst, Register src) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000720 arithmetic_op_32(0x03, dst, src);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000721 }
722
ager@chromium.org3e875802009-06-29 08:26:34 +0000723 void addl(Register dst, Immediate src) {
724 immediate_arithmetic_op_32(0x0, dst, src);
725 }
726
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000727 void addl(Register dst, const Operand& src) {
728 arithmetic_op_32(0x03, dst, src);
729 }
730
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000731 void addl(const Operand& dst, Immediate src) {
732 immediate_arithmetic_op_32(0x0, dst, src);
733 }
734
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000735 void addq(Register dst, Register src) {
736 arithmetic_op(0x03, dst, src);
737 }
738
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000739 void addq(Register dst, const Operand& src) {
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000740 arithmetic_op(0x03, dst, src);
741 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000742
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000743 void addq(const Operand& dst, Register src) {
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000744 arithmetic_op(0x01, src, dst);
745 }
746
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000747 void addq(Register dst, Immediate src) {
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000748 immediate_arithmetic_op(0x0, dst, src);
749 }
750
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000751 void addq(const Operand& dst, Immediate src) {
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000752 immediate_arithmetic_op(0x0, dst, src);
753 }
754
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000755 void sbbl(Register dst, Register src) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000756 arithmetic_op_32(0x1b, dst, src);
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000757 }
758
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000759 void sbbq(Register dst, Register src) {
760 arithmetic_op(0x1b, dst, src);
761 }
762
ager@chromium.org3e875802009-06-29 08:26:34 +0000763 void cmpb(Register dst, Immediate src) {
764 immediate_arithmetic_op_8(0x7, dst, src);
765 }
766
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000767 void cmpb_al(Immediate src);
768
769 void cmpb(Register dst, Register src) {
770 arithmetic_op(0x3A, dst, src);
771 }
772
773 void cmpb(Register dst, const Operand& src) {
774 arithmetic_op(0x3A, dst, src);
775 }
776
777 void cmpb(const Operand& dst, Register src) {
778 arithmetic_op(0x38, src, dst);
779 }
780
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000781 void cmpb(const Operand& dst, Immediate src) {
782 immediate_arithmetic_op_8(0x7, dst, src);
783 }
784
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000785 void cmpw(const Operand& dst, Immediate src) {
786 immediate_arithmetic_op_16(0x7, dst, src);
787 }
788
789 void cmpw(Register dst, Immediate src) {
790 immediate_arithmetic_op_16(0x7, dst, src);
791 }
792
793 void cmpw(Register dst, const Operand& src) {
794 arithmetic_op_16(0x3B, dst, src);
795 }
796
797 void cmpw(Register dst, Register src) {
798 arithmetic_op_16(0x3B, dst, src);
799 }
800
801 void cmpw(const Operand& dst, Register src) {
802 arithmetic_op_16(0x39, src, dst);
803 }
804
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000805 void cmpl(Register dst, Register src) {
806 arithmetic_op_32(0x3B, dst, src);
807 }
808
809 void cmpl(Register dst, const Operand& src) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000810 arithmetic_op_32(0x3B, dst, src);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000811 }
812
813 void cmpl(const Operand& dst, Register src) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000814 arithmetic_op_32(0x39, src, dst);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000815 }
816
817 void cmpl(Register dst, Immediate src) {
818 immediate_arithmetic_op_32(0x7, dst, src);
819 }
820
821 void cmpl(const Operand& dst, Immediate src) {
822 immediate_arithmetic_op_32(0x7, dst, src);
823 }
824
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000825 void cmpq(Register dst, Register src) {
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000826 arithmetic_op(0x3B, dst, src);
827 }
828
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000829 void cmpq(Register dst, const Operand& src) {
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000830 arithmetic_op(0x3B, dst, src);
831 }
832
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000833 void cmpq(const Operand& dst, Register src) {
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000834 arithmetic_op(0x39, src, dst);
835 }
836
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000837 void cmpq(Register dst, Immediate src) {
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000838 immediate_arithmetic_op(0x7, dst, src);
839 }
840
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000841 void cmpq(const Operand& dst, Immediate src) {
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000842 immediate_arithmetic_op(0x7, dst, src);
843 }
844
845 void and_(Register dst, Register src) {
846 arithmetic_op(0x23, dst, src);
847 }
848
849 void and_(Register dst, const Operand& src) {
850 arithmetic_op(0x23, dst, src);
851 }
852
853 void and_(const Operand& dst, Register src) {
854 arithmetic_op(0x21, src, dst);
855 }
856
857 void and_(Register dst, Immediate src) {
858 immediate_arithmetic_op(0x4, dst, src);
859 }
860
861 void and_(const Operand& dst, Immediate src) {
862 immediate_arithmetic_op(0x4, dst, src);
863 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000864
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000865 void andl(Register dst, Immediate src) {
866 immediate_arithmetic_op_32(0x4, dst, src);
867 }
868
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000869 void andl(Register dst, Register src) {
870 arithmetic_op_32(0x23, dst, src);
871 }
872
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000873 void andl(Register dst, const Operand& src) {
874 arithmetic_op_32(0x23, dst, src);
875 }
876
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000877 void andb(Register dst, Immediate src) {
878 immediate_arithmetic_op_8(0x4, dst, src);
879 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000880
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000881 void decq(Register dst);
882 void decq(const Operand& dst);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000883 void decl(Register dst);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000884 void decl(const Operand& dst);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000885 void decb(Register dst);
886 void decb(const Operand& dst);
ager@chromium.org9085a012009-05-11 19:22:57 +0000887
ager@chromium.orge2902be2009-06-08 12:21:35 +0000888 // Sign-extends rax into rdx:rax.
889 void cqo();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000890 // Sign-extends eax into edx:eax.
891 void cdq();
ager@chromium.org9085a012009-05-11 19:22:57 +0000892
ager@chromium.orge2902be2009-06-08 12:21:35 +0000893 // Divide rdx:rax by src. Quotient in rax, remainder in rdx.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000894 void idivq(Register src);
895 // Divide edx:eax by lower 32 bits of src. Quotient in eax, rem. in edx.
896 void idivl(Register src);
ager@chromium.org9085a012009-05-11 19:22:57 +0000897
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000898 // Signed multiply instructions.
899 void imul(Register src); // rdx:rax = rax * src.
900 void imul(Register dst, Register src); // dst = dst * src.
901 void imul(Register dst, const Operand& src); // dst = dst * src.
902 void imul(Register dst, Register src, Immediate imm); // dst = src * imm.
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000903 // Signed 32-bit multiply instructions.
904 void imull(Register dst, Register src); // dst = dst * src.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000905 void imull(Register dst, const Operand& src); // dst = dst * src.
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000906 void imull(Register dst, Register src, Immediate imm); // dst = src * imm.
ager@chromium.org9085a012009-05-11 19:22:57 +0000907
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000908 void incq(Register dst);
909 void incq(const Operand& dst);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000910 void incl(Register dst);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000911 void incl(const Operand& dst);
ager@chromium.org9085a012009-05-11 19:22:57 +0000912
913 void lea(Register dst, const Operand& src);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000914 void leal(Register dst, const Operand& src);
ager@chromium.org9085a012009-05-11 19:22:57 +0000915
ager@chromium.orge2902be2009-06-08 12:21:35 +0000916 // Multiply rax by src, put the result in rdx:rax.
ager@chromium.org9085a012009-05-11 19:22:57 +0000917 void mul(Register src);
918
919 void neg(Register dst);
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000920 void neg(const Operand& dst);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000921 void negl(Register dst);
ager@chromium.org9085a012009-05-11 19:22:57 +0000922
923 void not_(Register dst);
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000924 void not_(const Operand& dst);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000925 void notl(Register dst);
ager@chromium.org9085a012009-05-11 19:22:57 +0000926
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000927 void or_(Register dst, Register src) {
928 arithmetic_op(0x0B, dst, src);
929 }
930
ager@chromium.org4af710e2009-09-15 12:20:11 +0000931 void orl(Register dst, Register src) {
932 arithmetic_op_32(0x0B, dst, src);
933 }
934
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000935 void or_(Register dst, const Operand& src) {
936 arithmetic_op(0x0B, dst, src);
937 }
938
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000939 void orl(Register dst, const Operand& src) {
940 arithmetic_op_32(0x0B, dst, src);
941 }
942
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000943 void or_(const Operand& dst, Register src) {
944 arithmetic_op(0x09, src, dst);
945 }
946
947 void or_(Register dst, Immediate src) {
948 immediate_arithmetic_op(0x1, dst, src);
949 }
950
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000951 void orl(Register dst, Immediate src) {
952 immediate_arithmetic_op_32(0x1, dst, src);
953 }
954
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000955 void or_(const Operand& dst, Immediate src) {
956 immediate_arithmetic_op(0x1, dst, src);
957 }
958
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000959 void orl(const Operand& dst, Immediate src) {
960 immediate_arithmetic_op_32(0x1, dst, src);
961 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000962
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000963
964 void rcl(Register dst, Immediate imm8) {
965 shift(dst, imm8, 0x2);
966 }
967
968 void rol(Register dst, Immediate imm8) {
969 shift(dst, imm8, 0x0);
970 }
971
972 void rcr(Register dst, Immediate imm8) {
973 shift(dst, imm8, 0x3);
974 }
975
976 void ror(Register dst, Immediate imm8) {
977 shift(dst, imm8, 0x1);
978 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000979
ager@chromium.orge2902be2009-06-08 12:21:35 +0000980 // Shifts dst:src left by cl bits, affecting only dst.
981 void shld(Register dst, Register src);
ager@chromium.org9085a012009-05-11 19:22:57 +0000982
ager@chromium.orge2902be2009-06-08 12:21:35 +0000983 // Shifts src:dst right by cl bits, affecting only dst.
984 void shrd(Register dst, Register src);
ager@chromium.org9085a012009-05-11 19:22:57 +0000985
ager@chromium.orge2902be2009-06-08 12:21:35 +0000986 // Shifts dst right, duplicating sign bit, by shift_amount bits.
987 // Shifting by 1 is handled efficiently.
988 void sar(Register dst, Immediate shift_amount) {
989 shift(dst, shift_amount, 0x7);
990 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000991
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000992 // Shifts dst right, duplicating sign bit, by shift_amount bits.
993 // Shifting by 1 is handled efficiently.
994 void sarl(Register dst, Immediate shift_amount) {
995 shift_32(dst, shift_amount, 0x7);
996 }
997
ager@chromium.orge2902be2009-06-08 12:21:35 +0000998 // Shifts dst right, duplicating sign bit, by cl % 64 bits.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000999 void sar_cl(Register dst) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00001000 shift(dst, 0x7);
1001 }
ager@chromium.org9085a012009-05-11 19:22:57 +00001002
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001003 // Shifts dst right, duplicating sign bit, by cl % 64 bits.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001004 void sarl_cl(Register dst) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001005 shift_32(dst, 0x7);
1006 }
1007
ager@chromium.orge2902be2009-06-08 12:21:35 +00001008 void shl(Register dst, Immediate shift_amount) {
1009 shift(dst, shift_amount, 0x4);
1010 }
ager@chromium.org9085a012009-05-11 19:22:57 +00001011
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001012 void shl_cl(Register dst) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00001013 shift(dst, 0x4);
1014 }
1015
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001016 void shll_cl(Register dst) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001017 shift_32(dst, 0x4);
1018 }
1019
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001020 void shll(Register dst, Immediate shift_amount) {
1021 shift_32(dst, shift_amount, 0x4);
1022 }
1023
ager@chromium.orge2902be2009-06-08 12:21:35 +00001024 void shr(Register dst, Immediate shift_amount) {
1025 shift(dst, shift_amount, 0x5);
1026 }
1027
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001028 void shr_cl(Register dst) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00001029 shift(dst, 0x5);
1030 }
1031
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001032 void shrl_cl(Register dst) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001033 shift_32(dst, 0x5);
1034 }
1035
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001036 void shrl(Register dst, Immediate shift_amount) {
1037 shift_32(dst, shift_amount, 0x5);
1038 }
1039
ager@chromium.orge2902be2009-06-08 12:21:35 +00001040 void store_rax(void* dst, RelocInfo::Mode mode);
1041 void store_rax(ExternalReference ref);
ager@chromium.org9085a012009-05-11 19:22:57 +00001042
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001043 void subq(Register dst, Register src) {
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00001044 arithmetic_op(0x2B, dst, src);
1045 }
ager@chromium.org9085a012009-05-11 19:22:57 +00001046
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001047 void subq(Register dst, const Operand& src) {
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00001048 arithmetic_op(0x2B, dst, src);
1049 }
ager@chromium.org9085a012009-05-11 19:22:57 +00001050
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001051 void subq(const Operand& dst, Register src) {
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00001052 arithmetic_op(0x29, src, dst);
1053 }
1054
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001055 void subq(Register dst, Immediate src) {
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00001056 immediate_arithmetic_op(0x5, dst, src);
1057 }
1058
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001059 void subq(const Operand& dst, Immediate src) {
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00001060 immediate_arithmetic_op(0x5, dst, src);
1061 }
1062
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001063 void subl(Register dst, Register src) {
1064 arithmetic_op_32(0x2B, dst, src);
1065 }
1066
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001067 void subl(Register dst, const Operand& src) {
1068 arithmetic_op_32(0x2B, dst, src);
1069 }
1070
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001071 void subl(const Operand& dst, Immediate src) {
1072 immediate_arithmetic_op_32(0x5, dst, src);
1073 }
1074
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001075 void subl(Register dst, Immediate src) {
1076 immediate_arithmetic_op_32(0x5, dst, src);
1077 }
1078
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001079 void subb(Register dst, Immediate src) {
1080 immediate_arithmetic_op_8(0x5, dst, src);
1081 }
1082
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001083 void testb(Register dst, Register src);
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00001084 void testb(Register reg, Immediate mask);
1085 void testb(const Operand& op, Immediate mask);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001086 void testb(const Operand& op, Register reg);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001087 void testl(Register dst, Register src);
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00001088 void testl(Register reg, Immediate mask);
1089 void testl(const Operand& op, Immediate mask);
ager@chromium.orge2902be2009-06-08 12:21:35 +00001090 void testq(const Operand& op, Register reg);
1091 void testq(Register dst, Register src);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001092 void testq(Register dst, Immediate mask);
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00001093
1094 void xor_(Register dst, Register src) {
ager@chromium.org3811b432009-10-28 14:53:37 +00001095 if (dst.code() == src.code()) {
1096 arithmetic_op_32(0x33, dst, src);
1097 } else {
1098 arithmetic_op(0x33, dst, src);
1099 }
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00001100 }
1101
ager@chromium.org4af710e2009-09-15 12:20:11 +00001102 void xorl(Register dst, Register src) {
1103 arithmetic_op_32(0x33, dst, src);
1104 }
1105
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001106 void xorl(Register dst, const Operand& src) {
1107 arithmetic_op_32(0x33, dst, src);
1108 }
1109
1110 void xorl(Register dst, Immediate src) {
1111 immediate_arithmetic_op_32(0x6, dst, src);
1112 }
1113
1114 void xorl(const Operand& dst, Immediate src) {
1115 immediate_arithmetic_op_32(0x6, dst, src);
1116 }
1117
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00001118 void xor_(Register dst, const Operand& src) {
1119 arithmetic_op(0x33, dst, src);
1120 }
1121
1122 void xor_(const Operand& dst, Register src) {
1123 arithmetic_op(0x31, src, dst);
1124 }
1125
1126 void xor_(Register dst, Immediate src) {
1127 immediate_arithmetic_op(0x6, dst, src);
1128 }
1129
1130 void xor_(const Operand& dst, Immediate src) {
1131 immediate_arithmetic_op(0x6, dst, src);
1132 }
1133
ager@chromium.org9085a012009-05-11 19:22:57 +00001134 // Bit operations.
1135 void bt(const Operand& dst, Register src);
1136 void bts(const Operand& dst, Register src);
1137
1138 // Miscellaneous
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001139 void clc();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001140 void cld();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001141 void cpuid();
ager@chromium.org9085a012009-05-11 19:22:57 +00001142 void hlt();
1143 void int3();
1144 void nop();
ager@chromium.orge2902be2009-06-08 12:21:35 +00001145 void nop(int n);
ager@chromium.org9085a012009-05-11 19:22:57 +00001146 void rdtsc();
1147 void ret(int imm16);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001148 void setcc(Condition cc, Register reg);
ager@chromium.org9085a012009-05-11 19:22:57 +00001149
1150 // Label operations & relative jumps (PPUM Appendix D)
1151 //
1152 // Takes a branch opcode (cc) and a label (L) and generates
1153 // either a backward branch or a forward branch and links it
1154 // to the label fixup chain. Usage:
1155 //
1156 // Label L; // unbound label
1157 // j(cc, &L); // forward branch to unbound label
1158 // bind(&L); // bind label to the current pc
1159 // j(cc, &L); // backward branch to bound label
1160 // bind(&L); // illegal: a label may be bound only once
1161 //
1162 // Note: The same Label can be used for forward and backward branches
1163 // but it may be bound only once.
1164
1165 void bind(Label* L); // binds an unbound label L to the current code position
1166
1167 // Calls
ager@chromium.orge2902be2009-06-08 12:21:35 +00001168 // Call near relative 32-bit displacement, relative to next instruction.
ager@chromium.org9085a012009-05-11 19:22:57 +00001169 void call(Label* L);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001170 void call(Handle<Code> target,
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001171 RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001172 unsigned ast_id = kNoASTId);
ager@chromium.orge2902be2009-06-08 12:21:35 +00001173
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001174 // Calls directly to the given address using a relative offset.
1175 // Should only ever be used in Code objects for calls within the
1176 // same Code object. Should not be used when generating new code (use labels),
1177 // but only when patching existing code.
1178 void call(Address target);
1179
ager@chromium.orge2902be2009-06-08 12:21:35 +00001180 // Call near absolute indirect, address in register
1181 void call(Register adr);
1182
1183 // Call near indirect
1184 void call(const Operand& operand);
ager@chromium.org9085a012009-05-11 19:22:57 +00001185
1186 // Jumps
ager@chromium.orge2902be2009-06-08 12:21:35 +00001187 // Jump short or near relative.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001188 // Use a 32-bit signed displacement.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001189 // Unconditional jump to L
1190 void jmp(Label* L, Label::Distance distance = Label::kFar);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001191 void jmp(Handle<Code> target, RelocInfo::Mode rmode);
ager@chromium.orge2902be2009-06-08 12:21:35 +00001192
1193 // Jump near absolute indirect (r64)
1194 void jmp(Register adr);
ager@chromium.org9085a012009-05-11 19:22:57 +00001195
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001196 // Jump near absolute indirect (m64)
1197 void jmp(const Operand& src);
1198
ager@chromium.org9085a012009-05-11 19:22:57 +00001199 // Conditional jumps
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001200 void j(Condition cc,
1201 Label* L,
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001202 Label::Distance distance = Label::kFar);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001203 void j(Condition cc, Handle<Code> target, RelocInfo::Mode rmode);
ager@chromium.org9085a012009-05-11 19:22:57 +00001204
1205 // Floating-point operations
1206 void fld(int i);
1207
1208 void fld1();
1209 void fldz();
ager@chromium.orgac091b72010-05-05 07:34:42 +00001210 void fldpi();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001211 void fldln2();
ager@chromium.org9085a012009-05-11 19:22:57 +00001212
1213 void fld_s(const Operand& adr);
1214 void fld_d(const Operand& adr);
1215
1216 void fstp_s(const Operand& adr);
1217 void fstp_d(const Operand& adr);
ager@chromium.org3811b432009-10-28 14:53:37 +00001218 void fstp(int index);
ager@chromium.org9085a012009-05-11 19:22:57 +00001219
1220 void fild_s(const Operand& adr);
1221 void fild_d(const Operand& adr);
1222
1223 void fist_s(const Operand& adr);
1224
1225 void fistp_s(const Operand& adr);
1226 void fistp_d(const Operand& adr);
1227
1228 void fisttp_s(const Operand& adr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001229 void fisttp_d(const Operand& adr);
ager@chromium.org9085a012009-05-11 19:22:57 +00001230
1231 void fabs();
1232 void fchs();
1233
1234 void fadd(int i);
1235 void fsub(int i);
1236 void fmul(int i);
1237 void fdiv(int i);
1238
1239 void fisub_s(const Operand& adr);
1240
1241 void faddp(int i = 1);
1242 void fsubp(int i = 1);
1243 void fsubrp(int i = 1);
1244 void fmulp(int i = 1);
1245 void fdivp(int i = 1);
1246 void fprem();
1247 void fprem1();
1248
1249 void fxch(int i = 1);
1250 void fincstp();
1251 void ffree(int i = 0);
1252
1253 void ftst();
1254 void fucomp(int i);
1255 void fucompp();
ager@chromium.org3811b432009-10-28 14:53:37 +00001256 void fucomi(int i);
1257 void fucomip();
1258
ager@chromium.org9085a012009-05-11 19:22:57 +00001259 void fcompp();
1260 void fnstsw_ax();
1261 void fwait();
1262 void fnclex();
1263
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001264 void fsin();
1265 void fcos();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001266 void fyl2x();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001267
ager@chromium.org9085a012009-05-11 19:22:57 +00001268 void frndint();
1269
ager@chromium.org3e875802009-06-29 08:26:34 +00001270 void sahf();
1271
1272 // SSE2 instructions
ager@chromium.org357bf652010-04-12 11:30:10 +00001273 void movd(XMMRegister dst, Register src);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001274 void movd(Register dst, XMMRegister src);
1275 void movq(XMMRegister dst, Register src);
1276 void movq(Register dst, XMMRegister src);
danno@chromium.org160a7b02011-04-18 15:51:38 +00001277 void movq(XMMRegister dst, XMMRegister src);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001278 void extractps(Register dst, XMMRegister src, byte imm8);
ager@chromium.org357bf652010-04-12 11:30:10 +00001279
danno@chromium.org160a7b02011-04-18 15:51:38 +00001280 // Don't use this unless it's important to keep the
1281 // top half of the destination register unchanged.
1282 // Used movaps when moving double values and movq for integer
1283 // values in xmm registers.
ager@chromium.org357bf652010-04-12 11:30:10 +00001284 void movsd(XMMRegister dst, XMMRegister src);
danno@chromium.org160a7b02011-04-18 15:51:38 +00001285
1286 void movsd(const Operand& dst, XMMRegister src);
ager@chromium.org357bf652010-04-12 11:30:10 +00001287 void movsd(XMMRegister dst, const Operand& src);
ager@chromium.org3e875802009-06-29 08:26:34 +00001288
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001289 void movdqa(const Operand& dst, XMMRegister src);
1290 void movdqa(XMMRegister dst, const Operand& src);
1291
danno@chromium.org160a7b02011-04-18 15:51:38 +00001292 void movapd(XMMRegister dst, XMMRegister src);
1293 void movaps(XMMRegister dst, XMMRegister src);
1294
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001295 void movss(XMMRegister dst, const Operand& src);
1296 void movss(const Operand& dst, XMMRegister src);
1297
ager@chromium.org9085a012009-05-11 19:22:57 +00001298 void cvttss2si(Register dst, const Operand& src);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001299 void cvttss2si(Register dst, XMMRegister src);
ager@chromium.org9085a012009-05-11 19:22:57 +00001300 void cvttsd2si(Register dst, const Operand& src);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001301 void cvttsd2si(Register dst, XMMRegister src);
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +00001302 void cvttsd2siq(Register dst, XMMRegister src);
ager@chromium.org9085a012009-05-11 19:22:57 +00001303
ager@chromium.org3e875802009-06-29 08:26:34 +00001304 void cvtlsi2sd(XMMRegister dst, const Operand& src);
1305 void cvtlsi2sd(XMMRegister dst, Register src);
1306 void cvtqsi2sd(XMMRegister dst, const Operand& src);
1307 void cvtqsi2sd(XMMRegister dst, Register src);
ager@chromium.org9085a012009-05-11 19:22:57 +00001308
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001309 void cvtlsi2ss(XMMRegister dst, Register src);
1310
ager@chromium.org357bf652010-04-12 11:30:10 +00001311 void cvtss2sd(XMMRegister dst, XMMRegister src);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001312 void cvtss2sd(XMMRegister dst, const Operand& src);
1313 void cvtsd2ss(XMMRegister dst, XMMRegister src);
1314
1315 void cvtsd2si(Register dst, XMMRegister src);
1316 void cvtsd2siq(Register dst, XMMRegister src);
ager@chromium.org357bf652010-04-12 11:30:10 +00001317
ager@chromium.org9085a012009-05-11 19:22:57 +00001318 void addsd(XMMRegister dst, XMMRegister src);
1319 void subsd(XMMRegister dst, XMMRegister src);
1320 void mulsd(XMMRegister dst, XMMRegister src);
1321 void divsd(XMMRegister dst, XMMRegister src);
1322
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001323 void andpd(XMMRegister dst, XMMRegister src);
1324 void orpd(XMMRegister dst, XMMRegister src);
ager@chromium.org5c838252010-02-19 08:53:10 +00001325 void xorpd(XMMRegister dst, XMMRegister src);
danno@chromium.org160a7b02011-04-18 15:51:38 +00001326 void xorps(XMMRegister dst, XMMRegister src);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001327 void sqrtsd(XMMRegister dst, XMMRegister src);
ager@chromium.org5c838252010-02-19 08:53:10 +00001328
ager@chromium.org5c838252010-02-19 08:53:10 +00001329 void ucomisd(XMMRegister dst, XMMRegister src);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001330 void ucomisd(XMMRegister dst, const Operand& src);
ager@chromium.org3e875802009-06-29 08:26:34 +00001331
danno@chromium.org160a7b02011-04-18 15:51:38 +00001332 enum RoundingMode {
1333 kRoundToNearest = 0x0,
1334 kRoundDown = 0x1,
1335 kRoundUp = 0x2,
1336 kRoundToZero = 0x3
1337 };
1338
1339 void roundsd(XMMRegister dst, XMMRegister src, RoundingMode mode);
1340
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001341 void movmskpd(Register dst, XMMRegister src);
1342
ager@chromium.org357bf652010-04-12 11:30:10 +00001343 // The first argument is the reg field, the second argument is the r/m field.
ager@chromium.org3e875802009-06-29 08:26:34 +00001344 void emit_sse_operand(XMMRegister dst, XMMRegister src);
1345 void emit_sse_operand(XMMRegister reg, const Operand& adr);
1346 void emit_sse_operand(XMMRegister dst, Register src);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001347 void emit_sse_operand(Register dst, XMMRegister src);
ager@chromium.org3e875802009-06-29 08:26:34 +00001348
ager@chromium.org9085a012009-05-11 19:22:57 +00001349 // Debugging
1350 void Print();
1351
1352 // Check the code size generated from label to here.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001353 int SizeOfCodeGeneratedSince(Label* label) {
1354 return pc_offset() - label->pos();
1355 }
ager@chromium.org9085a012009-05-11 19:22:57 +00001356
1357 // Mark address of the ExitJSFrame code.
1358 void RecordJSReturn();
1359
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001360 // Mark address of a debug break slot.
1361 void RecordDebugBreakSlot();
1362
ager@chromium.org9085a012009-05-11 19:22:57 +00001363 // Record a comment relocation entry that can be used by a disassembler.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001364 // Use --code-comments to enable.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001365 void RecordComment(const char* msg, bool force = false);
ager@chromium.org9085a012009-05-11 19:22:57 +00001366
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001367 // Writes a single word of data in the code stream.
1368 // Used for inline tables, e.g., jump-tables.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001369 void db(uint8_t data);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001370 void dd(uint32_t data);
1371
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001372 int pc_offset() const { return static_cast<int>(pc_ - buffer_); }
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001373
1374 PositionsRecorder* positions_recorder() { return &positions_recorder_; }
ager@chromium.org9085a012009-05-11 19:22:57 +00001375
1376 // Check if there is less than kGap bytes available in the buffer.
1377 // If this is the case, we need to grow the buffer before emitting
1378 // an instruction or relocation information.
ager@chromium.org4af710e2009-09-15 12:20:11 +00001379 inline bool buffer_overflow() const {
1380 return pc_ >= reloc_info_writer.pos() - kGap;
1381 }
ager@chromium.org9085a012009-05-11 19:22:57 +00001382
1383 // Get the number of bytes available in the buffer.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001384 inline int available_space() const {
1385 return static_cast<int>(reloc_info_writer.pos() - pc_);
1386 }
ager@chromium.org9085a012009-05-11 19:22:57 +00001387
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001388 static bool IsNop(Address addr) { return *addr == 0x90; }
1389
ager@chromium.org9085a012009-05-11 19:22:57 +00001390 // Avoid overflows for displacements etc.
1391 static const int kMaximalBufferSize = 512*MB;
1392 static const int kMinimalBufferSize = 4*KB;
1393
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001394 protected:
1395 bool emit_debug_code() const { return emit_debug_code_; }
1396
ager@chromium.org9085a012009-05-11 19:22:57 +00001397 private:
1398 byte* addr_at(int pos) { return buffer_ + pos; }
1399 byte byte_at(int pos) { return buffer_[pos]; }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001400 void set_byte_at(int pos, byte value) { buffer_[pos] = value; }
ager@chromium.org9085a012009-05-11 19:22:57 +00001401 uint32_t long_at(int pos) {
1402 return *reinterpret_cast<uint32_t*>(addr_at(pos));
1403 }
1404 void long_at_put(int pos, uint32_t x) {
1405 *reinterpret_cast<uint32_t*>(addr_at(pos)) = x;
1406 }
1407
1408 // code emission
1409 void GrowBuffer();
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00001410
1411 void emit(byte x) { *pc_++ = x; }
1412 inline void emitl(uint32_t x);
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00001413 inline void emitq(uint64_t x, RelocInfo::Mode rmode);
ager@chromium.orge2902be2009-06-08 12:21:35 +00001414 inline void emitw(uint16_t x);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001415 inline void emit_code_target(Handle<Code> target,
1416 RelocInfo::Mode rmode,
1417 unsigned ast_id = kNoASTId);
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00001418 void emit(Immediate x) { emitl(x.value_); }
ager@chromium.org9085a012009-05-11 19:22:57 +00001419
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001420 // Emits a REX prefix that encodes a 64-bit operand size and
1421 // the top bit of both register codes.
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00001422 // High bit of reg goes to REX.R, high bit of rm_reg goes to REX.B.
1423 // REX.W is set.
ager@chromium.org3e875802009-06-29 08:26:34 +00001424 inline void emit_rex_64(XMMRegister reg, Register rm_reg);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001425 inline void emit_rex_64(Register reg, XMMRegister rm_reg);
1426 inline void emit_rex_64(Register reg, Register rm_reg);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001427
1428 // Emits a REX prefix that encodes a 64-bit operand size and
1429 // the top bit of the destination, index, and base register codes.
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00001430 // The high bit of reg is used for REX.R, the high bit of op's base
1431 // register is used for REX.B, and the high bit of op's index register
1432 // is used for REX.X. REX.W is set.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001433 inline void emit_rex_64(Register reg, const Operand& op);
ager@chromium.org3e875802009-06-29 08:26:34 +00001434 inline void emit_rex_64(XMMRegister reg, const Operand& op);
ager@chromium.orge2902be2009-06-08 12:21:35 +00001435
1436 // Emits a REX prefix that encodes a 64-bit operand size and
1437 // the top bit of the register code.
1438 // The high bit of register is used for REX.B.
1439 // REX.W is set and REX.R and REX.X are clear.
1440 inline void emit_rex_64(Register rm_reg);
1441
1442 // Emits a REX prefix that encodes a 64-bit operand size and
1443 // the top bit of the index and base register codes.
1444 // The high bit of op's base register is used for REX.B, and the high
1445 // bit of op's index register is used for REX.X.
1446 // REX.W is set and REX.R clear.
1447 inline void emit_rex_64(const Operand& op);
1448
1449 // Emit a REX prefix that only sets REX.W to choose a 64-bit operand size.
1450 void emit_rex_64() { emit(0x48); }
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00001451
1452 // High bit of reg goes to REX.R, high bit of rm_reg goes to REX.B.
ager@chromium.orge2902be2009-06-08 12:21:35 +00001453 // REX.W is clear.
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00001454 inline void emit_rex_32(Register reg, Register rm_reg);
1455
1456 // The high bit of reg is used for REX.R, the high bit of op's base
1457 // register is used for REX.B, and the high bit of op's index register
1458 // is used for REX.X. REX.W is cleared.
1459 inline void emit_rex_32(Register reg, const Operand& op);
1460
ager@chromium.orge2902be2009-06-08 12:21:35 +00001461 // High bit of rm_reg goes to REX.B.
1462 // REX.W, REX.R and REX.X are clear.
1463 inline void emit_rex_32(Register rm_reg);
1464
1465 // High bit of base goes to REX.B and high bit of index to REX.X.
1466 // REX.W and REX.R are clear.
1467 inline void emit_rex_32(const Operand& op);
1468
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00001469 // High bit of reg goes to REX.R, high bit of rm_reg goes to REX.B.
1470 // REX.W is cleared. If no REX bits are set, no byte is emitted.
1471 inline void emit_optional_rex_32(Register reg, Register rm_reg);
1472
1473 // The high bit of reg is used for REX.R, the high bit of op's base
1474 // register is used for REX.B, and the high bit of op's index register
1475 // is used for REX.X. REX.W is cleared. If no REX bits are set, nothing
1476 // is emitted.
1477 inline void emit_optional_rex_32(Register reg, const Operand& op);
1478
ager@chromium.org3e875802009-06-29 08:26:34 +00001479 // As for emit_optional_rex_32(Register, Register), except that
1480 // the registers are XMM registers.
1481 inline void emit_optional_rex_32(XMMRegister reg, XMMRegister base);
1482
1483 // As for emit_optional_rex_32(Register, Register), except that
ager@chromium.orgac091b72010-05-05 07:34:42 +00001484 // one of the registers is an XMM registers.
ager@chromium.org3e875802009-06-29 08:26:34 +00001485 inline void emit_optional_rex_32(XMMRegister reg, Register base);
1486
ager@chromium.orgac091b72010-05-05 07:34:42 +00001487 // As for emit_optional_rex_32(Register, Register), except that
1488 // one of the registers is an XMM registers.
1489 inline void emit_optional_rex_32(Register reg, XMMRegister base);
1490
ager@chromium.org3e875802009-06-29 08:26:34 +00001491 // As for emit_optional_rex_32(Register, const Operand&), except that
1492 // the register is an XMM register.
1493 inline void emit_optional_rex_32(XMMRegister reg, const Operand& op);
1494
ager@chromium.orge2902be2009-06-08 12:21:35 +00001495 // Optionally do as emit_rex_32(Register) if the register number has
1496 // the high bit set.
1497 inline void emit_optional_rex_32(Register rm_reg);
1498
1499 // Optionally do as emit_rex_32(const Operand&) if the operand register
1500 // numbers have a high bit set.
1501 inline void emit_optional_rex_32(const Operand& op);
1502
1503
1504 // Emit the ModR/M byte, and optionally the SIB byte and
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00001505 // 1- or 4-byte offset for a memory operand. Also encodes
1506 // the second operand of the operation, a register or operation
ager@chromium.orge2902be2009-06-08 12:21:35 +00001507 // subcode, into the reg field of the ModR/M byte.
1508 void emit_operand(Register reg, const Operand& adr) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001509 emit_operand(reg.low_bits(), adr);
ager@chromium.orge2902be2009-06-08 12:21:35 +00001510 }
1511
1512 // Emit the ModR/M byte, and optionally the SIB byte and
1513 // 1- or 4-byte offset for a memory operand. Also used to encode
1514 // a three-bit opcode extension into the ModR/M byte.
1515 void emit_operand(int rm, const Operand& adr);
1516
1517 // Emit a ModR/M byte with registers coded in the reg and rm_reg fields.
1518 void emit_modrm(Register reg, Register rm_reg) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001519 emit(0xC0 | reg.low_bits() << 3 | rm_reg.low_bits());
ager@chromium.orge2902be2009-06-08 12:21:35 +00001520 }
1521
1522 // Emit a ModR/M byte with an operation subcode in the reg field and
1523 // a register in the rm_reg field.
1524 void emit_modrm(int code, Register rm_reg) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001525 ASSERT(is_uint3(code));
1526 emit(0xC0 | code << 3 | rm_reg.low_bits());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00001527 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001528
ager@chromium.org9085a012009-05-11 19:22:57 +00001529 // Emit the code-object-relative offset of the label's position
1530 inline void emit_code_relative_offset(Label* label);
1531
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00001532 // Emit machine code for one of the operations ADD, ADC, SUB, SBC,
1533 // AND, OR, XOR, or CMP. The encodings of these operations are all
1534 // similar, differing just in the opcode or in the reg field of the
ager@chromium.orge2902be2009-06-08 12:21:35 +00001535 // ModR/M byte.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001536 void arithmetic_op_16(byte opcode, Register reg, Register rm_reg);
1537 void arithmetic_op_16(byte opcode, Register reg, const Operand& rm_reg);
1538 void arithmetic_op_32(byte opcode, Register reg, Register rm_reg);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001539 void arithmetic_op_32(byte opcode, Register reg, const Operand& rm_reg);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001540 void arithmetic_op(byte opcode, Register reg, Register rm_reg);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001541 void arithmetic_op(byte opcode, Register reg, const Operand& rm_reg);
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00001542 void immediate_arithmetic_op(byte subcode, Register dst, Immediate src);
1543 void immediate_arithmetic_op(byte subcode, const Operand& dst, Immediate src);
ager@chromium.org3e875802009-06-29 08:26:34 +00001544 // Operate on a byte in memory or register.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001545 void immediate_arithmetic_op_8(byte subcode,
ager@chromium.org3e875802009-06-29 08:26:34 +00001546 Register dst,
1547 Immediate src);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001548 void immediate_arithmetic_op_8(byte subcode,
1549 const Operand& dst,
1550 Immediate src);
1551 // Operate on a word in memory or register.
1552 void immediate_arithmetic_op_16(byte subcode,
1553 Register dst,
1554 Immediate src);
1555 void immediate_arithmetic_op_16(byte subcode,
1556 const Operand& dst,
1557 Immediate src);
1558 // Operate on a 32-bit word in memory or register.
1559 void immediate_arithmetic_op_32(byte subcode,
1560 Register dst,
1561 Immediate src);
1562 void immediate_arithmetic_op_32(byte subcode,
1563 const Operand& dst,
1564 Immediate src);
1565
ager@chromium.orge2902be2009-06-08 12:21:35 +00001566 // Emit machine code for a shift operation.
1567 void shift(Register dst, Immediate shift_amount, int subcode);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001568 void shift_32(Register dst, Immediate shift_amount, int subcode);
ager@chromium.orge2902be2009-06-08 12:21:35 +00001569 // Shift dst by cl % 64 bits.
1570 void shift(Register dst, int subcode);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001571 void shift_32(Register dst, int subcode);
ager@chromium.org9085a012009-05-11 19:22:57 +00001572
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001573 void emit_farith(int b1, int b2, int i);
ager@chromium.org9085a012009-05-11 19:22:57 +00001574
1575 // labels
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001576 // void print(Label* L);
ager@chromium.org9085a012009-05-11 19:22:57 +00001577 void bind_to(Label* L, int pos);
ager@chromium.org9085a012009-05-11 19:22:57 +00001578
ager@chromium.org9085a012009-05-11 19:22:57 +00001579 // record reloc info for current pc_
1580 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
1581
1582 friend class CodePatcher;
1583 friend class EnsureSpace;
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001584 friend class RegExpMacroAssemblerX64;
ager@chromium.org9085a012009-05-11 19:22:57 +00001585
1586 // Code buffer:
1587 // The buffer into which code and relocation info are generated.
1588 byte* buffer_;
1589 int buffer_size_;
1590 // True if the assembler owns the buffer, false if buffer is external.
1591 bool own_buffer_;
1592
1593 // code generation
1594 byte* pc_; // the program counter; moves forward
1595 RelocInfoWriter reloc_info_writer;
1596
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001597 List< Handle<Code> > code_targets_;
ager@chromium.org9085a012009-05-11 19:22:57 +00001598
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001599 PositionsRecorder positions_recorder_;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001600
1601 bool emit_debug_code_;
1602
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001603 friend class PositionsRecorder;
ager@chromium.org9085a012009-05-11 19:22:57 +00001604};
1605
1606
1607// Helper class that ensures that there is enough space for generating
1608// instructions and relocation information. The constructor makes
1609// sure that there is enough space and (in debug mode) the destructor
1610// checks that we did not generate too much.
1611class EnsureSpace BASE_EMBEDDED {
1612 public:
1613 explicit EnsureSpace(Assembler* assembler) : assembler_(assembler) {
ager@chromium.org4af710e2009-09-15 12:20:11 +00001614 if (assembler_->buffer_overflow()) assembler_->GrowBuffer();
ager@chromium.org9085a012009-05-11 19:22:57 +00001615#ifdef DEBUG
1616 space_before_ = assembler_->available_space();
1617#endif
1618 }
1619
1620#ifdef DEBUG
1621 ~EnsureSpace() {
1622 int bytes_generated = space_before_ - assembler_->available_space();
1623 ASSERT(bytes_generated < assembler_->kGap);
1624 }
1625#endif
1626
1627 private:
1628 Assembler* assembler_;
1629#ifdef DEBUG
1630 int space_before_;
1631#endif
1632};
1633
1634} } // namespace v8::internal
1635
1636#endif // V8_X64_ASSEMBLER_X64_H_