blob: 20446b0085e4098c5f133b45c1f0ccf72909038b [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.
Ben Murdochb0fe1622011-05-05 13:52:32 +010033// Copyright 2010 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +000034
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 {
Ben Murdochb0fe1622011-05-05 13:52:32 +010067 static const int kNumAllocatableRegisters = 5;
68 static const int kNumRegisters = 8;
69
70 static int ToAllocationIndex(Register reg) {
71 ASSERT(reg.code() < 4 || reg.code() == 7);
72 return (reg.code() == 7) ? 4 : reg.code();
73 }
74
75 static Register FromAllocationIndex(int index) {
76 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
77 return (index == 4) ? from_code(7) : from_code(index);
78 }
79
80 static const char* AllocationIndexToString(int index) {
81 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
82 const char* const names[] = {
83 "eax",
84 "ecx",
85 "edx",
86 "ebx",
87 "edi"
88 };
89 return names[index];
90 }
91
92 static Register from_code(int code) {
93 Register r = { code };
94 return r;
95 }
96 bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; }
Kristian Monsen0d5e1162010-09-30 15:31:59 +010097 bool is(Register reg) const { return code_ == reg.code_; }
Steve Blocka7e24c12009-10-30 11:49:00 +000098 // eax, ebx, ecx and edx are byte registers, the rest are not.
Kristian Monsen0d5e1162010-09-30 15:31:59 +010099 bool is_byte_register() const { return code_ <= 3; }
100 int code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000101 ASSERT(is_valid());
102 return code_;
103 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100104 int bit() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000105 ASSERT(is_valid());
106 return 1 << code_;
107 }
108
Andrei Popescu31002712010-02-23 13:46:05 +0000109 // Unfortunately we can't make this private in a struct.
Steve Blocka7e24c12009-10-30 11:49:00 +0000110 int code_;
111};
112
113const Register eax = { 0 };
114const Register ecx = { 1 };
115const Register edx = { 2 };
116const Register ebx = { 3 };
117const Register esp = { 4 };
118const Register ebp = { 5 };
119const Register esi = { 6 };
120const Register edi = { 7 };
121const Register no_reg = { -1 };
122
123
124struct XMMRegister {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100125 static const int kNumAllocatableRegisters = 7;
126 static const int kNumRegisters = 8;
127
128 static int ToAllocationIndex(XMMRegister reg) {
129 ASSERT(reg.code() != 0);
130 return reg.code() - 1;
131 }
132
133 static XMMRegister FromAllocationIndex(int index) {
134 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
135 return from_code(index + 1);
136 }
137
138 static const char* AllocationIndexToString(int index) {
139 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
140 const char* const names[] = {
141 "xmm1",
142 "xmm2",
143 "xmm3",
144 "xmm4",
145 "xmm5",
146 "xmm6",
147 "xmm7"
148 };
149 return names[index];
150 }
151
152 static XMMRegister from_code(int code) {
153 XMMRegister r = { code };
154 return r;
155 }
156
157 bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; }
158 bool is(XMMRegister reg) const { return code_ == reg.code_; }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100159 int code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000160 ASSERT(is_valid());
161 return code_;
162 }
163
164 int code_;
165};
166
Ben Murdochb0fe1622011-05-05 13:52:32 +0100167
Steve Blocka7e24c12009-10-30 11:49:00 +0000168const XMMRegister xmm0 = { 0 };
169const XMMRegister xmm1 = { 1 };
170const XMMRegister xmm2 = { 2 };
171const XMMRegister xmm3 = { 3 };
172const XMMRegister xmm4 = { 4 };
173const XMMRegister xmm5 = { 5 };
174const XMMRegister xmm6 = { 6 };
175const XMMRegister xmm7 = { 7 };
176
Ben Murdochb0fe1622011-05-05 13:52:32 +0100177
178typedef XMMRegister DoubleRegister;
179
180
181// Index of register used in pusha/popa.
182// Order of pushed registers: EAX, ECX, EDX, EBX, ESP, EBP, ESI, and EDI
183inline int EspIndexForPushAll(Register reg) {
184 return Register::kNumRegisters - 1 - reg.code();
185}
186
187
Steve Blocka7e24c12009-10-30 11:49:00 +0000188enum Condition {
189 // any value < 0 is considered no_condition
190 no_condition = -1,
191
192 overflow = 0,
193 no_overflow = 1,
194 below = 2,
195 above_equal = 3,
196 equal = 4,
197 not_equal = 5,
198 below_equal = 6,
199 above = 7,
200 negative = 8,
201 positive = 9,
202 parity_even = 10,
203 parity_odd = 11,
204 less = 12,
205 greater_equal = 13,
206 less_equal = 14,
207 greater = 15,
208
209 // aliases
210 carry = below,
211 not_carry = above_equal,
212 zero = equal,
213 not_zero = not_equal,
214 sign = negative,
215 not_sign = positive
216};
217
218
219// Returns the equivalent of !cc.
220// Negation of the default no_condition (-1) results in a non-default
221// no_condition value (-2). As long as tests for no_condition check
222// for condition < 0, this will work as expected.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100223inline Condition NegateCondition(Condition cc) {
224 return static_cast<Condition>(cc ^ 1);
225}
226
Steve Blocka7e24c12009-10-30 11:49:00 +0000227
228// Corresponds to transposing the operands of a comparison.
229inline Condition ReverseCondition(Condition cc) {
230 switch (cc) {
231 case below:
232 return above;
233 case above:
234 return below;
235 case above_equal:
236 return below_equal;
237 case below_equal:
238 return above_equal;
239 case less:
240 return greater;
241 case greater:
242 return less;
243 case greater_equal:
244 return less_equal;
245 case less_equal:
246 return greater_equal;
247 default:
248 return cc;
249 };
250}
251
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100252
Steve Blocka7e24c12009-10-30 11:49:00 +0000253enum Hint {
254 no_hint = 0,
255 not_taken = 0x2e,
256 taken = 0x3e
257};
258
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100259
Steve Blocka7e24c12009-10-30 11:49:00 +0000260// The result of negating a hint is as if the corresponding condition
261// were negated by NegateCondition. That is, no_hint is mapped to
262// itself and not_taken and taken are mapped to each other.
263inline Hint NegateHint(Hint hint) {
264 return (hint == no_hint)
265 ? no_hint
266 : ((hint == not_taken) ? taken : not_taken);
267}
268
269
270// -----------------------------------------------------------------------------
271// Machine instruction Immediates
272
273class Immediate BASE_EMBEDDED {
274 public:
275 inline explicit Immediate(int x);
Steve Blocka7e24c12009-10-30 11:49:00 +0000276 inline explicit Immediate(const ExternalReference& ext);
277 inline explicit Immediate(Handle<Object> handle);
278 inline explicit Immediate(Smi* value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100279 inline explicit Immediate(Address addr);
Steve Blocka7e24c12009-10-30 11:49:00 +0000280
281 static Immediate CodeRelativeOffset(Label* label) {
282 return Immediate(label);
283 }
284
285 bool is_zero() const { return x_ == 0 && rmode_ == RelocInfo::NONE; }
286 bool is_int8() const {
287 return -128 <= x_ && x_ < 128 && rmode_ == RelocInfo::NONE;
288 }
289 bool is_int16() const {
290 return -32768 <= x_ && x_ < 32768 && rmode_ == RelocInfo::NONE;
291 }
292
293 private:
294 inline explicit Immediate(Label* value);
295
296 int x_;
297 RelocInfo::Mode rmode_;
298
299 friend class Assembler;
300};
301
302
303// -----------------------------------------------------------------------------
304// Machine instruction Operands
305
306enum ScaleFactor {
307 times_1 = 0,
308 times_2 = 1,
309 times_4 = 2,
310 times_8 = 3,
Leon Clarke4515c472010-02-03 11:58:03 +0000311 times_int_size = times_4,
312 times_half_pointer_size = times_2,
Andrei Popescu402d9372010-02-26 13:31:12 +0000313 times_pointer_size = times_4,
314 times_twice_pointer_size = times_8
Steve Blocka7e24c12009-10-30 11:49:00 +0000315};
316
317
318class Operand BASE_EMBEDDED {
319 public:
320 // reg
321 INLINE(explicit Operand(Register reg));
322
Steve Block6ded16b2010-05-10 14:33:55 +0100323 // XMM reg
324 INLINE(explicit Operand(XMMRegister xmm_reg));
325
Steve Blocka7e24c12009-10-30 11:49:00 +0000326 // [disp/r]
327 INLINE(explicit Operand(int32_t disp, RelocInfo::Mode rmode));
328 // disp only must always be relocated
329
330 // [base + disp/r]
331 explicit Operand(Register base, int32_t disp,
332 RelocInfo::Mode rmode = RelocInfo::NONE);
333
334 // [base + index*scale + disp/r]
335 explicit Operand(Register base,
336 Register index,
337 ScaleFactor scale,
338 int32_t disp,
339 RelocInfo::Mode rmode = RelocInfo::NONE);
340
341 // [index*scale + disp/r]
342 explicit Operand(Register index,
343 ScaleFactor scale,
344 int32_t disp,
345 RelocInfo::Mode rmode = RelocInfo::NONE);
346
347 static Operand StaticVariable(const ExternalReference& ext) {
348 return Operand(reinterpret_cast<int32_t>(ext.address()),
349 RelocInfo::EXTERNAL_REFERENCE);
350 }
351
352 static Operand StaticArray(Register index,
353 ScaleFactor scale,
354 const ExternalReference& arr) {
355 return Operand(index, scale, reinterpret_cast<int32_t>(arr.address()),
356 RelocInfo::EXTERNAL_REFERENCE);
357 }
358
Ben Murdochb0fe1622011-05-05 13:52:32 +0100359 static Operand Cell(Handle<JSGlobalPropertyCell> cell) {
360 return Operand(reinterpret_cast<int32_t>(cell.location()),
361 RelocInfo::GLOBAL_PROPERTY_CELL);
362 }
363
Steve Blocka7e24c12009-10-30 11:49:00 +0000364 // Returns true if this Operand is a wrapper for the specified register.
365 bool is_reg(Register reg) const;
366
367 private:
368 byte buf_[6];
369 // The number of bytes in buf_.
370 unsigned int len_;
371 // Only valid if len_ > 4.
372 RelocInfo::Mode rmode_;
373
374 // Set the ModRM byte without an encoded 'reg' register. The
375 // register is encoded later as part of the emit_operand operation.
376 inline void set_modrm(int mod, Register rm);
377
378 inline void set_sib(ScaleFactor scale, Register index, Register base);
379 inline void set_disp8(int8_t disp);
380 inline void set_dispr(int32_t disp, RelocInfo::Mode rmode);
381
382 friend class Assembler;
383};
384
385
386// -----------------------------------------------------------------------------
387// A Displacement describes the 32bit immediate field of an instruction which
388// may be used together with a Label in order to refer to a yet unknown code
389// position. Displacements stored in the instruction stream are used to describe
390// the instruction and to chain a list of instructions using the same Label.
391// A Displacement contains 2 different fields:
392//
393// next field: position of next displacement in the chain (0 = end of list)
394// type field: instruction type
395//
396// A next value of null (0) indicates the end of a chain (note that there can
397// be no displacement at position zero, because there is always at least one
398// instruction byte before the displacement).
399//
400// Displacement _data field layout
401//
402// |31.....2|1......0|
403// [ next | type |
404
405class Displacement BASE_EMBEDDED {
406 public:
407 enum Type {
408 UNCONDITIONAL_JUMP,
409 CODE_RELATIVE,
410 OTHER
411 };
412
413 int data() const { return data_; }
414 Type type() const { return TypeField::decode(data_); }
415 void next(Label* L) const {
416 int n = NextField::decode(data_);
417 n > 0 ? L->link_to(n) : L->Unuse();
418 }
419 void link_to(Label* L) { init(L, type()); }
420
421 explicit Displacement(int data) { data_ = data; }
422
423 Displacement(Label* L, Type type) { init(L, type); }
424
425 void print() {
426 PrintF("%s (%x) ", (type() == UNCONDITIONAL_JUMP ? "jmp" : "[other]"),
427 NextField::decode(data_));
428 }
429
430 private:
431 int data_;
432
433 class TypeField: public BitField<Type, 0, 2> {};
434 class NextField: public BitField<int, 2, 32-2> {};
435
436 void init(Label* L, Type type);
437};
438
439
440
441// CpuFeatures keeps track of which features are supported by the target CPU.
442// Supported features must be enabled by a Scope before use.
443// Example:
444// if (CpuFeatures::IsSupported(SSE2)) {
445// CpuFeatures::Scope fscope(SSE2);
446// // Generate SSE2 floating point code.
447// } else {
448// // Generate standard x87 floating point code.
449// }
450class CpuFeatures : public AllStatic {
451 public:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100452 // Detect features of the target CPU. If the portable flag is set,
453 // the method sets safe defaults if the serializer is enabled
454 // (snapshots must be portable).
455 static void Probe(bool portable);
456 static void Clear() { supported_ = 0; }
457
Steve Blocka7e24c12009-10-30 11:49:00 +0000458 // Check whether a feature is supported by the target CPU.
Steve Blockd0582a62009-12-15 09:54:21 +0000459 static bool IsSupported(CpuFeature f) {
Steve Block3ce2e202009-11-05 08:53:23 +0000460 if (f == SSE2 && !FLAG_enable_sse2) return false;
461 if (f == SSE3 && !FLAG_enable_sse3) return false;
Ben Murdochf87a2032010-10-22 12:50:53 +0100462 if (f == SSE4_1 && !FLAG_enable_sse4_1) return false;
Steve Block3ce2e202009-11-05 08:53:23 +0000463 if (f == CMOV && !FLAG_enable_cmov) return false;
464 if (f == RDTSC && !FLAG_enable_rdtsc) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000465 return (supported_ & (static_cast<uint64_t>(1) << f)) != 0;
466 }
467 // Check whether a feature is currently enabled.
Steve Blockd0582a62009-12-15 09:54:21 +0000468 static bool IsEnabled(CpuFeature f) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000469 return (enabled_ & (static_cast<uint64_t>(1) << f)) != 0;
470 }
471 // Enable a specified feature within a scope.
472 class Scope BASE_EMBEDDED {
473#ifdef DEBUG
474 public:
Steve Blockd0582a62009-12-15 09:54:21 +0000475 explicit Scope(CpuFeature f) {
476 uint64_t mask = static_cast<uint64_t>(1) << f;
Steve Blocka7e24c12009-10-30 11:49:00 +0000477 ASSERT(CpuFeatures::IsSupported(f));
Steve Blockd0582a62009-12-15 09:54:21 +0000478 ASSERT(!Serializer::enabled() || (found_by_runtime_probing_ & mask) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000479 old_enabled_ = CpuFeatures::enabled_;
Steve Blockd0582a62009-12-15 09:54:21 +0000480 CpuFeatures::enabled_ |= mask;
Steve Blocka7e24c12009-10-30 11:49:00 +0000481 }
482 ~Scope() { CpuFeatures::enabled_ = old_enabled_; }
483 private:
484 uint64_t old_enabled_;
485#else
486 public:
Steve Blockd0582a62009-12-15 09:54:21 +0000487 explicit Scope(CpuFeature f) {}
Steve Blocka7e24c12009-10-30 11:49:00 +0000488#endif
489 };
490 private:
491 static uint64_t supported_;
492 static uint64_t enabled_;
Steve Blockd0582a62009-12-15 09:54:21 +0000493 static uint64_t found_by_runtime_probing_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000494};
495
496
497class Assembler : public Malloced {
498 private:
499 // We check before assembling an instruction that there is sufficient
500 // space to write an instruction and its relocation information.
501 // The relocation writer's position must be kGap bytes above the end of
502 // the generated instructions. This leaves enough space for the
503 // longest possible ia32 instruction, 15 bytes, and the longest possible
504 // relocation information encoding, RelocInfoWriter::kMaxLength == 16.
505 // (There is a 15 byte limit on ia32 instruction length that rules out some
506 // otherwise valid instructions.)
507 // This allows for a single, fast space check per instruction.
508 static const int kGap = 32;
509
510 public:
511 // Create an assembler. Instructions and relocation information are emitted
512 // into a buffer, with the instructions starting from the beginning and the
513 // relocation information starting from the end of the buffer. See CodeDesc
514 // for a detailed comment on the layout (globals.h).
515 //
516 // If the provided buffer is NULL, the assembler allocates and grows its own
517 // buffer, and buffer_size determines the initial buffer size. The buffer is
518 // owned by the assembler and deallocated upon destruction of the assembler.
519 //
520 // If the provided buffer is not NULL, the assembler uses the provided buffer
521 // for code generation and assumes its size to be buffer_size. If the buffer
522 // is too small, a fatal error occurs. No deallocation of the buffer is done
523 // upon destruction of the assembler.
524 Assembler(void* buffer, int buffer_size);
525 ~Assembler();
526
527 // GetCode emits any pending (non-emitted) code and fills the descriptor
528 // desc. GetCode() is idempotent; it returns the same result if no other
529 // Assembler functions are invoked in between GetCode() calls.
530 void GetCode(CodeDesc* desc);
531
532 // Read/Modify the code target in the branch/call instruction at pc.
533 inline static Address target_address_at(Address pc);
534 inline static void set_target_address_at(Address pc, Address target);
535
Steve Blockd0582a62009-12-15 09:54:21 +0000536 // This sets the branch destination (which is in the instruction on x86).
537 // This is for calls and branches within generated code.
538 inline static void set_target_at(Address instruction_payload,
539 Address target) {
540 set_target_address_at(instruction_payload, target);
541 }
542
543 // This sets the branch destination (which is in the instruction on x86).
544 // This is for calls and branches to runtime code.
545 inline static void set_external_target_at(Address instruction_payload,
546 Address target) {
547 set_target_address_at(instruction_payload, target);
548 }
549
550 static const int kCallTargetSize = kPointerSize;
551 static const int kExternalTargetSize = kPointerSize;
552
Steve Blocka7e24c12009-10-30 11:49:00 +0000553 // Distance between the address of the code target in the call instruction
554 // and the return address
555 static const int kCallTargetAddressOffset = kPointerSize;
556 // Distance between start of patched return sequence and the emitted address
557 // to jump to.
558 static const int kPatchReturnSequenceAddressOffset = 1; // JMP imm32.
559
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100560 // Distance between start of patched debug break slot and the emitted address
561 // to jump to.
562 static const int kPatchDebugBreakSlotAddressOffset = 1; // JMP imm32.
563
Steve Blockd0582a62009-12-15 09:54:21 +0000564 static const int kCallInstructionLength = 5;
565 static const int kJSReturnSequenceLength = 6;
Steve Blocka7e24c12009-10-30 11:49:00 +0000566
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100567 // The debug break slot must be able to contain a call instruction.
568 static const int kDebugBreakSlotLength = kCallInstructionLength;
569
Ben Murdochb0fe1622011-05-05 13:52:32 +0100570 // One byte opcode for test eax,0xXXXXXXXX.
571 static const byte kTestEaxByte = 0xA9;
572 // One byte opcode for test al, 0xXX.
573 static const byte kTestAlByte = 0xA8;
574 // One byte opcode for nop.
575 static const byte kNopByte = 0x90;
576
577 // One byte opcode for a short unconditional jump.
578 static const byte kJmpShortOpcode = 0xEB;
579 // One byte prefix for a short conditional jump.
580 static const byte kJccShortPrefix = 0x70;
581 static const byte kJncShortOpcode = kJccShortPrefix | not_carry;
582 static const byte kJcShortOpcode = kJccShortPrefix | carry;
583
Steve Blocka7e24c12009-10-30 11:49:00 +0000584 // ---------------------------------------------------------------------------
585 // Code generation
586 //
587 // - function names correspond one-to-one to ia32 instruction mnemonics
588 // - unless specified otherwise, instructions operate on 32bit operands
589 // - instructions on 8bit (byte) operands/registers have a trailing '_b'
590 // - instructions on 16bit (word) operands/registers have a trailing '_w'
591 // - naming conflicts with C++ keywords are resolved via a trailing '_'
592
593 // NOTE ON INTERFACE: Currently, the interface is not very consistent
594 // in the sense that some operations (e.g. mov()) can be called in more
595 // the one way to generate the same instruction: The Register argument
596 // can in some cases be replaced with an Operand(Register) argument.
597 // This should be cleaned up and made more orthogonal. The questions
598 // is: should we always use Operands instead of Registers where an
599 // Operand is possible, or should we have a Register (overloaded) form
600 // instead? We must be careful to make sure that the selected instruction
601 // is obvious from the parameters to avoid hard-to-find code generation
602 // bugs.
603
604 // Insert the smallest number of nop instructions
605 // possible to align the pc offset to a multiple
606 // of m. m must be a power of 2.
607 void Align(int m);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100608 // Aligns code to something that's optimal for a jump target for the platform.
609 void CodeTargetAlign();
Steve Blocka7e24c12009-10-30 11:49:00 +0000610
611 // Stack
612 void pushad();
613 void popad();
614
615 void pushfd();
616 void popfd();
617
618 void push(const Immediate& x);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100619 void push_imm32(int32_t imm32);
Steve Blocka7e24c12009-10-30 11:49:00 +0000620 void push(Register src);
621 void push(const Operand& src);
Steve Blocka7e24c12009-10-30 11:49:00 +0000622
623 void pop(Register dst);
624 void pop(const Operand& dst);
625
626 void enter(const Immediate& size);
627 void leave();
628
629 // Moves
630 void mov_b(Register dst, const Operand& src);
631 void mov_b(const Operand& dst, int8_t imm8);
632 void mov_b(const Operand& dst, Register src);
633
634 void mov_w(Register dst, const Operand& src);
635 void mov_w(const Operand& dst, Register src);
636
637 void mov(Register dst, int32_t imm32);
638 void mov(Register dst, const Immediate& x);
639 void mov(Register dst, Handle<Object> handle);
640 void mov(Register dst, const Operand& src);
641 void mov(Register dst, Register src);
642 void mov(const Operand& dst, const Immediate& x);
643 void mov(const Operand& dst, Handle<Object> handle);
644 void mov(const Operand& dst, Register src);
645
646 void movsx_b(Register dst, const Operand& src);
647
648 void movsx_w(Register dst, const Operand& src);
649
650 void movzx_b(Register dst, const Operand& src);
651
652 void movzx_w(Register dst, const Operand& src);
653
654 // Conditional moves
655 void cmov(Condition cc, Register dst, int32_t imm32);
656 void cmov(Condition cc, Register dst, Handle<Object> handle);
657 void cmov(Condition cc, Register dst, const Operand& src);
658
Steve Block6ded16b2010-05-10 14:33:55 +0100659 // Flag management.
660 void cld();
661
Leon Clarkee46be812010-01-19 14:06:41 +0000662 // Repetitive string instructions.
663 void rep_movs();
Steve Block6ded16b2010-05-10 14:33:55 +0100664 void rep_stos();
Leon Clarkef7060e22010-06-03 12:02:55 +0100665 void stos();
Leon Clarkee46be812010-01-19 14:06:41 +0000666
Steve Blocka7e24c12009-10-30 11:49:00 +0000667 // Exchange two registers
668 void xchg(Register dst, Register src);
669
670 // Arithmetics
671 void adc(Register dst, int32_t imm32);
672 void adc(Register dst, const Operand& src);
673
674 void add(Register dst, const Operand& src);
675 void add(const Operand& dst, const Immediate& x);
676
677 void and_(Register dst, int32_t imm32);
Steve Block59151502010-09-22 15:07:15 +0100678 void and_(Register dst, const Immediate& x);
Steve Blocka7e24c12009-10-30 11:49:00 +0000679 void and_(Register dst, const Operand& src);
680 void and_(const Operand& src, Register dst);
681 void and_(const Operand& dst, const Immediate& x);
682
683 void cmpb(const Operand& op, int8_t imm8);
Leon Clarked91b9f72010-01-27 17:25:45 +0000684 void cmpb(Register src, const Operand& dst);
685 void cmpb(const Operand& dst, Register src);
Steve Blocka7e24c12009-10-30 11:49:00 +0000686 void cmpb_al(const Operand& op);
687 void cmpw_ax(const Operand& op);
688 void cmpw(const Operand& op, Immediate imm16);
689 void cmp(Register reg, int32_t imm32);
690 void cmp(Register reg, Handle<Object> handle);
691 void cmp(Register reg, const Operand& op);
692 void cmp(const Operand& op, const Immediate& imm);
693 void cmp(const Operand& op, Handle<Object> handle);
694
695 void dec_b(Register dst);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100696 void dec_b(const Operand& dst);
Steve Blocka7e24c12009-10-30 11:49:00 +0000697
698 void dec(Register dst);
699 void dec(const Operand& dst);
700
701 void cdq();
702
703 void idiv(Register src);
704
705 // Signed multiply instructions.
706 void imul(Register src); // edx:eax = eax * src.
707 void imul(Register dst, const Operand& src); // dst = dst * src.
708 void imul(Register dst, Register src, int32_t imm32); // dst = src * imm32.
709
710 void inc(Register dst);
711 void inc(const Operand& dst);
712
713 void lea(Register dst, const Operand& src);
714
715 // Unsigned multiply instruction.
716 void mul(Register src); // edx:eax = eax * reg.
717
718 void neg(Register dst);
719
720 void not_(Register dst);
721
722 void or_(Register dst, int32_t imm32);
723 void or_(Register dst, const Operand& src);
724 void or_(const Operand& dst, Register src);
725 void or_(const Operand& dst, const Immediate& x);
726
727 void rcl(Register dst, uint8_t imm8);
Iain Merrick75681382010-08-19 15:07:18 +0100728 void rcr(Register dst, uint8_t imm8);
Steve Blocka7e24c12009-10-30 11:49:00 +0000729
730 void sar(Register dst, uint8_t imm8);
Steve Blockd0582a62009-12-15 09:54:21 +0000731 void sar_cl(Register dst);
Steve Blocka7e24c12009-10-30 11:49:00 +0000732
733 void sbb(Register dst, const Operand& src);
734
735 void shld(Register dst, const Operand& src);
736
737 void shl(Register dst, uint8_t imm8);
Steve Blockd0582a62009-12-15 09:54:21 +0000738 void shl_cl(Register dst);
Steve Blocka7e24c12009-10-30 11:49:00 +0000739
740 void shrd(Register dst, const Operand& src);
741
742 void shr(Register dst, uint8_t imm8);
Steve Blocka7e24c12009-10-30 11:49:00 +0000743 void shr_cl(Register dst);
744
Steve Block3ce2e202009-11-05 08:53:23 +0000745 void subb(const Operand& dst, int8_t imm8);
Leon Clarkee46be812010-01-19 14:06:41 +0000746 void subb(Register dst, const Operand& src);
Steve Blocka7e24c12009-10-30 11:49:00 +0000747 void sub(const Operand& dst, const Immediate& x);
748 void sub(Register dst, const Operand& src);
749 void sub(const Operand& dst, Register src);
750
751 void test(Register reg, const Immediate& imm);
752 void test(Register reg, const Operand& op);
Leon Clarkee46be812010-01-19 14:06:41 +0000753 void test_b(Register reg, const Operand& op);
Steve Blocka7e24c12009-10-30 11:49:00 +0000754 void test(const Operand& op, const Immediate& imm);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100755 void test_b(const Operand& op, uint8_t imm8);
Steve Blocka7e24c12009-10-30 11:49:00 +0000756
757 void xor_(Register dst, int32_t imm32);
758 void xor_(Register dst, const Operand& src);
759 void xor_(const Operand& src, Register dst);
760 void xor_(const Operand& dst, const Immediate& x);
761
762 // Bit operations.
763 void bt(const Operand& dst, Register src);
764 void bts(const Operand& dst, Register src);
765
766 // Miscellaneous
767 void hlt();
768 void int3();
769 void nop();
770 void rdtsc();
771 void ret(int imm16);
772
773 // Label operations & relative jumps (PPUM Appendix D)
774 //
775 // Takes a branch opcode (cc) and a label (L) and generates
776 // either a backward branch or a forward branch and links it
777 // to the label fixup chain. Usage:
778 //
779 // Label L; // unbound label
780 // j(cc, &L); // forward branch to unbound label
781 // bind(&L); // bind label to the current pc
782 // j(cc, &L); // backward branch to bound label
783 // bind(&L); // illegal: a label may be bound only once
784 //
785 // Note: The same Label can be used for forward and backward branches
786 // but it may be bound only once.
787
788 void bind(Label* L); // binds an unbound label L to the current code position
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100789 void bind(NearLabel* L);
Steve Blocka7e24c12009-10-30 11:49:00 +0000790
791 // Calls
792 void call(Label* L);
793 void call(byte* entry, RelocInfo::Mode rmode);
794 void call(const Operand& adr);
795 void call(Handle<Code> code, RelocInfo::Mode rmode);
796
797 // Jumps
798 void jmp(Label* L); // unconditional jump to L
799 void jmp(byte* entry, RelocInfo::Mode rmode);
800 void jmp(const Operand& adr);
801 void jmp(Handle<Code> code, RelocInfo::Mode rmode);
802
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100803 // Short jump
804 void jmp(NearLabel* L);
805
Steve Blocka7e24c12009-10-30 11:49:00 +0000806 // Conditional jumps
807 void j(Condition cc, Label* L, Hint hint = no_hint);
808 void j(Condition cc, byte* entry, RelocInfo::Mode rmode, Hint hint = no_hint);
809 void j(Condition cc, Handle<Code> code, Hint hint = no_hint);
810
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100811 // Conditional short jump
812 void j(Condition cc, NearLabel* L, Hint hint = no_hint);
813
Steve Blocka7e24c12009-10-30 11:49:00 +0000814 // Floating-point operations
815 void fld(int i);
Andrei Popescu402d9372010-02-26 13:31:12 +0000816 void fstp(int i);
Steve Blocka7e24c12009-10-30 11:49:00 +0000817
818 void fld1();
819 void fldz();
Andrei Popescu402d9372010-02-26 13:31:12 +0000820 void fldpi();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100821 void fldln2();
Steve Blocka7e24c12009-10-30 11:49:00 +0000822
823 void fld_s(const Operand& adr);
824 void fld_d(const Operand& adr);
825
826 void fstp_s(const Operand& adr);
827 void fstp_d(const Operand& adr);
Andrei Popescu402d9372010-02-26 13:31:12 +0000828 void fst_d(const Operand& adr);
Steve Blocka7e24c12009-10-30 11:49:00 +0000829
830 void fild_s(const Operand& adr);
831 void fild_d(const Operand& adr);
832
833 void fist_s(const Operand& adr);
834
835 void fistp_s(const Operand& adr);
836 void fistp_d(const Operand& adr);
837
Steve Block6ded16b2010-05-10 14:33:55 +0100838 // The fisttp instructions require SSE3.
Steve Blocka7e24c12009-10-30 11:49:00 +0000839 void fisttp_s(const Operand& adr);
Leon Clarkee46be812010-01-19 14:06:41 +0000840 void fisttp_d(const Operand& adr);
Steve Blocka7e24c12009-10-30 11:49:00 +0000841
842 void fabs();
843 void fchs();
844 void fcos();
845 void fsin();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100846 void fyl2x();
Steve Blocka7e24c12009-10-30 11:49:00 +0000847
848 void fadd(int i);
849 void fsub(int i);
850 void fmul(int i);
851 void fdiv(int i);
852
853 void fisub_s(const Operand& adr);
854
855 void faddp(int i = 1);
856 void fsubp(int i = 1);
857 void fsubrp(int i = 1);
858 void fmulp(int i = 1);
859 void fdivp(int i = 1);
860 void fprem();
861 void fprem1();
862
863 void fxch(int i = 1);
864 void fincstp();
865 void ffree(int i = 0);
866
867 void ftst();
868 void fucomp(int i);
869 void fucompp();
Steve Block3ce2e202009-11-05 08:53:23 +0000870 void fucomi(int i);
871 void fucomip();
Steve Blocka7e24c12009-10-30 11:49:00 +0000872 void fcompp();
873 void fnstsw_ax();
874 void fwait();
875 void fnclex();
876
877 void frndint();
878
879 void sahf();
880 void setcc(Condition cc, Register reg);
881
882 void cpuid();
883
884 // SSE2 instructions
885 void cvttss2si(Register dst, const Operand& src);
886 void cvttsd2si(Register dst, const Operand& src);
887
888 void cvtsi2sd(XMMRegister dst, const Operand& src);
Steve Block6ded16b2010-05-10 14:33:55 +0100889 void cvtss2sd(XMMRegister dst, XMMRegister src);
Steve Blocka7e24c12009-10-30 11:49:00 +0000890
891 void addsd(XMMRegister dst, XMMRegister src);
892 void subsd(XMMRegister dst, XMMRegister src);
893 void mulsd(XMMRegister dst, XMMRegister src);
894 void divsd(XMMRegister dst, XMMRegister src);
Leon Clarkee46be812010-01-19 14:06:41 +0000895 void xorpd(XMMRegister dst, XMMRegister src);
Steve Block6ded16b2010-05-10 14:33:55 +0100896 void sqrtsd(XMMRegister dst, XMMRegister src);
Steve Blocka7e24c12009-10-30 11:49:00 +0000897
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100898 void andpd(XMMRegister dst, XMMRegister src);
899
Steve Block6ded16b2010-05-10 14:33:55 +0100900 void ucomisd(XMMRegister dst, XMMRegister src);
901 void movmskpd(Register dst, XMMRegister src);
Steve Blocka7e24c12009-10-30 11:49:00 +0000902
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100903 void cmpltsd(XMMRegister dst, XMMRegister src);
904
905 void movaps(XMMRegister dst, XMMRegister src);
906
Leon Clarkee46be812010-01-19 14:06:41 +0000907 void movdqa(XMMRegister dst, const Operand& src);
908 void movdqa(const Operand& dst, XMMRegister src);
909 void movdqu(XMMRegister dst, const Operand& src);
910 void movdqu(const Operand& dst, XMMRegister src);
911
Steve Blocka7e24c12009-10-30 11:49:00 +0000912 // Use either movsd or movlpd.
913 void movdbl(XMMRegister dst, const Operand& src);
914 void movdbl(const Operand& dst, XMMRegister src);
915
Steve Block6ded16b2010-05-10 14:33:55 +0100916 void movd(XMMRegister dst, const Operand& src);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100917 void movd(const Operand& src, XMMRegister dst);
Steve Block6ded16b2010-05-10 14:33:55 +0100918 void movsd(XMMRegister dst, XMMRegister src);
919
Ben Murdochb0fe1622011-05-05 13:52:32 +0100920 void pand(XMMRegister dst, XMMRegister src);
Steve Block6ded16b2010-05-10 14:33:55 +0100921 void pxor(XMMRegister dst, XMMRegister src);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100922 void por(XMMRegister dst, XMMRegister src);
Steve Block6ded16b2010-05-10 14:33:55 +0100923 void ptest(XMMRegister dst, XMMRegister src);
924
Ben Murdochb0fe1622011-05-05 13:52:32 +0100925 void psllq(XMMRegister reg, int8_t shift);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100926 void psllq(XMMRegister dst, XMMRegister src);
927 void psrlq(XMMRegister reg, int8_t shift);
928 void psrlq(XMMRegister dst, XMMRegister src);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100929 void pshufd(XMMRegister dst, XMMRegister src, int8_t shuffle);
930 void pextrd(const Operand& dst, XMMRegister src, int8_t offset);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100931
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100932 // Parallel XMM operations.
933 void movntdqa(XMMRegister src, const Operand& dst);
934 void movntdq(const Operand& dst, XMMRegister src);
935 // Prefetch src position into cache level.
936 // Level 1, 2 or 3 specifies CPU cache level. Level 0 specifies a
937 // non-temporal
938 void prefetch(const Operand& src, int level);
939 // TODO(lrn): Need SFENCE for movnt?
940
Steve Blocka7e24c12009-10-30 11:49:00 +0000941 // Debugging
942 void Print();
943
944 // Check the code size generated from label to here.
945 int SizeOfCodeGeneratedSince(Label* l) { return pc_offset() - l->pos(); }
946
947 // Mark address of the ExitJSFrame code.
948 void RecordJSReturn();
949
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100950 // Mark address of a debug break slot.
951 void RecordDebugBreakSlot();
952
Steve Blocka7e24c12009-10-30 11:49:00 +0000953 // Record a comment relocation entry that can be used by a disassembler.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100954 // Use --code-comments to enable.
Steve Blocka7e24c12009-10-30 11:49:00 +0000955 void RecordComment(const char* msg);
956
Ben Murdochb0fe1622011-05-05 13:52:32 +0100957 // Writes a single byte or word of data in the code stream. Used for
958 // inline tables, e.g., jump-tables.
959 void db(uint8_t data);
960 void dd(uint32_t data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000961
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100962 int pc_offset() const { return pc_ - buffer_; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000963
964 // Check if there is less than kGap bytes available in the buffer.
965 // If this is the case, we need to grow the buffer before emitting
966 // an instruction or relocation information.
967 inline bool overflow() const { return pc_ >= reloc_info_writer.pos() - kGap; }
968
969 // Get the number of bytes available in the buffer.
970 inline int available_space() const { return reloc_info_writer.pos() - pc_; }
971
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100972 static bool IsNop(Address addr) { return *addr == 0x90; }
973
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800974 PositionsRecorder* positions_recorder() { return &positions_recorder_; }
975
Steve Blocka7e24c12009-10-30 11:49:00 +0000976 // Avoid overflows for displacements etc.
977 static const int kMaximalBufferSize = 512*MB;
978 static const int kMinimalBufferSize = 4*KB;
979
980 protected:
981 void movsd(XMMRegister dst, const Operand& src);
982 void movsd(const Operand& dst, XMMRegister src);
983
984 void emit_sse_operand(XMMRegister reg, const Operand& adr);
985 void emit_sse_operand(XMMRegister dst, XMMRegister src);
Steve Block6ded16b2010-05-10 14:33:55 +0100986 void emit_sse_operand(Register dst, XMMRegister src);
Steve Blocka7e24c12009-10-30 11:49:00 +0000987
Steve Blocka7e24c12009-10-30 11:49:00 +0000988 byte* addr_at(int pos) { return buffer_ + pos; }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100989 private:
Steve Blocka7e24c12009-10-30 11:49:00 +0000990 byte byte_at(int pos) { return buffer_[pos]; }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100991 void set_byte_at(int pos, byte value) { buffer_[pos] = value; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000992 uint32_t long_at(int pos) {
993 return *reinterpret_cast<uint32_t*>(addr_at(pos));
994 }
995 void long_at_put(int pos, uint32_t x) {
996 *reinterpret_cast<uint32_t*>(addr_at(pos)) = x;
997 }
998
999 // code emission
1000 void GrowBuffer();
1001 inline void emit(uint32_t x);
1002 inline void emit(Handle<Object> handle);
1003 inline void emit(uint32_t x, RelocInfo::Mode rmode);
1004 inline void emit(const Immediate& x);
1005 inline void emit_w(const Immediate& x);
1006
1007 // Emit the code-object-relative offset of the label's position
1008 inline void emit_code_relative_offset(Label* label);
1009
1010 // instruction generation
1011 void emit_arith_b(int op1, int op2, Register dst, int imm8);
1012
1013 // Emit a basic arithmetic instruction (i.e. first byte of the family is 0x81)
1014 // with a given destination expression and an immediate operand. It attempts
1015 // to use the shortest encoding possible.
1016 // sel specifies the /n in the modrm byte (see the Intel PRM).
1017 void emit_arith(int sel, Operand dst, const Immediate& x);
1018
1019 void emit_operand(Register reg, const Operand& adr);
1020
1021 void emit_farith(int b1, int b2, int i);
1022
1023 // labels
1024 void print(Label* L);
1025 void bind_to(Label* L, int pos);
Steve Blocka7e24c12009-10-30 11:49:00 +00001026
1027 // displacements
1028 inline Displacement disp_at(Label* L);
1029 inline void disp_at_put(Label* L, Displacement disp);
1030 inline void emit_disp(Label* L, Displacement::Type type);
1031
1032 // record reloc info for current pc_
1033 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
1034
1035 friend class CodePatcher;
1036 friend class EnsureSpace;
1037
1038 // Code buffer:
1039 // The buffer into which code and relocation info are generated.
1040 byte* buffer_;
1041 int buffer_size_;
1042 // True if the assembler owns the buffer, false if buffer is external.
1043 bool own_buffer_;
1044 // A previously allocated buffer of kMinimalBufferSize bytes, or NULL.
1045 static byte* spare_buffer_;
1046
1047 // code generation
1048 byte* pc_; // the program counter; moves forward
1049 RelocInfoWriter reloc_info_writer;
1050
1051 // push-pop elimination
1052 byte* last_pc_;
1053
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001054 PositionsRecorder positions_recorder_;
1055
1056 friend class PositionsRecorder;
Steve Blocka7e24c12009-10-30 11:49:00 +00001057};
1058
1059
1060// Helper class that ensures that there is enough space for generating
1061// instructions and relocation information. The constructor makes
1062// sure that there is enough space and (in debug mode) the destructor
1063// checks that we did not generate too much.
1064class EnsureSpace BASE_EMBEDDED {
1065 public:
1066 explicit EnsureSpace(Assembler* assembler) : assembler_(assembler) {
1067 if (assembler_->overflow()) assembler_->GrowBuffer();
1068#ifdef DEBUG
1069 space_before_ = assembler_->available_space();
1070#endif
1071 }
1072
1073#ifdef DEBUG
1074 ~EnsureSpace() {
1075 int bytes_generated = space_before_ - assembler_->available_space();
1076 ASSERT(bytes_generated < assembler_->kGap);
1077 }
1078#endif
1079
1080 private:
1081 Assembler* assembler_;
1082#ifdef DEBUG
1083 int space_before_;
1084#endif
1085};
1086
1087} } // namespace v8::internal
1088
1089#endif // V8_IA32_ASSEMBLER_IA32_H_