blob: 5286788fa72da108f0e1a7bfe22650def98a54ba [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright (c) 1994-2006 Sun Microsystems Inc.
2// All Rights Reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// - Redistributions of source code must retain the above copyright notice,
9// this list of conditions and the following disclaimer.
10//
11// - 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.
30
31// The original source code covered by the above license above has been
32// modified significantly by Google Inc.
33// Copyright 2006-2008 the V8 project authors. All rights reserved.
34
35// A light-weight IA32 Assembler.
36
37#ifndef V8_IA32_ASSEMBLER_IA32_H_
38#define V8_IA32_ASSEMBLER_IA32_H_
39
Steve Blockd0582a62009-12-15 09:54:21 +000040#include "serialize.h"
41
Steve Blocka7e24c12009-10-30 11:49:00 +000042namespace v8 {
43namespace internal {
44
45// CPU Registers.
46//
47// 1) We would prefer to use an enum, but enum values are assignment-
48// compatible with int, which has caused code-generation bugs.
49//
50// 2) We would prefer to use a class instead of a struct but we don't like
51// the register initialization to depend on the particular initialization
52// order (which appears to be different on OS X, Linux, and Windows for the
53// installed versions of C++ we tried). Using a struct permits C-style
54// "initialization". Also, the Register objects cannot be const as this
55// forces initialization stubs in MSVC, making us dependent on initialization
56// order.
57//
58// 3) By not using an enum, we are possibly preventing the compiler from
59// doing certain constant folds, which may significantly reduce the
60// code generated for some assembly instructions (because they boil down
61// to a few constants). If this is a problem, we could change the code
62// such that we use an enum in optimized mode, and the struct in debug
63// mode. This way we get the compile-time error checking in debug mode
64// and best performance in optimized code.
65//
66struct Register {
Kristian Monsen0d5e1162010-09-30 15:31:59 +010067 bool is_valid() const { return 0 <= code_ && code_ < 8; }
68 bool is(Register reg) const { return code_ == reg.code_; }
Steve Blocka7e24c12009-10-30 11:49:00 +000069 // eax, ebx, ecx and edx are byte registers, the rest are not.
Kristian Monsen0d5e1162010-09-30 15:31:59 +010070 bool is_byte_register() const { return code_ <= 3; }
71 int code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +000072 ASSERT(is_valid());
73 return code_;
74 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +010075 int bit() const {
Steve Blocka7e24c12009-10-30 11:49:00 +000076 ASSERT(is_valid());
77 return 1 << code_;
78 }
79
Andrei Popescu31002712010-02-23 13:46:05 +000080 // Unfortunately we can't make this private in a struct.
Steve Blocka7e24c12009-10-30 11:49:00 +000081 int code_;
82};
83
84const Register eax = { 0 };
85const Register ecx = { 1 };
86const Register edx = { 2 };
87const Register ebx = { 3 };
88const Register esp = { 4 };
89const Register ebp = { 5 };
90const Register esi = { 6 };
91const Register edi = { 7 };
92const Register no_reg = { -1 };
93
94
95struct XMMRegister {
Kristian Monsen0d5e1162010-09-30 15:31:59 +010096 bool is_valid() const { return 0 <= code_ && code_ < 8; }
97 int code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +000098 ASSERT(is_valid());
99 return code_;
100 }
101
102 int code_;
103};
104
105const XMMRegister xmm0 = { 0 };
106const XMMRegister xmm1 = { 1 };
107const XMMRegister xmm2 = { 2 };
108const XMMRegister xmm3 = { 3 };
109const XMMRegister xmm4 = { 4 };
110const XMMRegister xmm5 = { 5 };
111const XMMRegister xmm6 = { 6 };
112const XMMRegister xmm7 = { 7 };
113
114enum Condition {
115 // any value < 0 is considered no_condition
116 no_condition = -1,
117
118 overflow = 0,
119 no_overflow = 1,
120 below = 2,
121 above_equal = 3,
122 equal = 4,
123 not_equal = 5,
124 below_equal = 6,
125 above = 7,
126 negative = 8,
127 positive = 9,
128 parity_even = 10,
129 parity_odd = 11,
130 less = 12,
131 greater_equal = 13,
132 less_equal = 14,
133 greater = 15,
134
135 // aliases
136 carry = below,
137 not_carry = above_equal,
138 zero = equal,
139 not_zero = not_equal,
140 sign = negative,
141 not_sign = positive
142};
143
144
145// Returns the equivalent of !cc.
146// Negation of the default no_condition (-1) results in a non-default
147// no_condition value (-2). As long as tests for no_condition check
148// for condition < 0, this will work as expected.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100149inline Condition NegateCondition(Condition cc) {
150 return static_cast<Condition>(cc ^ 1);
151}
152
Steve Blocka7e24c12009-10-30 11:49:00 +0000153
154// Corresponds to transposing the operands of a comparison.
155inline Condition ReverseCondition(Condition cc) {
156 switch (cc) {
157 case below:
158 return above;
159 case above:
160 return below;
161 case above_equal:
162 return below_equal;
163 case below_equal:
164 return above_equal;
165 case less:
166 return greater;
167 case greater:
168 return less;
169 case greater_equal:
170 return less_equal;
171 case less_equal:
172 return greater_equal;
173 default:
174 return cc;
175 };
176}
177
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100178
Steve Blocka7e24c12009-10-30 11:49:00 +0000179enum Hint {
180 no_hint = 0,
181 not_taken = 0x2e,
182 taken = 0x3e
183};
184
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100185
Steve Blocka7e24c12009-10-30 11:49:00 +0000186// The result of negating a hint is as if the corresponding condition
187// were negated by NegateCondition. That is, no_hint is mapped to
188// itself and not_taken and taken are mapped to each other.
189inline Hint NegateHint(Hint hint) {
190 return (hint == no_hint)
191 ? no_hint
192 : ((hint == not_taken) ? taken : not_taken);
193}
194
195
196// -----------------------------------------------------------------------------
197// Machine instruction Immediates
198
199class Immediate BASE_EMBEDDED {
200 public:
201 inline explicit Immediate(int x);
Steve Blocka7e24c12009-10-30 11:49:00 +0000202 inline explicit Immediate(const ExternalReference& ext);
203 inline explicit Immediate(Handle<Object> handle);
204 inline explicit Immediate(Smi* value);
205
206 static Immediate CodeRelativeOffset(Label* label) {
207 return Immediate(label);
208 }
209
210 bool is_zero() const { return x_ == 0 && rmode_ == RelocInfo::NONE; }
211 bool is_int8() const {
212 return -128 <= x_ && x_ < 128 && rmode_ == RelocInfo::NONE;
213 }
214 bool is_int16() const {
215 return -32768 <= x_ && x_ < 32768 && rmode_ == RelocInfo::NONE;
216 }
217
218 private:
219 inline explicit Immediate(Label* value);
220
221 int x_;
222 RelocInfo::Mode rmode_;
223
224 friend class Assembler;
225};
226
227
228// -----------------------------------------------------------------------------
229// Machine instruction Operands
230
231enum ScaleFactor {
232 times_1 = 0,
233 times_2 = 1,
234 times_4 = 2,
235 times_8 = 3,
Leon Clarke4515c472010-02-03 11:58:03 +0000236 times_int_size = times_4,
237 times_half_pointer_size = times_2,
Andrei Popescu402d9372010-02-26 13:31:12 +0000238 times_pointer_size = times_4,
239 times_twice_pointer_size = times_8
Steve Blocka7e24c12009-10-30 11:49:00 +0000240};
241
242
243class Operand BASE_EMBEDDED {
244 public:
245 // reg
246 INLINE(explicit Operand(Register reg));
247
Steve Block6ded16b2010-05-10 14:33:55 +0100248 // XMM reg
249 INLINE(explicit Operand(XMMRegister xmm_reg));
250
Steve Blocka7e24c12009-10-30 11:49:00 +0000251 // [disp/r]
252 INLINE(explicit Operand(int32_t disp, RelocInfo::Mode rmode));
253 // disp only must always be relocated
254
255 // [base + disp/r]
256 explicit Operand(Register base, int32_t disp,
257 RelocInfo::Mode rmode = RelocInfo::NONE);
258
259 // [base + index*scale + disp/r]
260 explicit Operand(Register base,
261 Register index,
262 ScaleFactor scale,
263 int32_t disp,
264 RelocInfo::Mode rmode = RelocInfo::NONE);
265
266 // [index*scale + disp/r]
267 explicit Operand(Register index,
268 ScaleFactor scale,
269 int32_t disp,
270 RelocInfo::Mode rmode = RelocInfo::NONE);
271
272 static Operand StaticVariable(const ExternalReference& ext) {
273 return Operand(reinterpret_cast<int32_t>(ext.address()),
274 RelocInfo::EXTERNAL_REFERENCE);
275 }
276
277 static Operand StaticArray(Register index,
278 ScaleFactor scale,
279 const ExternalReference& arr) {
280 return Operand(index, scale, reinterpret_cast<int32_t>(arr.address()),
281 RelocInfo::EXTERNAL_REFERENCE);
282 }
283
284 // Returns true if this Operand is a wrapper for the specified register.
285 bool is_reg(Register reg) const;
286
287 private:
288 byte buf_[6];
289 // The number of bytes in buf_.
290 unsigned int len_;
291 // Only valid if len_ > 4.
292 RelocInfo::Mode rmode_;
293
294 // Set the ModRM byte without an encoded 'reg' register. The
295 // register is encoded later as part of the emit_operand operation.
296 inline void set_modrm(int mod, Register rm);
297
298 inline void set_sib(ScaleFactor scale, Register index, Register base);
299 inline void set_disp8(int8_t disp);
300 inline void set_dispr(int32_t disp, RelocInfo::Mode rmode);
301
302 friend class Assembler;
303};
304
305
306// -----------------------------------------------------------------------------
307// A Displacement describes the 32bit immediate field of an instruction which
308// may be used together with a Label in order to refer to a yet unknown code
309// position. Displacements stored in the instruction stream are used to describe
310// the instruction and to chain a list of instructions using the same Label.
311// A Displacement contains 2 different fields:
312//
313// next field: position of next displacement in the chain (0 = end of list)
314// type field: instruction type
315//
316// A next value of null (0) indicates the end of a chain (note that there can
317// be no displacement at position zero, because there is always at least one
318// instruction byte before the displacement).
319//
320// Displacement _data field layout
321//
322// |31.....2|1......0|
323// [ next | type |
324
325class Displacement BASE_EMBEDDED {
326 public:
327 enum Type {
328 UNCONDITIONAL_JUMP,
329 CODE_RELATIVE,
330 OTHER
331 };
332
333 int data() const { return data_; }
334 Type type() const { return TypeField::decode(data_); }
335 void next(Label* L) const {
336 int n = NextField::decode(data_);
337 n > 0 ? L->link_to(n) : L->Unuse();
338 }
339 void link_to(Label* L) { init(L, type()); }
340
341 explicit Displacement(int data) { data_ = data; }
342
343 Displacement(Label* L, Type type) { init(L, type); }
344
345 void print() {
346 PrintF("%s (%x) ", (type() == UNCONDITIONAL_JUMP ? "jmp" : "[other]"),
347 NextField::decode(data_));
348 }
349
350 private:
351 int data_;
352
353 class TypeField: public BitField<Type, 0, 2> {};
354 class NextField: public BitField<int, 2, 32-2> {};
355
356 void init(Label* L, Type type);
357};
358
359
360
361// CpuFeatures keeps track of which features are supported by the target CPU.
362// Supported features must be enabled by a Scope before use.
363// Example:
364// if (CpuFeatures::IsSupported(SSE2)) {
365// CpuFeatures::Scope fscope(SSE2);
366// // Generate SSE2 floating point code.
367// } else {
368// // Generate standard x87 floating point code.
369// }
370class CpuFeatures : public AllStatic {
371 public:
Steve Blocka7e24c12009-10-30 11:49:00 +0000372 // Detect features of the target CPU. Set safe defaults if the serializer
373 // is enabled (snapshots must be portable).
374 static void Probe();
375 // Check whether a feature is supported by the target CPU.
Steve Blockd0582a62009-12-15 09:54:21 +0000376 static bool IsSupported(CpuFeature f) {
Steve Block3ce2e202009-11-05 08:53:23 +0000377 if (f == SSE2 && !FLAG_enable_sse2) return false;
378 if (f == SSE3 && !FLAG_enable_sse3) return false;
Ben Murdochf87a2032010-10-22 12:50:53 +0100379 if (f == SSE4_1 && !FLAG_enable_sse4_1) return false;
Steve Block3ce2e202009-11-05 08:53:23 +0000380 if (f == CMOV && !FLAG_enable_cmov) return false;
381 if (f == RDTSC && !FLAG_enable_rdtsc) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000382 return (supported_ & (static_cast<uint64_t>(1) << f)) != 0;
383 }
384 // Check whether a feature is currently enabled.
Steve Blockd0582a62009-12-15 09:54:21 +0000385 static bool IsEnabled(CpuFeature f) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000386 return (enabled_ & (static_cast<uint64_t>(1) << f)) != 0;
387 }
388 // Enable a specified feature within a scope.
389 class Scope BASE_EMBEDDED {
390#ifdef DEBUG
391 public:
Steve Blockd0582a62009-12-15 09:54:21 +0000392 explicit Scope(CpuFeature f) {
393 uint64_t mask = static_cast<uint64_t>(1) << f;
Steve Blocka7e24c12009-10-30 11:49:00 +0000394 ASSERT(CpuFeatures::IsSupported(f));
Steve Blockd0582a62009-12-15 09:54:21 +0000395 ASSERT(!Serializer::enabled() || (found_by_runtime_probing_ & mask) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000396 old_enabled_ = CpuFeatures::enabled_;
Steve Blockd0582a62009-12-15 09:54:21 +0000397 CpuFeatures::enabled_ |= mask;
Steve Blocka7e24c12009-10-30 11:49:00 +0000398 }
399 ~Scope() { CpuFeatures::enabled_ = old_enabled_; }
400 private:
401 uint64_t old_enabled_;
402#else
403 public:
Steve Blockd0582a62009-12-15 09:54:21 +0000404 explicit Scope(CpuFeature f) {}
Steve Blocka7e24c12009-10-30 11:49:00 +0000405#endif
406 };
407 private:
408 static uint64_t supported_;
409 static uint64_t enabled_;
Steve Blockd0582a62009-12-15 09:54:21 +0000410 static uint64_t found_by_runtime_probing_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000411};
412
413
414class Assembler : public Malloced {
415 private:
416 // We check before assembling an instruction that there is sufficient
417 // space to write an instruction and its relocation information.
418 // The relocation writer's position must be kGap bytes above the end of
419 // the generated instructions. This leaves enough space for the
420 // longest possible ia32 instruction, 15 bytes, and the longest possible
421 // relocation information encoding, RelocInfoWriter::kMaxLength == 16.
422 // (There is a 15 byte limit on ia32 instruction length that rules out some
423 // otherwise valid instructions.)
424 // This allows for a single, fast space check per instruction.
425 static const int kGap = 32;
426
427 public:
428 // Create an assembler. Instructions and relocation information are emitted
429 // into a buffer, with the instructions starting from the beginning and the
430 // relocation information starting from the end of the buffer. See CodeDesc
431 // for a detailed comment on the layout (globals.h).
432 //
433 // If the provided buffer is NULL, the assembler allocates and grows its own
434 // buffer, and buffer_size determines the initial buffer size. The buffer is
435 // owned by the assembler and deallocated upon destruction of the assembler.
436 //
437 // If the provided buffer is not NULL, the assembler uses the provided buffer
438 // for code generation and assumes its size to be buffer_size. If the buffer
439 // is too small, a fatal error occurs. No deallocation of the buffer is done
440 // upon destruction of the assembler.
441 Assembler(void* buffer, int buffer_size);
442 ~Assembler();
443
444 // GetCode emits any pending (non-emitted) code and fills the descriptor
445 // desc. GetCode() is idempotent; it returns the same result if no other
446 // Assembler functions are invoked in between GetCode() calls.
447 void GetCode(CodeDesc* desc);
448
449 // Read/Modify the code target in the branch/call instruction at pc.
450 inline static Address target_address_at(Address pc);
451 inline static void set_target_address_at(Address pc, Address target);
452
Steve Blockd0582a62009-12-15 09:54:21 +0000453 // This sets the branch destination (which is in the instruction on x86).
454 // This is for calls and branches within generated code.
455 inline static void set_target_at(Address instruction_payload,
456 Address target) {
457 set_target_address_at(instruction_payload, target);
458 }
459
460 // This sets the branch destination (which is in the instruction on x86).
461 // This is for calls and branches to runtime code.
462 inline static void set_external_target_at(Address instruction_payload,
463 Address target) {
464 set_target_address_at(instruction_payload, target);
465 }
466
467 static const int kCallTargetSize = kPointerSize;
468 static const int kExternalTargetSize = kPointerSize;
469
Steve Blocka7e24c12009-10-30 11:49:00 +0000470 // Distance between the address of the code target in the call instruction
471 // and the return address
472 static const int kCallTargetAddressOffset = kPointerSize;
473 // Distance between start of patched return sequence and the emitted address
474 // to jump to.
475 static const int kPatchReturnSequenceAddressOffset = 1; // JMP imm32.
476
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100477 // Distance between start of patched debug break slot and the emitted address
478 // to jump to.
479 static const int kPatchDebugBreakSlotAddressOffset = 1; // JMP imm32.
480
Steve Blockd0582a62009-12-15 09:54:21 +0000481 static const int kCallInstructionLength = 5;
482 static const int kJSReturnSequenceLength = 6;
Steve Blocka7e24c12009-10-30 11:49:00 +0000483
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100484 // The debug break slot must be able to contain a call instruction.
485 static const int kDebugBreakSlotLength = kCallInstructionLength;
486
Steve Blocka7e24c12009-10-30 11:49:00 +0000487 // ---------------------------------------------------------------------------
488 // Code generation
489 //
490 // - function names correspond one-to-one to ia32 instruction mnemonics
491 // - unless specified otherwise, instructions operate on 32bit operands
492 // - instructions on 8bit (byte) operands/registers have a trailing '_b'
493 // - instructions on 16bit (word) operands/registers have a trailing '_w'
494 // - naming conflicts with C++ keywords are resolved via a trailing '_'
495
496 // NOTE ON INTERFACE: Currently, the interface is not very consistent
497 // in the sense that some operations (e.g. mov()) can be called in more
498 // the one way to generate the same instruction: The Register argument
499 // can in some cases be replaced with an Operand(Register) argument.
500 // This should be cleaned up and made more orthogonal. The questions
501 // is: should we always use Operands instead of Registers where an
502 // Operand is possible, or should we have a Register (overloaded) form
503 // instead? We must be careful to make sure that the selected instruction
504 // is obvious from the parameters to avoid hard-to-find code generation
505 // bugs.
506
507 // Insert the smallest number of nop instructions
508 // possible to align the pc offset to a multiple
509 // of m. m must be a power of 2.
510 void Align(int m);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100511 // Aligns code to something that's optimal for a jump target for the platform.
512 void CodeTargetAlign();
Steve Blocka7e24c12009-10-30 11:49:00 +0000513
514 // Stack
515 void pushad();
516 void popad();
517
518 void pushfd();
519 void popfd();
520
521 void push(const Immediate& x);
522 void push(Register src);
523 void push(const Operand& src);
524 void push(Label* label, RelocInfo::Mode relocation_mode);
525
526 void pop(Register dst);
527 void pop(const Operand& dst);
528
529 void enter(const Immediate& size);
530 void leave();
531
532 // Moves
533 void mov_b(Register dst, const Operand& src);
534 void mov_b(const Operand& dst, int8_t imm8);
535 void mov_b(const Operand& dst, Register src);
536
537 void mov_w(Register dst, const Operand& src);
538 void mov_w(const Operand& dst, Register src);
539
540 void mov(Register dst, int32_t imm32);
541 void mov(Register dst, const Immediate& x);
542 void mov(Register dst, Handle<Object> handle);
543 void mov(Register dst, const Operand& src);
544 void mov(Register dst, Register src);
545 void mov(const Operand& dst, const Immediate& x);
546 void mov(const Operand& dst, Handle<Object> handle);
547 void mov(const Operand& dst, Register src);
548
549 void movsx_b(Register dst, const Operand& src);
550
551 void movsx_w(Register dst, const Operand& src);
552
553 void movzx_b(Register dst, const Operand& src);
554
555 void movzx_w(Register dst, const Operand& src);
556
557 // Conditional moves
558 void cmov(Condition cc, Register dst, int32_t imm32);
559 void cmov(Condition cc, Register dst, Handle<Object> handle);
560 void cmov(Condition cc, Register dst, const Operand& src);
561
Steve Block6ded16b2010-05-10 14:33:55 +0100562 // Flag management.
563 void cld();
564
Leon Clarkee46be812010-01-19 14:06:41 +0000565 // Repetitive string instructions.
566 void rep_movs();
Steve Block6ded16b2010-05-10 14:33:55 +0100567 void rep_stos();
Leon Clarkef7060e22010-06-03 12:02:55 +0100568 void stos();
Leon Clarkee46be812010-01-19 14:06:41 +0000569
Steve Blocka7e24c12009-10-30 11:49:00 +0000570 // Exchange two registers
571 void xchg(Register dst, Register src);
572
573 // Arithmetics
574 void adc(Register dst, int32_t imm32);
575 void adc(Register dst, const Operand& src);
576
577 void add(Register dst, const Operand& src);
578 void add(const Operand& dst, const Immediate& x);
579
580 void and_(Register dst, int32_t imm32);
Steve Block59151502010-09-22 15:07:15 +0100581 void and_(Register dst, const Immediate& x);
Steve Blocka7e24c12009-10-30 11:49:00 +0000582 void and_(Register dst, const Operand& src);
583 void and_(const Operand& src, Register dst);
584 void and_(const Operand& dst, const Immediate& x);
585
586 void cmpb(const Operand& op, int8_t imm8);
Leon Clarked91b9f72010-01-27 17:25:45 +0000587 void cmpb(Register src, const Operand& dst);
588 void cmpb(const Operand& dst, Register src);
Steve Blocka7e24c12009-10-30 11:49:00 +0000589 void cmpb_al(const Operand& op);
590 void cmpw_ax(const Operand& op);
591 void cmpw(const Operand& op, Immediate imm16);
592 void cmp(Register reg, int32_t imm32);
593 void cmp(Register reg, Handle<Object> handle);
594 void cmp(Register reg, const Operand& op);
595 void cmp(const Operand& op, const Immediate& imm);
596 void cmp(const Operand& op, Handle<Object> handle);
597
598 void dec_b(Register dst);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100599 void dec_b(const Operand& dst);
Steve Blocka7e24c12009-10-30 11:49:00 +0000600
601 void dec(Register dst);
602 void dec(const Operand& dst);
603
604 void cdq();
605
606 void idiv(Register src);
607
608 // Signed multiply instructions.
609 void imul(Register src); // edx:eax = eax * src.
610 void imul(Register dst, const Operand& src); // dst = dst * src.
611 void imul(Register dst, Register src, int32_t imm32); // dst = src * imm32.
612
613 void inc(Register dst);
614 void inc(const Operand& dst);
615
616 void lea(Register dst, const Operand& src);
617
618 // Unsigned multiply instruction.
619 void mul(Register src); // edx:eax = eax * reg.
620
621 void neg(Register dst);
622
623 void not_(Register dst);
624
625 void or_(Register dst, int32_t imm32);
626 void or_(Register dst, const Operand& src);
627 void or_(const Operand& dst, Register src);
628 void or_(const Operand& dst, const Immediate& x);
629
630 void rcl(Register dst, uint8_t imm8);
Iain Merrick75681382010-08-19 15:07:18 +0100631 void rcr(Register dst, uint8_t imm8);
Steve Blocka7e24c12009-10-30 11:49:00 +0000632
633 void sar(Register dst, uint8_t imm8);
Steve Blockd0582a62009-12-15 09:54:21 +0000634 void sar_cl(Register dst);
Steve Blocka7e24c12009-10-30 11:49:00 +0000635
636 void sbb(Register dst, const Operand& src);
637
638 void shld(Register dst, const Operand& src);
639
640 void shl(Register dst, uint8_t imm8);
Steve Blockd0582a62009-12-15 09:54:21 +0000641 void shl_cl(Register dst);
Steve Blocka7e24c12009-10-30 11:49:00 +0000642
643 void shrd(Register dst, const Operand& src);
644
645 void shr(Register dst, uint8_t imm8);
Steve Blocka7e24c12009-10-30 11:49:00 +0000646 void shr_cl(Register dst);
647
Steve Block3ce2e202009-11-05 08:53:23 +0000648 void subb(const Operand& dst, int8_t imm8);
Leon Clarkee46be812010-01-19 14:06:41 +0000649 void subb(Register dst, const Operand& src);
Steve Blocka7e24c12009-10-30 11:49:00 +0000650 void sub(const Operand& dst, const Immediate& x);
651 void sub(Register dst, const Operand& src);
652 void sub(const Operand& dst, Register src);
653
654 void test(Register reg, const Immediate& imm);
655 void test(Register reg, const Operand& op);
Leon Clarkee46be812010-01-19 14:06:41 +0000656 void test_b(Register reg, const Operand& op);
Steve Blocka7e24c12009-10-30 11:49:00 +0000657 void test(const Operand& op, const Immediate& imm);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100658 void test_b(const Operand& op, uint8_t imm8);
Steve Blocka7e24c12009-10-30 11:49:00 +0000659
660 void xor_(Register dst, int32_t imm32);
661 void xor_(Register dst, const Operand& src);
662 void xor_(const Operand& src, Register dst);
663 void xor_(const Operand& dst, const Immediate& x);
664
665 // Bit operations.
666 void bt(const Operand& dst, Register src);
667 void bts(const Operand& dst, Register src);
668
669 // Miscellaneous
670 void hlt();
671 void int3();
672 void nop();
673 void rdtsc();
674 void ret(int imm16);
675
676 // Label operations & relative jumps (PPUM Appendix D)
677 //
678 // Takes a branch opcode (cc) and a label (L) and generates
679 // either a backward branch or a forward branch and links it
680 // to the label fixup chain. Usage:
681 //
682 // Label L; // unbound label
683 // j(cc, &L); // forward branch to unbound label
684 // bind(&L); // bind label to the current pc
685 // j(cc, &L); // backward branch to bound label
686 // bind(&L); // illegal: a label may be bound only once
687 //
688 // Note: The same Label can be used for forward and backward branches
689 // but it may be bound only once.
690
691 void bind(Label* L); // binds an unbound label L to the current code position
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100692 void bind(NearLabel* L);
Steve Blocka7e24c12009-10-30 11:49:00 +0000693
694 // Calls
695 void call(Label* L);
696 void call(byte* entry, RelocInfo::Mode rmode);
697 void call(const Operand& adr);
698 void call(Handle<Code> code, RelocInfo::Mode rmode);
699
700 // Jumps
701 void jmp(Label* L); // unconditional jump to L
702 void jmp(byte* entry, RelocInfo::Mode rmode);
703 void jmp(const Operand& adr);
704 void jmp(Handle<Code> code, RelocInfo::Mode rmode);
705
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100706 // Short jump
707 void jmp(NearLabel* L);
708
Steve Blocka7e24c12009-10-30 11:49:00 +0000709 // Conditional jumps
710 void j(Condition cc, Label* L, Hint hint = no_hint);
711 void j(Condition cc, byte* entry, RelocInfo::Mode rmode, Hint hint = no_hint);
712 void j(Condition cc, Handle<Code> code, Hint hint = no_hint);
713
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100714 // Conditional short jump
715 void j(Condition cc, NearLabel* L, Hint hint = no_hint);
716
Steve Blocka7e24c12009-10-30 11:49:00 +0000717 // Floating-point operations
718 void fld(int i);
Andrei Popescu402d9372010-02-26 13:31:12 +0000719 void fstp(int i);
Steve Blocka7e24c12009-10-30 11:49:00 +0000720
721 void fld1();
722 void fldz();
Andrei Popescu402d9372010-02-26 13:31:12 +0000723 void fldpi();
Steve Blocka7e24c12009-10-30 11:49:00 +0000724
725 void fld_s(const Operand& adr);
726 void fld_d(const Operand& adr);
727
728 void fstp_s(const Operand& adr);
729 void fstp_d(const Operand& adr);
Andrei Popescu402d9372010-02-26 13:31:12 +0000730 void fst_d(const Operand& adr);
Steve Blocka7e24c12009-10-30 11:49:00 +0000731
732 void fild_s(const Operand& adr);
733 void fild_d(const Operand& adr);
734
735 void fist_s(const Operand& adr);
736
737 void fistp_s(const Operand& adr);
738 void fistp_d(const Operand& adr);
739
Steve Block6ded16b2010-05-10 14:33:55 +0100740 // The fisttp instructions require SSE3.
Steve Blocka7e24c12009-10-30 11:49:00 +0000741 void fisttp_s(const Operand& adr);
Leon Clarkee46be812010-01-19 14:06:41 +0000742 void fisttp_d(const Operand& adr);
Steve Blocka7e24c12009-10-30 11:49:00 +0000743
744 void fabs();
745 void fchs();
746 void fcos();
747 void fsin();
748
749 void fadd(int i);
750 void fsub(int i);
751 void fmul(int i);
752 void fdiv(int i);
753
754 void fisub_s(const Operand& adr);
755
756 void faddp(int i = 1);
757 void fsubp(int i = 1);
758 void fsubrp(int i = 1);
759 void fmulp(int i = 1);
760 void fdivp(int i = 1);
761 void fprem();
762 void fprem1();
763
764 void fxch(int i = 1);
765 void fincstp();
766 void ffree(int i = 0);
767
768 void ftst();
769 void fucomp(int i);
770 void fucompp();
Steve Block3ce2e202009-11-05 08:53:23 +0000771 void fucomi(int i);
772 void fucomip();
Steve Blocka7e24c12009-10-30 11:49:00 +0000773 void fcompp();
774 void fnstsw_ax();
775 void fwait();
776 void fnclex();
777
778 void frndint();
779
780 void sahf();
781 void setcc(Condition cc, Register reg);
782
783 void cpuid();
784
785 // SSE2 instructions
786 void cvttss2si(Register dst, const Operand& src);
787 void cvttsd2si(Register dst, const Operand& src);
788
789 void cvtsi2sd(XMMRegister dst, const Operand& src);
Steve Block6ded16b2010-05-10 14:33:55 +0100790 void cvtss2sd(XMMRegister dst, XMMRegister src);
Steve Blocka7e24c12009-10-30 11:49:00 +0000791
792 void addsd(XMMRegister dst, XMMRegister src);
793 void subsd(XMMRegister dst, XMMRegister src);
794 void mulsd(XMMRegister dst, XMMRegister src);
795 void divsd(XMMRegister dst, XMMRegister src);
Leon Clarkee46be812010-01-19 14:06:41 +0000796 void xorpd(XMMRegister dst, XMMRegister src);
Steve Block6ded16b2010-05-10 14:33:55 +0100797 void sqrtsd(XMMRegister dst, XMMRegister src);
Steve Blocka7e24c12009-10-30 11:49:00 +0000798
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100799 void andpd(XMMRegister dst, XMMRegister src);
800
Steve Block6ded16b2010-05-10 14:33:55 +0100801 void ucomisd(XMMRegister dst, XMMRegister src);
802 void movmskpd(Register dst, XMMRegister src);
Steve Blocka7e24c12009-10-30 11:49:00 +0000803
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100804 void cmpltsd(XMMRegister dst, XMMRegister src);
805
806 void movaps(XMMRegister dst, XMMRegister src);
807
Leon Clarkee46be812010-01-19 14:06:41 +0000808 void movdqa(XMMRegister dst, const Operand& src);
809 void movdqa(const Operand& dst, XMMRegister src);
810 void movdqu(XMMRegister dst, const Operand& src);
811 void movdqu(const Operand& dst, XMMRegister src);
812
Steve Blocka7e24c12009-10-30 11:49:00 +0000813 // Use either movsd or movlpd.
814 void movdbl(XMMRegister dst, const Operand& src);
815 void movdbl(const Operand& dst, XMMRegister src);
816
Steve Block6ded16b2010-05-10 14:33:55 +0100817 void movd(XMMRegister dst, const Operand& src);
818 void movsd(XMMRegister dst, XMMRegister src);
819
820 void pxor(XMMRegister dst, XMMRegister src);
821 void ptest(XMMRegister dst, XMMRegister src);
822
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100823 void psllq(XMMRegister reg, int8_t imm8);
824
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100825 // Parallel XMM operations.
826 void movntdqa(XMMRegister src, const Operand& dst);
827 void movntdq(const Operand& dst, XMMRegister src);
828 // Prefetch src position into cache level.
829 // Level 1, 2 or 3 specifies CPU cache level. Level 0 specifies a
830 // non-temporal
831 void prefetch(const Operand& src, int level);
832 // TODO(lrn): Need SFENCE for movnt?
833
Steve Blocka7e24c12009-10-30 11:49:00 +0000834 // Debugging
835 void Print();
836
837 // Check the code size generated from label to here.
838 int SizeOfCodeGeneratedSince(Label* l) { return pc_offset() - l->pos(); }
839
840 // Mark address of the ExitJSFrame code.
841 void RecordJSReturn();
842
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100843 // Mark address of a debug break slot.
844 void RecordDebugBreakSlot();
845
Steve Blocka7e24c12009-10-30 11:49:00 +0000846 // Record a comment relocation entry that can be used by a disassembler.
847 // Use --debug_code to enable.
848 void RecordComment(const char* msg);
849
850 void RecordPosition(int pos);
851 void RecordStatementPosition(int pos);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100852 bool WriteRecordedPositions();
Steve Blocka7e24c12009-10-30 11:49:00 +0000853
854 // Writes a single word of data in the code stream.
855 // Used for inline tables, e.g., jump-tables.
856 void dd(uint32_t data, RelocInfo::Mode reloc_info);
857
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100858 int pc_offset() const { return pc_ - buffer_; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000859 int current_statement_position() const { return current_statement_position_; }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100860 int current_position() const { return current_position_; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000861
862 // Check if there is less than kGap bytes available in the buffer.
863 // If this is the case, we need to grow the buffer before emitting
864 // an instruction or relocation information.
865 inline bool overflow() const { return pc_ >= reloc_info_writer.pos() - kGap; }
866
867 // Get the number of bytes available in the buffer.
868 inline int available_space() const { return reloc_info_writer.pos() - pc_; }
869
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100870 static bool IsNop(Address addr) { return *addr == 0x90; }
871
Steve Blocka7e24c12009-10-30 11:49:00 +0000872 // Avoid overflows for displacements etc.
873 static const int kMaximalBufferSize = 512*MB;
874 static const int kMinimalBufferSize = 4*KB;
875
876 protected:
877 void movsd(XMMRegister dst, const Operand& src);
878 void movsd(const Operand& dst, XMMRegister src);
879
880 void emit_sse_operand(XMMRegister reg, const Operand& adr);
881 void emit_sse_operand(XMMRegister dst, XMMRegister src);
Steve Block6ded16b2010-05-10 14:33:55 +0100882 void emit_sse_operand(Register dst, XMMRegister src);
Steve Blocka7e24c12009-10-30 11:49:00 +0000883
884 private:
885 byte* addr_at(int pos) { return buffer_ + pos; }
886 byte byte_at(int pos) { return buffer_[pos]; }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100887 void set_byte_at(int pos, byte value) { buffer_[pos] = value; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000888 uint32_t long_at(int pos) {
889 return *reinterpret_cast<uint32_t*>(addr_at(pos));
890 }
891 void long_at_put(int pos, uint32_t x) {
892 *reinterpret_cast<uint32_t*>(addr_at(pos)) = x;
893 }
894
895 // code emission
896 void GrowBuffer();
897 inline void emit(uint32_t x);
898 inline void emit(Handle<Object> handle);
899 inline void emit(uint32_t x, RelocInfo::Mode rmode);
900 inline void emit(const Immediate& x);
901 inline void emit_w(const Immediate& x);
902
903 // Emit the code-object-relative offset of the label's position
904 inline void emit_code_relative_offset(Label* label);
905
906 // instruction generation
907 void emit_arith_b(int op1, int op2, Register dst, int imm8);
908
909 // Emit a basic arithmetic instruction (i.e. first byte of the family is 0x81)
910 // with a given destination expression and an immediate operand. It attempts
911 // to use the shortest encoding possible.
912 // sel specifies the /n in the modrm byte (see the Intel PRM).
913 void emit_arith(int sel, Operand dst, const Immediate& x);
914
915 void emit_operand(Register reg, const Operand& adr);
916
917 void emit_farith(int b1, int b2, int i);
918
919 // labels
920 void print(Label* L);
921 void bind_to(Label* L, int pos);
Steve Blocka7e24c12009-10-30 11:49:00 +0000922
923 // displacements
924 inline Displacement disp_at(Label* L);
925 inline void disp_at_put(Label* L, Displacement disp);
926 inline void emit_disp(Label* L, Displacement::Type type);
927
928 // record reloc info for current pc_
929 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
930
931 friend class CodePatcher;
932 friend class EnsureSpace;
933
934 // Code buffer:
935 // The buffer into which code and relocation info are generated.
936 byte* buffer_;
937 int buffer_size_;
938 // True if the assembler owns the buffer, false if buffer is external.
939 bool own_buffer_;
940 // A previously allocated buffer of kMinimalBufferSize bytes, or NULL.
941 static byte* spare_buffer_;
942
943 // code generation
944 byte* pc_; // the program counter; moves forward
945 RelocInfoWriter reloc_info_writer;
946
947 // push-pop elimination
948 byte* last_pc_;
949
950 // source position information
951 int current_statement_position_;
952 int current_position_;
953 int written_statement_position_;
954 int written_position_;
955};
956
957
958// Helper class that ensures that there is enough space for generating
959// instructions and relocation information. The constructor makes
960// sure that there is enough space and (in debug mode) the destructor
961// checks that we did not generate too much.
962class EnsureSpace BASE_EMBEDDED {
963 public:
964 explicit EnsureSpace(Assembler* assembler) : assembler_(assembler) {
965 if (assembler_->overflow()) assembler_->GrowBuffer();
966#ifdef DEBUG
967 space_before_ = assembler_->available_space();
968#endif
969 }
970
971#ifdef DEBUG
972 ~EnsureSpace() {
973 int bytes_generated = space_before_ - assembler_->available_space();
974 ASSERT(bytes_generated < assembler_->kGap);
975 }
976#endif
977
978 private:
979 Assembler* assembler_;
980#ifdef DEBUG
981 int space_before_;
982#endif
983};
984
985} } // namespace v8::internal
986
987#endif // V8_IA32_ASSEMBLER_IA32_H_