blob: 4c995882e1b9ae064119e8644e360faaa39efd0d [file] [log] [blame]
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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.
ager@chromium.org9258b6b2008-09-11 09:11:10 +000033// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000034
35// A light-weight IA32 Assembler.
36
ager@chromium.org5ec48922009-05-05 07:25:34 +000037#ifndef V8_IA32_ASSEMBLER_IA32_H_
38#define V8_IA32_ASSEMBLER_IA32_H_
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039
40namespace v8 { namespace internal {
41
42// CPU Registers.
43//
44// 1) We would prefer to use an enum, but enum values are assignment-
45// compatible with int, which has caused code-generation bugs.
46//
47// 2) We would prefer to use a class instead of a struct but we don't like
48// the register initialization to depend on the particular initialization
49// order (which appears to be different on OS X, Linux, and Windows for the
50// installed versions of C++ we tried). Using a struct permits C-style
51// "initialization". Also, the Register objects cannot be const as this
52// forces initialization stubs in MSVC, making us dependent on initialization
53// order.
54//
55// 3) By not using an enum, we are possibly preventing the compiler from
56// doing certain constant folds, which may significantly reduce the
57// code generated for some assembly instructions (because they boil down
58// to a few constants). If this is a problem, we could change the code
59// such that we use an enum in optimized mode, and the struct in debug
60// mode. This way we get the compile-time error checking in debug mode
61// and best performance in optimized code.
62//
63struct Register {
64 bool is_valid() const { return 0 <= code_ && code_ < 8; }
65 bool is(Register reg) const { return code_ == reg.code_; }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000066 // eax, ebx, ecx and edx are byte registers, the rest are not.
67 bool is_byte_register() const { return code_ <= 3; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068 int code() const {
69 ASSERT(is_valid());
70 return code_;
71 }
72 int bit() const {
73 ASSERT(is_valid());
74 return 1 << code_;
75 }
76
77 // (unfortunately we can't make this private in a struct)
78 int code_;
79};
80
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000081const int kNumRegisters = 8;
82
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000083extern Register eax;
84extern Register ecx;
85extern Register edx;
86extern Register ebx;
87extern Register esp;
88extern Register ebp;
89extern Register esi;
90extern Register edi;
91extern Register no_reg;
92
93
94struct XMMRegister {
95 bool is_valid() const { return 0 <= code_ && code_ < 2; } // currently
96 int code() const {
97 ASSERT(is_valid());
98 return code_;
99 }
100
101 int code_;
102};
103
104extern XMMRegister xmm0;
105extern XMMRegister xmm1;
106extern XMMRegister xmm2;
107extern XMMRegister xmm3;
108extern XMMRegister xmm4;
109extern XMMRegister xmm5;
110extern XMMRegister xmm6;
111extern XMMRegister xmm7;
112
113enum Condition {
114 // any value < 0 is considered no_condition
115 no_condition = -1,
116
117 overflow = 0,
118 no_overflow = 1,
119 below = 2,
120 above_equal = 3,
121 equal = 4,
122 not_equal = 5,
123 below_equal = 6,
124 above = 7,
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000125 negative = 8,
126 positive = 9,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000127 parity_even = 10,
128 parity_odd = 11,
129 less = 12,
130 greater_equal = 13,
131 less_equal = 14,
132 greater = 15,
133
134 // aliases
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000135 carry = below,
136 not_carry = above_equal,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000137 zero = equal,
138 not_zero = not_equal,
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000139 sign = negative,
140 not_sign = positive
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000141};
142
143
144// Returns the equivalent of !cc.
145// Negation of the default no_condition (-1) results in a non-default
146// no_condition value (-2). As long as tests for no_condition check
147// for condition < 0, this will work as expected.
148inline Condition NegateCondition(Condition cc);
149
150// Corresponds to transposing the operands of a comparison.
151inline Condition ReverseCondition(Condition cc) {
152 switch (cc) {
153 case below:
154 return above;
155 case above:
156 return below;
157 case above_equal:
158 return below_equal;
159 case below_equal:
160 return above_equal;
161 case less:
162 return greater;
163 case greater:
164 return less;
165 case greater_equal:
166 return less_equal;
167 case less_equal:
168 return greater_equal;
169 default:
170 return cc;
171 };
172}
173
174enum Hint {
175 no_hint = 0,
176 not_taken = 0x2e,
177 taken = 0x3e
178};
179
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000180// The result of negating a hint is as if the corresponding condition
181// were negated by NegateCondition. That is, no_hint is mapped to
182// itself and not_taken and taken are mapped to each other.
183inline Hint NegateHint(Hint hint) {
184 return (hint == no_hint)
185 ? no_hint
186 : ((hint == not_taken) ? taken : not_taken);
187}
188
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000189
190// -----------------------------------------------------------------------------
191// Machine instruction Immediates
192
193class Immediate BASE_EMBEDDED {
194 public:
195 inline explicit Immediate(int x);
196 inline explicit Immediate(const char* s);
197 inline explicit Immediate(const ExternalReference& ext);
198 inline explicit Immediate(Handle<Object> handle);
199 inline explicit Immediate(Smi* value);
200
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000201 static Immediate CodeRelativeOffset(Label* label) {
202 return Immediate(label);
203 }
204
ager@chromium.org236ad962008-09-25 09:45:57 +0000205 bool is_zero() const { return x_ == 0 && rmode_ == RelocInfo::NONE; }
206 bool is_int8() const {
207 return -128 <= x_ && x_ < 128 && rmode_ == RelocInfo::NONE;
208 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000209 bool is_int16() const {
210 return -32768 <= x_ && x_ < 32768 && rmode_ == RelocInfo::NONE;
211 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000212
213 private:
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000214 inline explicit Immediate(Label* value);
215
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000216 int x_;
ager@chromium.org236ad962008-09-25 09:45:57 +0000217 RelocInfo::Mode rmode_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000218
219 friend class Assembler;
220};
221
222
223// -----------------------------------------------------------------------------
224// Machine instruction Operands
225
226enum ScaleFactor {
227 times_1 = 0,
228 times_2 = 1,
229 times_4 = 2,
230 times_8 = 3
231};
232
233
234class Operand BASE_EMBEDDED {
235 public:
236 // reg
237 INLINE(explicit Operand(Register reg));
238
239 // [disp/r]
ager@chromium.org236ad962008-09-25 09:45:57 +0000240 INLINE(explicit Operand(int32_t disp, RelocInfo::Mode rmode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000241 // disp only must always be relocated
242
243 // [base + disp/r]
ager@chromium.org236ad962008-09-25 09:45:57 +0000244 explicit Operand(Register base, int32_t disp,
245 RelocInfo::Mode rmode = RelocInfo::NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000246
247 // [base + index*scale + disp/r]
248 explicit Operand(Register base,
249 Register index,
250 ScaleFactor scale,
251 int32_t disp,
ager@chromium.org236ad962008-09-25 09:45:57 +0000252 RelocInfo::Mode rmode = RelocInfo::NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000253
254 // [index*scale + disp/r]
255 explicit Operand(Register index,
256 ScaleFactor scale,
257 int32_t disp,
ager@chromium.org236ad962008-09-25 09:45:57 +0000258 RelocInfo::Mode rmode = RelocInfo::NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000259
260 static Operand StaticVariable(const ExternalReference& ext) {
261 return Operand(reinterpret_cast<int32_t>(ext.address()),
ager@chromium.org236ad962008-09-25 09:45:57 +0000262 RelocInfo::EXTERNAL_REFERENCE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000263 }
264
265 static Operand StaticArray(Register index,
266 ScaleFactor scale,
267 const ExternalReference& arr) {
268 return Operand(index, scale, reinterpret_cast<int32_t>(arr.address()),
ager@chromium.org236ad962008-09-25 09:45:57 +0000269 RelocInfo::EXTERNAL_REFERENCE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000270 }
271
272 // Returns true if this Operand is a wrapper for the specified register.
273 bool is_reg(Register reg) const;
274
275 private:
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000276 byte buf_[6];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000277 // The number of bytes in buf_.
278 unsigned int len_;
279 // Only valid if len_ > 4.
ager@chromium.org236ad962008-09-25 09:45:57 +0000280 RelocInfo::Mode rmode_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000281
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000282 // Set the ModRM byte without an encoded 'reg' register. The
283 // register is encoded later as part of the emit_operand operation.
284 inline void set_modrm(int mod, Register rm);
285
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000286 inline void set_sib(ScaleFactor scale, Register index, Register base);
287 inline void set_disp8(int8_t disp);
ager@chromium.org236ad962008-09-25 09:45:57 +0000288 inline void set_dispr(int32_t disp, RelocInfo::Mode rmode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000289
290 friend class Assembler;
291};
292
293
kasper.lund7276f142008-07-30 08:49:36 +0000294// -----------------------------------------------------------------------------
295// A Displacement describes the 32bit immediate field of an instruction which
296// may be used together with a Label in order to refer to a yet unknown code
297// position. Displacements stored in the instruction stream are used to describe
298// the instruction and to chain a list of instructions using the same Label.
299// A Displacement contains 2 different fields:
300//
301// next field: position of next displacement in the chain (0 = end of list)
302// type field: instruction type
303//
304// A next value of null (0) indicates the end of a chain (note that there can
305// be no displacement at position zero, because there is always at least one
306// instruction byte before the displacement).
307//
308// Displacement _data field layout
309//
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000310// |31.....2|1......0|
kasper.lund7276f142008-07-30 08:49:36 +0000311// [ next | type |
312
313class Displacement BASE_EMBEDDED {
314 public:
315 enum Type {
316 UNCONDITIONAL_JUMP,
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000317 CODE_RELATIVE,
kasper.lund7276f142008-07-30 08:49:36 +0000318 OTHER
319 };
320
321 int data() const { return data_; }
322 Type type() const { return TypeField::decode(data_); }
323 void next(Label* L) const {
324 int n = NextField::decode(data_);
325 n > 0 ? L->link_to(n) : L->Unuse();
326 }
327 void link_to(Label* L) { init(L, type()); }
328
329 explicit Displacement(int data) { data_ = data; }
330
331 Displacement(Label* L, Type type) { init(L, type); }
332
333 void print() {
334 PrintF("%s (%x) ", (type() == UNCONDITIONAL_JUMP ? "jmp" : "[other]"),
335 NextField::decode(data_));
336 }
337
338 private:
339 int data_;
340
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000341 class TypeField: public BitField<Type, 0, 2> {};
342 class NextField: public BitField<int, 2, 32-2> {};
kasper.lund7276f142008-07-30 08:49:36 +0000343
344 void init(Label* L, Type type);
345};
346
347
ager@chromium.org236ad962008-09-25 09:45:57 +0000348
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000349// CpuFeatures keeps track of which features are supported by the target CPU.
350// Supported features must be enabled by a Scope before use.
351// Example:
352// if (CpuFeatures::IsSupported(SSE2)) {
353// CpuFeatures::Scope fscope(SSE2);
354// // Generate SSE2 floating point code.
355// } else {
356// // Generate standard x87 floating point code.
357// }
358class CpuFeatures : public AllStatic {
359 public:
360 // Feature flags bit positions. They are mostly based on the CPUID spec.
361 // (We assign CPUID itself to one of the currently reserved bits --
362 // feel free to change this if needed.)
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000363 enum Feature { SSE3 = 32, SSE2 = 26, CMOV = 15, RDTSC = 4, CPUID = 10 };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000364 // Detect features of the target CPU. Set safe defaults if the serializer
365 // is enabled (snapshots must be portable).
366 static void Probe();
367 // Check whether a feature is supported by the target CPU.
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000368 static bool IsSupported(Feature f) {
369 return (supported_ & (static_cast<uint64_t>(1) << f)) != 0;
370 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000371 // Check whether a feature is currently enabled.
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000372 static bool IsEnabled(Feature f) {
373 return (enabled_ & (static_cast<uint64_t>(1) << f)) != 0;
374 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000375 // Enable a specified feature within a scope.
376 class Scope BASE_EMBEDDED {
377#ifdef DEBUG
378 public:
379 explicit Scope(Feature f) {
380 ASSERT(CpuFeatures::IsSupported(f));
381 old_enabled_ = CpuFeatures::enabled_;
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000382 CpuFeatures::enabled_ |= (static_cast<uint64_t>(1) << f);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000383 }
384 ~Scope() { CpuFeatures::enabled_ = old_enabled_; }
385 private:
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000386 uint64_t old_enabled_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000387#else
388 public:
389 explicit Scope(Feature f) {}
390#endif
391 };
392 private:
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000393 static uint64_t supported_;
394 static uint64_t enabled_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000395};
396
397
398class Assembler : public Malloced {
399 private:
400 // The relocation writer's position is kGap bytes below the end of
401 // the generated instructions. This leaves enough space for the
402 // longest possible ia32 instruction (17 bytes as of 9/26/06) and
403 // allows for a single, fast space check per instruction.
404 static const int kGap = 32;
405
406 public:
407 // Create an assembler. Instructions and relocation information are emitted
408 // into a buffer, with the instructions starting from the beginning and the
409 // relocation information starting from the end of the buffer. See CodeDesc
410 // for a detailed comment on the layout (globals.h).
411 //
412 // If the provided buffer is NULL, the assembler allocates and grows its own
413 // buffer, and buffer_size determines the initial buffer size. The buffer is
414 // owned by the assembler and deallocated upon destruction of the assembler.
415 //
416 // If the provided buffer is not NULL, the assembler uses the provided buffer
417 // for code generation and assumes its size to be buffer_size. If the buffer
418 // is too small, a fatal error occurs. No deallocation of the buffer is done
419 // upon destruction of the assembler.
420 Assembler(void* buffer, int buffer_size);
421 ~Assembler();
422
423 // GetCode emits any pending (non-emitted) code and fills the descriptor
424 // desc. GetCode() is idempotent; it returns the same result if no other
ager@chromium.org32912102009-01-16 10:38:43 +0000425 // Assembler functions are invoked in between GetCode() calls.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000426 void GetCode(CodeDesc* desc);
427
428 // Read/Modify the code target in the branch/call instruction at pc.
429 inline static Address target_address_at(Address pc);
430 inline static void set_target_address_at(Address pc, Address target);
431
432 // Distance between the address of the code target in the call instruction
433 // and the return address
434 static const int kTargetAddrToReturnAddrDist = kPointerSize;
435
436
437 // ---------------------------------------------------------------------------
438 // Code generation
439 //
440 // - function names correspond one-to-one to ia32 instruction mnemonics
441 // - unless specified otherwise, instructions operate on 32bit operands
442 // - instructions on 8bit (byte) operands/registers have a trailing '_b'
443 // - instructions on 16bit (word) operands/registers have a trailing '_w'
444 // - naming conflicts with C++ keywords are resolved via a trailing '_'
445
446 // NOTE ON INTERFACE: Currently, the interface is not very consistent
447 // in the sense that some operations (e.g. mov()) can be called in more
448 // the one way to generate the same instruction: The Register argument
449 // can in some cases be replaced with an Operand(Register) argument.
ager@chromium.org32912102009-01-16 10:38:43 +0000450 // This should be cleaned up and made more orthogonal. The questions
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000451 // is: should we always use Operands instead of Registers where an
452 // Operand is possible, or should we have a Register (overloaded) form
ager@chromium.org32912102009-01-16 10:38:43 +0000453 // instead? We must be careful to make sure that the selected instruction
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000454 // is obvious from the parameters to avoid hard-to-find code generation
455 // bugs.
456
457 // Insert the smallest number of nop instructions
458 // possible to align the pc offset to a multiple
459 // of m. m must be a power of 2.
460 void Align(int m);
461
462 // Stack
463 void pushad();
464 void popad();
465
466 void pushfd();
467 void popfd();
468
469 void push(const Immediate& x);
470 void push(Register src);
471 void push(const Operand& src);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000472 void push(Label* label, RelocInfo::Mode relocation_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000473
474 void pop(Register dst);
475 void pop(const Operand& dst);
476
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000477 void enter(const Immediate& size);
478 void leave();
479
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000480 // Moves
481 void mov_b(Register dst, const Operand& src);
482 void mov_b(const Operand& dst, int8_t imm8);
483 void mov_b(const Operand& dst, Register src);
484
485 void mov_w(Register dst, const Operand& src);
486 void mov_w(const Operand& dst, Register src);
487
488 void mov(Register dst, int32_t imm32);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000489 void mov(Register dst, const Immediate& x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000490 void mov(Register dst, Handle<Object> handle);
491 void mov(Register dst, const Operand& src);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000492 void mov(Register dst, Register src);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000493 void mov(const Operand& dst, const Immediate& x);
494 void mov(const Operand& dst, Handle<Object> handle);
495 void mov(const Operand& dst, Register src);
496
497 void movsx_b(Register dst, const Operand& src);
498
499 void movsx_w(Register dst, const Operand& src);
500
501 void movzx_b(Register dst, const Operand& src);
502
503 void movzx_w(Register dst, const Operand& src);
504
505 // Conditional moves
506 void cmov(Condition cc, Register dst, int32_t imm32);
507 void cmov(Condition cc, Register dst, Handle<Object> handle);
508 void cmov(Condition cc, Register dst, const Operand& src);
509
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000510 // Exchange two registers
511 void xchg(Register dst, Register src);
512
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000513 // Arithmetics
514 void adc(Register dst, int32_t imm32);
515 void adc(Register dst, const Operand& src);
516
517 void add(Register dst, const Operand& src);
518 void add(const Operand& dst, const Immediate& x);
519
520 void and_(Register dst, int32_t imm32);
521 void and_(Register dst, const Operand& src);
522 void and_(const Operand& src, Register dst);
523 void and_(const Operand& dst, const Immediate& x);
524
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000525 void cmpb(const Operand& op, int8_t imm8);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000526 void cmpb_al(const Operand& op);
527 void cmpw_ax(const Operand& op);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000528 void cmpw(const Operand& op, Immediate imm16);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000529 void cmp(Register reg, int32_t imm32);
530 void cmp(Register reg, Handle<Object> handle);
531 void cmp(Register reg, const Operand& op);
532 void cmp(const Operand& op, const Immediate& imm);
533
534 void dec_b(Register dst);
535
536 void dec(Register dst);
537 void dec(const Operand& dst);
538
539 void cdq();
540
541 void idiv(Register src);
542
543 void imul(Register dst, const Operand& src);
544 void imul(Register dst, Register src, int32_t imm32);
545
546 void inc(Register dst);
547 void inc(const Operand& dst);
548
549 void lea(Register dst, const Operand& src);
550
551 void mul(Register src);
552
553 void neg(Register dst);
554
555 void not_(Register dst);
556
557 void or_(Register dst, int32_t imm32);
558 void or_(Register dst, const Operand& src);
559 void or_(const Operand& dst, Register src);
560 void or_(const Operand& dst, const Immediate& x);
561
562 void rcl(Register dst, uint8_t imm8);
563
564 void sar(Register dst, uint8_t imm8);
565 void sar(Register dst);
566
567 void sbb(Register dst, const Operand& src);
568
569 void shld(Register dst, const Operand& src);
570
571 void shl(Register dst, uint8_t imm8);
572 void shl(Register dst);
573
574 void shrd(Register dst, const Operand& src);
575
576 void shr(Register dst, uint8_t imm8);
577 void shr(Register dst);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000578 void shr_cl(Register dst);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000579
580 void sub(const Operand& dst, const Immediate& x);
581 void sub(Register dst, const Operand& src);
582 void sub(const Operand& dst, Register src);
583
584 void test(Register reg, const Immediate& imm);
585 void test(Register reg, const Operand& op);
586 void test(const Operand& op, const Immediate& imm);
587
588 void xor_(Register dst, int32_t imm32);
589 void xor_(Register dst, const Operand& src);
590 void xor_(const Operand& src, Register dst);
591 void xor_(const Operand& dst, const Immediate& x);
592
593 // Bit operations.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000594 void bt(const Operand& dst, Register src);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000595 void bts(const Operand& dst, Register src);
596
597 // Miscellaneous
598 void hlt();
599 void int3();
600 void nop();
601 void rdtsc();
602 void ret(int imm16);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000603
604 // Label operations & relative jumps (PPUM Appendix D)
605 //
606 // Takes a branch opcode (cc) and a label (L) and generates
607 // either a backward branch or a forward branch and links it
608 // to the label fixup chain. Usage:
609 //
610 // Label L; // unbound label
611 // j(cc, &L); // forward branch to unbound label
612 // bind(&L); // bind label to the current pc
613 // j(cc, &L); // backward branch to bound label
614 // bind(&L); // illegal: a label may be bound only once
615 //
616 // Note: The same Label can be used for forward and backward branches
617 // but it may be bound only once.
618
619 void bind(Label* L); // binds an unbound label L to the current code position
620
621 // Calls
622 void call(Label* L);
ager@chromium.org236ad962008-09-25 09:45:57 +0000623 void call(byte* entry, RelocInfo::Mode rmode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000624 void call(const Operand& adr);
ager@chromium.org236ad962008-09-25 09:45:57 +0000625 void call(Handle<Code> code, RelocInfo::Mode rmode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000626
627 // Jumps
628 void jmp(Label* L); // unconditional jump to L
ager@chromium.org236ad962008-09-25 09:45:57 +0000629 void jmp(byte* entry, RelocInfo::Mode rmode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000630 void jmp(const Operand& adr);
ager@chromium.org236ad962008-09-25 09:45:57 +0000631 void jmp(Handle<Code> code, RelocInfo::Mode rmode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000632
633 // Conditional jumps
634 void j(Condition cc, Label* L, Hint hint = no_hint);
ager@chromium.org236ad962008-09-25 09:45:57 +0000635 void j(Condition cc, byte* entry, RelocInfo::Mode rmode, Hint hint = no_hint);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000636 void j(Condition cc, Handle<Code> code, Hint hint = no_hint);
637
638 // Floating-point operations
639 void fld(int i);
640
641 void fld1();
642 void fldz();
643
644 void fld_s(const Operand& adr);
645 void fld_d(const Operand& adr);
646
647 void fstp_s(const Operand& adr);
648 void fstp_d(const Operand& adr);
649
650 void fild_s(const Operand& adr);
651 void fild_d(const Operand& adr);
652
653 void fist_s(const Operand& adr);
654
655 void fistp_s(const Operand& adr);
656 void fistp_d(const Operand& adr);
657
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000658 void fisttp_s(const Operand& adr);
659
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000660 void fabs();
661 void fchs();
662
663 void fadd(int i);
664 void fsub(int i);
665 void fmul(int i);
666 void fdiv(int i);
667
668 void fisub_s(const Operand& adr);
669
670 void faddp(int i = 1);
671 void fsubp(int i = 1);
672 void fsubrp(int i = 1);
673 void fmulp(int i = 1);
674 void fdivp(int i = 1);
675 void fprem();
676 void fprem1();
677
678 void fxch(int i = 1);
679 void fincstp();
680 void ffree(int i = 0);
681
682 void ftst();
683 void fucomp(int i);
684 void fucompp();
685 void fcompp();
686 void fnstsw_ax();
687 void fwait();
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000688 void fnclex();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000689
690 void frndint();
691
692 void sahf();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000693 void setcc(Condition cc, Register reg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000694
695 void cpuid();
696
697 // SSE2 instructions
698 void cvttss2si(Register dst, const Operand& src);
699 void cvttsd2si(Register dst, const Operand& src);
700
701 void cvtsi2sd(XMMRegister dst, const Operand& src);
702
703 void addsd(XMMRegister dst, XMMRegister src);
704 void subsd(XMMRegister dst, XMMRegister src);
705 void mulsd(XMMRegister dst, XMMRegister src);
706 void divsd(XMMRegister dst, XMMRegister src);
707
708 // Use either movsd or movlpd.
709 void movdbl(XMMRegister dst, const Operand& src);
710 void movdbl(const Operand& dst, XMMRegister src);
711
712 // Debugging
713 void Print();
714
715 // Check the code size generated from label to here.
716 int SizeOfCodeGeneratedSince(Label* l) { return pc_offset() - l->pos(); }
717
718 // Mark address of the ExitJSFrame code.
719 void RecordJSReturn();
720
721 // Record a comment relocation entry that can be used by a disassembler.
722 // Use --debug_code to enable.
723 void RecordComment(const char* msg);
724
725 void RecordPosition(int pos);
726 void RecordStatementPosition(int pos);
ager@chromium.org236ad962008-09-25 09:45:57 +0000727 void WriteRecordedPositions();
728
729 // Writes a single word of data in the code stream.
730 // Used for inline tables, e.g., jump-tables.
731 void dd(uint32_t data, RelocInfo::Mode reloc_info);
732
733 // Writes the absolute address of a bound label at the given position in
734 // the generated code. That positions should have the relocation mode
735 // internal_reference!
736 void WriteInternalReference(int position, const Label& bound_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000737
738 int pc_offset() const { return pc_ - buffer_; }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000739 int current_statement_position() const { return current_statement_position_; }
740 int current_position() const { return current_position_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000741
742 // Check if there is less than kGap bytes available in the buffer.
743 // If this is the case, we need to grow the buffer before emitting
744 // an instruction or relocation information.
745 inline bool overflow() const { return pc_ >= reloc_info_writer.pos() - kGap; }
746
747 // Get the number of bytes available in the buffer.
748 inline int available_space() const { return reloc_info_writer.pos() - pc_; }
749
750 // Avoid overflows for displacements etc.
751 static const int kMaximalBufferSize = 512*MB;
752 static const int kMinimalBufferSize = 4*KB;
753
754 protected:
755 void movsd(XMMRegister dst, const Operand& src);
756 void movsd(const Operand& dst, XMMRegister src);
757
758 void emit_sse_operand(XMMRegister reg, const Operand& adr);
759 void emit_sse_operand(XMMRegister dst, XMMRegister src);
760
761
762 private:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000763 byte* addr_at(int pos) { return buffer_ + pos; }
764 byte byte_at(int pos) { return buffer_[pos]; }
765 uint32_t long_at(int pos) {
766 return *reinterpret_cast<uint32_t*>(addr_at(pos));
767 }
768 void long_at_put(int pos, uint32_t x) {
769 *reinterpret_cast<uint32_t*>(addr_at(pos)) = x;
770 }
771
772 // code emission
773 void GrowBuffer();
774 inline void emit(uint32_t x);
775 inline void emit(Handle<Object> handle);
ager@chromium.org236ad962008-09-25 09:45:57 +0000776 inline void emit(uint32_t x, RelocInfo::Mode rmode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000777 inline void emit(const Immediate& x);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000778 inline void emit_w(const Immediate& x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000779
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000780 // Emit the code-object-relative offset of the label's position
781 inline void emit_code_relative_offset(Label* label);
782
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000783 // instruction generation
784 void emit_arith_b(int op1, int op2, Register dst, int imm8);
785
786 // Emit a basic arithmetic instruction (i.e. first byte of the family is 0x81)
787 // with a given destination expression and an immediate operand. It attempts
788 // to use the shortest encoding possible.
789 // sel specifies the /n in the modrm byte (see the Intel PRM).
790 void emit_arith(int sel, Operand dst, const Immediate& x);
791
792 void emit_operand(Register reg, const Operand& adr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000793
794 void emit_farith(int b1, int b2, int i);
795
796 // labels
797 void print(Label* L);
798 void bind_to(Label* L, int pos);
799 void link_to(Label* L, Label* appendix);
800
kasper.lund7276f142008-07-30 08:49:36 +0000801 // displacements
802 inline Displacement disp_at(Label* L);
803 inline void disp_at_put(Label* L, Displacement disp);
804 inline void emit_disp(Label* L, Displacement::Type type);
805
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000806 // record reloc info for current pc_
ager@chromium.org236ad962008-09-25 09:45:57 +0000807 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000808
809 friend class CodePatcher;
810 friend class EnsureSpace;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000811
812 // Code buffer:
813 // The buffer into which code and relocation info are generated.
814 byte* buffer_;
815 int buffer_size_;
816 // True if the assembler owns the buffer, false if buffer is external.
817 bool own_buffer_;
818
819 // code generation
820 byte* pc_; // the program counter; moves forward
821 RelocInfoWriter reloc_info_writer;
822
823 // push-pop elimination
824 byte* last_pc_;
825
826 // source position information
827 int current_statement_position_;
828 int current_position_;
829 int written_statement_position_;
830 int written_position_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000831};
832
833
834// Helper class that ensures that there is enough space for generating
835// instructions and relocation information. The constructor makes
836// sure that there is enough space and (in debug mode) the destructor
837// checks that we did not generate too much.
838class EnsureSpace BASE_EMBEDDED {
839 public:
840 explicit EnsureSpace(Assembler* assembler) : assembler_(assembler) {
841 if (assembler_->overflow()) assembler_->GrowBuffer();
842#ifdef DEBUG
843 space_before_ = assembler_->available_space();
844#endif
845 }
846
847#ifdef DEBUG
848 ~EnsureSpace() {
849 int bytes_generated = space_before_ - assembler_->available_space();
850 ASSERT(bytes_generated < assembler_->kGap);
851 }
852#endif
853
854 private:
855 Assembler* assembler_;
856#ifdef DEBUG
857 int space_before_;
858#endif
859};
860
861} } // namespace v8::internal
862
ager@chromium.org5ec48922009-05-05 07:25:34 +0000863#endif // V8_IA32_ASSEMBLER_IA32_H_