blob: 9d3d39b83ecb58f66d1cd13485a3078670ede2a7 [file] [log] [blame]
ager@chromium.org5c838252010-02-19 08:53:10 +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.
ulan@chromium.org2efb9002012-01-19 15:36:35 +000033// Copyright 2012 the V8 project authors. All rights reserved.
ager@chromium.org5c838252010-02-19 08:53:10 +000034
35
36#ifndef V8_MIPS_ASSEMBLER_MIPS_H_
37#define V8_MIPS_ASSEMBLER_MIPS_H_
38
39#include <stdio.h>
40#include "assembler.h"
41#include "constants-mips.h"
42#include "serialize.h"
43
ager@chromium.org5c838252010-02-19 08:53:10 +000044namespace v8 {
45namespace internal {
46
47// CPU Registers.
48//
49// 1) We would prefer to use an enum, but enum values are assignment-
50// compatible with int, which has caused code-generation bugs.
51//
52// 2) We would prefer to use a class instead of a struct but we don't like
53// the register initialization to depend on the particular initialization
54// order (which appears to be different on OS X, Linux, and Windows for the
55// installed versions of C++ we tried). Using a struct permits C-style
56// "initialization". Also, the Register objects cannot be const as this
57// forces initialization stubs in MSVC, making us dependent on initialization
58// order.
59//
60// 3) By not using an enum, we are possibly preventing the compiler from
61// doing certain constant folds, which may significantly reduce the
62// code generated for some assembly instructions (because they boil down
63// to a few constants). If this is a problem, we could change the code
64// such that we use an enum in optimized mode, and the struct in debug
65// mode. This way we get the compile-time error checking in debug mode
66// and best performance in optimized code.
67
68
69// -----------------------------------------------------------------------------
karlklose@chromium.org83a47282011-05-11 11:54:09 +000070// Implementation of Register and FPURegister.
ager@chromium.org5c838252010-02-19 08:53:10 +000071
72// Core register.
73struct Register {
lrn@chromium.org7516f052011-03-30 08:52:27 +000074 static const int kNumRegisters = v8::internal::kNumRegisters;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000075 static const int kMaxNumAllocatableRegisters = 14; // v0 through t7.
karlklose@chromium.org83a47282011-05-11 11:54:09 +000076 static const int kSizeInBytes = 4;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000077 static const int kGPRsPerNonFPUDouble = 2;
78
79 inline static int NumAllocatableRegisters();
lrn@chromium.org7516f052011-03-30 08:52:27 +000080
81 static int ToAllocationIndex(Register reg) {
82 return reg.code() - 2; // zero_reg and 'at' are skipped.
83 }
84
85 static Register FromAllocationIndex(int index) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000086 ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters);
lrn@chromium.org7516f052011-03-30 08:52:27 +000087 return from_code(index + 2); // zero_reg and 'at' are skipped.
88 }
89
90 static const char* AllocationIndexToString(int index) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000091 ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters);
lrn@chromium.org7516f052011-03-30 08:52:27 +000092 const char* const names[] = {
93 "v0",
94 "v1",
95 "a0",
96 "a1",
97 "a2",
98 "a3",
99 "t0",
100 "t1",
101 "t2",
102 "t3",
103 "t4",
104 "t5",
105 "t6",
106 "t7",
107 };
108 return names[index];
109 }
110
111 static Register from_code(int code) {
112 Register r = { code };
113 return r;
114 }
115
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000116 bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; }
117 bool is(Register reg) const { return code_ == reg.code_; }
118 int code() const {
ager@chromium.org5c838252010-02-19 08:53:10 +0000119 ASSERT(is_valid());
120 return code_;
121 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000122 int bit() const {
ager@chromium.org5c838252010-02-19 08:53:10 +0000123 ASSERT(is_valid());
124 return 1 << code_;
125 }
126
127 // Unfortunately we can't make this private in a struct.
128 int code_;
129};
130
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000131#define REGISTER(N, C) \
132 const int kRegister_ ## N ## _Code = C; \
133 const Register N = { C }
ager@chromium.org5c838252010-02-19 08:53:10 +0000134
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000135REGISTER(no_reg, -1);
136// Always zero.
137REGISTER(zero_reg, 0);
138// at: Reserved for synthetic instructions.
139REGISTER(at, 1);
140// v0, v1: Used when returning multiple values from subroutines.
141REGISTER(v0, 2);
142REGISTER(v1, 3);
143// a0 - a4: Used to pass non-FP parameters.
144REGISTER(a0, 4);
145REGISTER(a1, 5);
146REGISTER(a2, 6);
147REGISTER(a3, 7);
148// t0 - t9: Can be used without reservation, act as temporary registers and are
149// allowed to be destroyed by subroutines.
150REGISTER(t0, 8);
151REGISTER(t1, 9);
152REGISTER(t2, 10);
153REGISTER(t3, 11);
154REGISTER(t4, 12);
155REGISTER(t5, 13);
156REGISTER(t6, 14);
157REGISTER(t7, 15);
158// s0 - s7: Subroutine register variables. Subroutines that write to these
159// registers must restore their values before exiting so that the caller can
160// expect the values to be preserved.
161REGISTER(s0, 16);
162REGISTER(s1, 17);
163REGISTER(s2, 18);
164REGISTER(s3, 19);
165REGISTER(s4, 20);
166REGISTER(s5, 21);
167REGISTER(s6, 22);
168REGISTER(s7, 23);
169REGISTER(t8, 24);
170REGISTER(t9, 25);
171// k0, k1: Reserved for system calls and interrupt handlers.
172REGISTER(k0, 26);
173REGISTER(k1, 27);
174// gp: Reserved.
175REGISTER(gp, 28);
176// sp: Stack pointer.
177REGISTER(sp, 29);
178// fp: Frame pointer.
179REGISTER(fp, 30);
180// ra: Return address pointer.
181REGISTER(ra, 31);
182
183#undef REGISTER
lrn@chromium.org7516f052011-03-30 08:52:27 +0000184
ager@chromium.org5c838252010-02-19 08:53:10 +0000185
186int ToNumber(Register reg);
187
188Register ToRegister(int num);
189
190// Coprocessor register.
191struct FPURegister {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000192 static const int kMaxNumRegisters = v8::internal::kNumFPURegisters;
lrn@chromium.org34e60782011-09-15 07:25:40 +0000193
194 // TODO(plind): Warning, inconsistent numbering here. kNumFPURegisters refers
195 // to number of 32-bit FPU regs, but kNumAllocatableRegisters refers to
196 // number of Double regs (64-bit regs, or FPU-reg-pairs).
197
198 // A few double registers are reserved: one as a scratch register and one to
199 // hold 0.0.
200 // f28: 0.0
201 // f30: scratch register.
202 static const int kNumReservedRegisters = 2;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000203 static const int kMaxNumAllocatableRegisters = kMaxNumRegisters / 2 -
lrn@chromium.org34e60782011-09-15 07:25:40 +0000204 kNumReservedRegisters;
205
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000206 inline static int NumRegisters();
207 inline static int NumAllocatableRegisters();
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000208 inline static int ToAllocationIndex(FPURegister reg);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000209 static const char* AllocationIndexToString(int index);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000210
211 static FPURegister FromAllocationIndex(int index) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000212 ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000213 return from_code(index * 2);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000214 }
215
lrn@chromium.org7516f052011-03-30 08:52:27 +0000216 static FPURegister from_code(int code) {
217 FPURegister r = { code };
218 return r;
219 }
220
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000221 bool is_valid() const { return 0 <= code_ && code_ < kMaxNumRegisters ; }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000222 bool is(FPURegister creg) const { return code_ == creg.code_; }
lrn@chromium.org34e60782011-09-15 07:25:40 +0000223 FPURegister low() const {
224 // Find low reg of a Double-reg pair, which is the reg itself.
225 ASSERT(code_ % 2 == 0); // Specified Double reg must be even.
226 FPURegister reg;
227 reg.code_ = code_;
228 ASSERT(reg.is_valid());
229 return reg;
230 }
231 FPURegister high() const {
232 // Find high reg of a Doubel-reg pair, which is reg + 1.
233 ASSERT(code_ % 2 == 0); // Specified Double reg must be even.
234 FPURegister reg;
235 reg.code_ = code_ + 1;
236 ASSERT(reg.is_valid());
237 return reg;
238 }
239
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000240 int code() const {
ager@chromium.org5c838252010-02-19 08:53:10 +0000241 ASSERT(is_valid());
242 return code_;
243 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000244 int bit() const {
ager@chromium.org5c838252010-02-19 08:53:10 +0000245 ASSERT(is_valid());
246 return 1 << code_;
247 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000248 void setcode(int f) {
249 code_ = f;
250 ASSERT(is_valid());
251 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000252 // Unfortunately we can't make this private in a struct.
253 int code_;
254};
255
lrn@chromium.org34e60782011-09-15 07:25:40 +0000256// V8 now supports the O32 ABI, and the FPU Registers are organized as 32
257// 32-bit registers, f0 through f31. When used as 'double' they are used
258// in pairs, starting with the even numbered register. So a double operation
259// on f0 really uses f0 and f1.
260// (Modern mips hardware also supports 32 64-bit registers, via setting
261// (priviledged) Status Register FR bit to 1. This is used by the N32 ABI,
262// but it is not in common use. Someday we will want to support this in v8.)
ager@chromium.org5c838252010-02-19 08:53:10 +0000263
lrn@chromium.org34e60782011-09-15 07:25:40 +0000264// For O32 ABI, Floats and Doubles refer to same set of 32 32-bit registers.
265typedef FPURegister DoubleRegister;
266typedef FPURegister FloatRegister;
267
268const FPURegister no_freg = { -1 };
ager@chromium.org5c838252010-02-19 08:53:10 +0000269
lrn@chromium.org7516f052011-03-30 08:52:27 +0000270const FPURegister f0 = { 0 }; // Return value in hard float mode.
271const FPURegister f1 = { 1 };
272const FPURegister f2 = { 2 };
273const FPURegister f3 = { 3 };
274const FPURegister f4 = { 4 };
275const FPURegister f5 = { 5 };
276const FPURegister f6 = { 6 };
277const FPURegister f7 = { 7 };
278const FPURegister f8 = { 8 };
279const FPURegister f9 = { 9 };
280const FPURegister f10 = { 10 };
281const FPURegister f11 = { 11 };
282const FPURegister f12 = { 12 }; // Arg 0 in hard float mode.
283const FPURegister f13 = { 13 };
284const FPURegister f14 = { 14 }; // Arg 1 in hard float mode.
285const FPURegister f15 = { 15 };
286const FPURegister f16 = { 16 };
287const FPURegister f17 = { 17 };
288const FPURegister f18 = { 18 };
289const FPURegister f19 = { 19 };
290const FPURegister f20 = { 20 };
291const FPURegister f21 = { 21 };
292const FPURegister f22 = { 22 };
293const FPURegister f23 = { 23 };
294const FPURegister f24 = { 24 };
295const FPURegister f25 = { 25 };
296const FPURegister f26 = { 26 };
297const FPURegister f27 = { 27 };
298const FPURegister f28 = { 28 };
299const FPURegister f29 = { 29 };
300const FPURegister f30 = { 30 };
301const FPURegister f31 = { 31 };
ager@chromium.org5c838252010-02-19 08:53:10 +0000302
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000303const Register sfpd_lo = { kRegister_t6_Code };
304const Register sfpd_hi = { kRegister_t7_Code };
305
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000306// Register aliases.
307// cp is assumed to be a callee saved register.
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000308// Defined using #define instead of "static const Register&" because Clang
309// complains otherwise when a compilation unit that includes this header
310// doesn't use the variables.
311#define kRootRegister s6
312#define cp s7
313#define kLithiumScratchReg s3
314#define kLithiumScratchReg2 s4
315#define kLithiumScratchDouble f30
316#define kDoubleRegZero f28
lrn@chromium.org34e60782011-09-15 07:25:40 +0000317
lrn@chromium.org7516f052011-03-30 08:52:27 +0000318// FPU (coprocessor 1) control registers.
319// Currently only FCSR (#31) is implemented.
320struct FPUControlRegister {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000321 bool is_valid() const { return code_ == kFCSRRegister; }
322 bool is(FPUControlRegister creg) const { return code_ == creg.code_; }
323 int code() const {
324 ASSERT(is_valid());
325 return code_;
326 }
327 int bit() const {
328 ASSERT(is_valid());
329 return 1 << code_;
330 }
331 void setcode(int f) {
332 code_ = f;
333 ASSERT(is_valid());
334 }
335 // Unfortunately we can't make this private in a struct.
336 int code_;
ager@chromium.org5c838252010-02-19 08:53:10 +0000337};
338
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000339const FPUControlRegister no_fpucreg = { kInvalidFPUControlRegister };
lrn@chromium.org7516f052011-03-30 08:52:27 +0000340const FPUControlRegister FCSR = { kFCSRRegister };
ager@chromium.org5c838252010-02-19 08:53:10 +0000341
342
343// -----------------------------------------------------------------------------
344// Machine instruction Operands.
345
346// Class Operand represents a shifter operand in data processing instructions.
347class Operand BASE_EMBEDDED {
348 public:
349 // Immediate.
350 INLINE(explicit Operand(int32_t immediate,
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000351 RelocInfo::Mode rmode = RelocInfo::NONE32));
ager@chromium.org5c838252010-02-19 08:53:10 +0000352 INLINE(explicit Operand(const ExternalReference& f));
353 INLINE(explicit Operand(const char* s));
354 INLINE(explicit Operand(Object** opp));
355 INLINE(explicit Operand(Context** cpp));
356 explicit Operand(Handle<Object> handle);
357 INLINE(explicit Operand(Smi* value));
358
359 // Register.
360 INLINE(explicit Operand(Register rm));
361
362 // Return true if this is a register operand.
363 INLINE(bool is_reg() const);
364
365 Register rm() const { return rm_; }
366
367 private:
368 Register rm_;
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000369 int32_t imm32_; // Valid if rm_ == no_reg.
ager@chromium.org5c838252010-02-19 08:53:10 +0000370 RelocInfo::Mode rmode_;
371
372 friend class Assembler;
373 friend class MacroAssembler;
374};
375
376
377// On MIPS we have only one adressing mode with base_reg + offset.
378// Class MemOperand represents a memory operand in load and store instructions.
379class MemOperand : public Operand {
380 public:
lrn@chromium.org7516f052011-03-30 08:52:27 +0000381 explicit MemOperand(Register rn, int32_t offset = 0);
ager@chromium.org04921a82011-06-27 13:21:41 +0000382 int32_t offset() const { return offset_; }
ager@chromium.org5c838252010-02-19 08:53:10 +0000383
lrn@chromium.org34e60782011-09-15 07:25:40 +0000384 bool OffsetIsInt16Encodable() const {
385 return is_int16(offset_);
386 }
387
ager@chromium.org5c838252010-02-19 08:53:10 +0000388 private:
lrn@chromium.org7516f052011-03-30 08:52:27 +0000389 int32_t offset_;
ager@chromium.org5c838252010-02-19 08:53:10 +0000390
391 friend class Assembler;
392};
393
394
lrn@chromium.org7516f052011-03-30 08:52:27 +0000395// CpuFeatures keeps track of which features are supported by the target CPU.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000396// Supported features must be enabled by a CpuFeatureScope before use.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000397class CpuFeatures : public AllStatic {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000398 public:
399 // Detect features of the target CPU. Set safe defaults if the serializer
400 // is enabled (snapshots must be portable).
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000401 static void Probe();
lrn@chromium.org7516f052011-03-30 08:52:27 +0000402
403 // Check whether a feature is supported by the target CPU.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000404 static bool IsSupported(CpuFeature f) {
405 ASSERT(initialized_);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000406 if (f == FPU && !FLAG_enable_fpu) return false;
407 return (supported_ & (1u << f)) != 0;
408 }
409
ulan@chromium.org750145a2013-03-07 15:14:13 +0000410 static bool IsFoundByRuntimeProbingOnly(CpuFeature f) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000411 ASSERT(initialized_);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000412 return (found_by_runtime_probing_only_ &
413 (static_cast<uint64_t>(1) << f)) != 0;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000414 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000415
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000416 static bool IsSafeForSnapshot(CpuFeature f) {
417 return (IsSupported(f) &&
418 (!Serializer::enabled() || !IsFoundByRuntimeProbingOnly(f)));
419 }
420
lrn@chromium.org7516f052011-03-30 08:52:27 +0000421 private:
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000422#ifdef DEBUG
423 static bool initialized_;
424#endif
425 static unsigned supported_;
ulan@chromium.org750145a2013-03-07 15:14:13 +0000426 static unsigned found_by_runtime_probing_only_;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000427
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000428 friend class ExternalReference;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000429 DISALLOW_COPY_AND_ASSIGN(CpuFeatures);
430};
431
432
433class Assembler : public AssemblerBase {
ager@chromium.org5c838252010-02-19 08:53:10 +0000434 public:
435 // Create an assembler. Instructions and relocation information are emitted
436 // into a buffer, with the instructions starting from the beginning and the
437 // relocation information starting from the end of the buffer. See CodeDesc
438 // for a detailed comment on the layout (globals.h).
439 //
440 // If the provided buffer is NULL, the assembler allocates and grows its own
441 // buffer, and buffer_size determines the initial buffer size. The buffer is
442 // owned by the assembler and deallocated upon destruction of the assembler.
443 //
444 // If the provided buffer is not NULL, the assembler uses the provided buffer
445 // for code generation and assumes its size to be buffer_size. If the buffer
446 // is too small, a fatal error occurs. No deallocation of the buffer is done
447 // upon destruction of the assembler.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000448 Assembler(Isolate* isolate, void* buffer, int buffer_size);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000449 virtual ~Assembler() { }
ager@chromium.org5c838252010-02-19 08:53:10 +0000450
451 // GetCode emits any pending (non-emitted) code and fills the descriptor
452 // desc. GetCode() is idempotent; it returns the same result if no other
453 // Assembler functions are invoked in between GetCode() calls.
454 void GetCode(CodeDesc* desc);
455
456 // Label operations & relative jumps (PPUM Appendix D).
457 //
458 // Takes a branch opcode (cc) and a label (L) and generates
459 // either a backward branch or a forward branch and links it
460 // to the label fixup chain. Usage:
461 //
462 // Label L; // unbound label
463 // j(cc, &L); // forward branch to unbound label
464 // bind(&L); // bind label to the current pc
465 // j(cc, &L); // backward branch to bound label
466 // bind(&L); // illegal: a label may be bound only once
467 //
468 // Note: The same Label can be used for forward and backward branches
469 // but it may be bound only once.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000470 void bind(Label* L); // Binds an unbound label L to current code position.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000471 // Determines if Label is bound and near enough so that branch instruction
472 // can be used to reach it, instead of jump instruction.
473 bool is_near(Label* L);
ager@chromium.org5c838252010-02-19 08:53:10 +0000474
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000475 // Returns the branch offset to the given label from the current code
476 // position. Links the label to the current position if it is still unbound.
ager@chromium.org5c838252010-02-19 08:53:10 +0000477 // Manages the jump elimination optimization if the second parameter is true.
478 int32_t branch_offset(Label* L, bool jump_elimination_allowed);
479 int32_t shifted_branch_offset(Label* L, bool jump_elimination_allowed) {
480 int32_t o = branch_offset(L, jump_elimination_allowed);
481 ASSERT((o & 3) == 0); // Assert the offset is aligned.
482 return o >> 2;
483 }
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000484 uint32_t jump_address(Label* L);
ager@chromium.org5c838252010-02-19 08:53:10 +0000485
486 // Puts a labels target address at the given position.
487 // The high 8 bits are set to zero.
488 void label_at_put(Label* L, int at_offset);
489
ager@chromium.org5c838252010-02-19 08:53:10 +0000490 // Read/Modify the code target address in the branch/call instruction at pc.
491 static Address target_address_at(Address pc);
492 static void set_target_address_at(Address pc, Address target);
493
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000494 // Return the code target address at a call site from the return address
495 // of that call in the instruction stream.
496 inline static Address target_address_from_return_address(Address pc);
497
lrn@chromium.org34e60782011-09-15 07:25:40 +0000498 static void JumpLabelToJumpRegister(Address pc);
499
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000500 static void QuietNaN(HeapObject* nan);
501
ager@chromium.org5c838252010-02-19 08:53:10 +0000502 // This sets the branch destination (which gets loaded at the call address).
danno@chromium.org88aa0582012-03-23 15:11:57 +0000503 // This is for calls and branches within generated code. The serializer
504 // has already deserialized the lui/ori instructions etc.
505 inline static void deserialization_set_special_target_at(
506 Address instruction_payload, Address target) {
507 set_target_address_at(
508 instruction_payload - kInstructionsFor32BitConstant * kInstrSize,
509 target);
ager@chromium.org5c838252010-02-19 08:53:10 +0000510 }
511
512 // This sets the branch destination.
513 // This is for calls and branches to runtime code.
514 inline static void set_external_target_at(Address instruction_payload,
515 Address target) {
516 set_target_address_at(instruction_payload, target);
517 }
518
lrn@chromium.org7516f052011-03-30 08:52:27 +0000519 // Size of an instruction.
520 static const int kInstrSize = sizeof(Instr);
521
522 // Difference between address of current opcode and target address offset.
523 static const int kBranchPCOffset = 4;
524
525 // Here we are patching the address in the LUI/ORI instruction pair.
526 // These values are used in the serialization process and must be zero for
527 // MIPS platform, as Code, Embedded Object or External-reference pointers
528 // are split across two consecutive instructions and don't exist separately
529 // in the code, so the serializer should not step forwards in memory after
530 // a target is resolved and written.
danno@chromium.org88aa0582012-03-23 15:11:57 +0000531 static const int kSpecialTargetSize = 0;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000532
533 // Number of consecutive instructions used to store 32bit constant.
lrn@chromium.org34e60782011-09-15 07:25:40 +0000534 // Before jump-optimizations, this constant was used in
535 // RelocInfo::target_address_address() function to tell serializer address of
536 // the instruction that follows LUI/ORI instruction pair. Now, with new jump
537 // optimization, where jump-through-register instruction that usually
538 // follows LUI/ORI pair is substituted with J/JAL, this constant equals
539 // to 3 instructions (LUI+ORI+J/JAL/JR/JALR).
540 static const int kInstructionsFor32BitConstant = 3;
ager@chromium.org5c838252010-02-19 08:53:10 +0000541
542 // Distance between the instruction referring to the address of the call
543 // target and the return address.
544 static const int kCallTargetAddressOffset = 4 * kInstrSize;
545
546 // Distance between start of patched return sequence and the emitted address
547 // to jump to.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000548 static const int kPatchReturnSequenceAddressOffset = 0;
ager@chromium.org5c838252010-02-19 08:53:10 +0000549
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000550 // Distance between start of patched debug break slot and the emitted address
551 // to jump to.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000552 static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
553
554 // Difference between address of current opcode and value read from pc
555 // register.
556 static const int kPcLoadDelta = 4;
557
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000558 static const int kPatchDebugBreakSlotReturnOffset = 4 * kInstrSize;
559
lrn@chromium.org7516f052011-03-30 08:52:27 +0000560 // Number of instructions used for the JS return sequence. The constant is
561 // used by the debugger to patch the JS return sequence.
562 static const int kJSReturnSequenceInstructions = 7;
563 static const int kDebugBreakSlotInstructions = 4;
564 static const int kDebugBreakSlotLength =
565 kDebugBreakSlotInstructions * kInstrSize;
566
ager@chromium.org5c838252010-02-19 08:53:10 +0000567
568 // ---------------------------------------------------------------------------
569 // Code generation.
570
lrn@chromium.org7516f052011-03-30 08:52:27 +0000571 // Insert the smallest number of nop instructions
572 // possible to align the pc offset to a multiple
573 // of m. m must be a power of 2 (>= 4).
574 void Align(int m);
575 // Aligns code to something that's optimal for a jump target for the platform.
576 void CodeTargetAlign();
577
578 // Different nop operations are used by the code generator to detect certain
579 // states of the generated code.
580 enum NopMarkerTypes {
581 NON_MARKING_NOP = 0,
582 DEBUG_BREAK_NOP,
583 // IC markers.
584 PROPERTY_ACCESS_INLINED,
585 PROPERTY_ACCESS_INLINED_CONTEXT,
586 PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE,
587 // Helper values.
588 LAST_CODE_MARKER,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000589 FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED,
590 // Code aging
591 CODE_AGE_MARKER_NOP = 6
lrn@chromium.org7516f052011-03-30 08:52:27 +0000592 };
593
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000594 // Type == 0 is the default non-marking nop. For mips this is a
595 // sll(zero_reg, zero_reg, 0). We use rt_reg == at for non-zero
596 // marking, to avoid conflict with ssnop and ehb instructions.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000597 void nop(unsigned int type = 0) {
598 ASSERT(type < 32);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000599 Register nop_rt_reg = (type == 0) ? zero_reg : at;
600 sll(zero_reg, nop_rt_reg, type, true);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000601 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000602
603
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000604 // --------Branch-and-jump-instructions----------
ager@chromium.org5c838252010-02-19 08:53:10 +0000605 // We don't use likely variant of instructions.
606 void b(int16_t offset);
607 void b(Label* L) { b(branch_offset(L, false)>>2); }
608 void bal(int16_t offset);
609 void bal(Label* L) { bal(branch_offset(L, false)>>2); }
610
611 void beq(Register rs, Register rt, int16_t offset);
612 void beq(Register rs, Register rt, Label* L) {
613 beq(rs, rt, branch_offset(L, false) >> 2);
614 }
615 void bgez(Register rs, int16_t offset);
616 void bgezal(Register rs, int16_t offset);
617 void bgtz(Register rs, int16_t offset);
618 void blez(Register rs, int16_t offset);
619 void bltz(Register rs, int16_t offset);
620 void bltzal(Register rs, int16_t offset);
621 void bne(Register rs, Register rt, int16_t offset);
622 void bne(Register rs, Register rt, Label* L) {
623 bne(rs, rt, branch_offset(L, false)>>2);
624 }
625
626 // Never use the int16_t b(l)cond version with a branch offset
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000627 // instead of using the Label* version.
ager@chromium.org5c838252010-02-19 08:53:10 +0000628
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000629 // Jump targets must be in the current 256 MB-aligned region. i.e. 28 bits.
ager@chromium.org5c838252010-02-19 08:53:10 +0000630 void j(int32_t target);
631 void jal(int32_t target);
632 void jalr(Register rs, Register rd = ra);
633 void jr(Register target);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000634 void j_or_jr(int32_t target, Register rs);
635 void jal_or_jalr(int32_t target, Register rs);
ager@chromium.org5c838252010-02-19 08:53:10 +0000636
637
638 //-------Data-processing-instructions---------
639
640 // Arithmetic.
ager@chromium.org5c838252010-02-19 08:53:10 +0000641 void addu(Register rd, Register rs, Register rt);
ager@chromium.org5c838252010-02-19 08:53:10 +0000642 void subu(Register rd, Register rs, Register rt);
643 void mult(Register rs, Register rt);
644 void multu(Register rs, Register rt);
645 void div(Register rs, Register rt);
646 void divu(Register rs, Register rt);
647 void mul(Register rd, Register rs, Register rt);
648
ager@chromium.org5c838252010-02-19 08:53:10 +0000649 void addiu(Register rd, Register rs, int32_t j);
650
651 // Logical.
652 void and_(Register rd, Register rs, Register rt);
653 void or_(Register rd, Register rs, Register rt);
654 void xor_(Register rd, Register rs, Register rt);
655 void nor(Register rd, Register rs, Register rt);
656
657 void andi(Register rd, Register rs, int32_t j);
658 void ori(Register rd, Register rs, int32_t j);
659 void xori(Register rd, Register rs, int32_t j);
660 void lui(Register rd, int32_t j);
661
662 // Shifts.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000663 // Please note: sll(zero_reg, zero_reg, x) instructions are reserved as nop
664 // and may cause problems in normal code. coming_from_nop makes sure this
665 // doesn't happen.
666 void sll(Register rd, Register rt, uint16_t sa, bool coming_from_nop = false);
ager@chromium.org5c838252010-02-19 08:53:10 +0000667 void sllv(Register rd, Register rt, Register rs);
668 void srl(Register rd, Register rt, uint16_t sa);
669 void srlv(Register rd, Register rt, Register rs);
670 void sra(Register rt, Register rd, uint16_t sa);
671 void srav(Register rt, Register rd, Register rs);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000672 void rotr(Register rd, Register rt, uint16_t sa);
673 void rotrv(Register rd, Register rt, Register rs);
ager@chromium.org5c838252010-02-19 08:53:10 +0000674
675
676 //------------Memory-instructions-------------
677
678 void lb(Register rd, const MemOperand& rs);
679 void lbu(Register rd, const MemOperand& rs);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000680 void lh(Register rd, const MemOperand& rs);
681 void lhu(Register rd, const MemOperand& rs);
ager@chromium.org5c838252010-02-19 08:53:10 +0000682 void lw(Register rd, const MemOperand& rs);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000683 void lwl(Register rd, const MemOperand& rs);
684 void lwr(Register rd, const MemOperand& rs);
ager@chromium.org5c838252010-02-19 08:53:10 +0000685 void sb(Register rd, const MemOperand& rs);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000686 void sh(Register rd, const MemOperand& rs);
ager@chromium.org5c838252010-02-19 08:53:10 +0000687 void sw(Register rd, const MemOperand& rs);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000688 void swl(Register rd, const MemOperand& rs);
689 void swr(Register rd, const MemOperand& rs);
ager@chromium.org5c838252010-02-19 08:53:10 +0000690
691
692 //-------------Misc-instructions--------------
693
694 // Break / Trap instructions.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +0000695 void break_(uint32_t code, bool break_as_stop = false);
696 void stop(const char* msg, uint32_t code = kMaxStopCode);
ager@chromium.org5c838252010-02-19 08:53:10 +0000697 void tge(Register rs, Register rt, uint16_t code);
698 void tgeu(Register rs, Register rt, uint16_t code);
699 void tlt(Register rs, Register rt, uint16_t code);
700 void tltu(Register rs, Register rt, uint16_t code);
701 void teq(Register rs, Register rt, uint16_t code);
702 void tne(Register rs, Register rt, uint16_t code);
703
704 // Move from HI/LO register.
705 void mfhi(Register rd);
706 void mflo(Register rd);
707
708 // Set on less than.
709 void slt(Register rd, Register rs, Register rt);
710 void sltu(Register rd, Register rs, Register rt);
711 void slti(Register rd, Register rs, int32_t j);
712 void sltiu(Register rd, Register rs, int32_t j);
713
lrn@chromium.org7516f052011-03-30 08:52:27 +0000714 // Conditional move.
715 void movz(Register rd, Register rs, Register rt);
716 void movn(Register rd, Register rs, Register rt);
717 void movt(Register rd, Register rs, uint16_t cc = 0);
718 void movf(Register rd, Register rs, uint16_t cc = 0);
719
720 // Bit twiddling.
721 void clz(Register rd, Register rs);
722 void ins_(Register rt, Register rs, uint16_t pos, uint16_t size);
723 void ext_(Register rt, Register rs, uint16_t pos, uint16_t size);
ager@chromium.org5c838252010-02-19 08:53:10 +0000724
725 //--------Coprocessor-instructions----------------
726
727 // Load, store, and move.
728 void lwc1(FPURegister fd, const MemOperand& src);
729 void ldc1(FPURegister fd, const MemOperand& src);
730
731 void swc1(FPURegister fs, const MemOperand& dst);
732 void sdc1(FPURegister fs, const MemOperand& dst);
733
lrn@chromium.org7516f052011-03-30 08:52:27 +0000734 void mtc1(Register rt, FPURegister fs);
735 void mfc1(Register rt, FPURegister fs);
736
737 void ctc1(Register rt, FPUControlRegister fs);
738 void cfc1(Register rt, FPUControlRegister fs);
739
740 // Arithmetic.
741 void add_d(FPURegister fd, FPURegister fs, FPURegister ft);
742 void sub_d(FPURegister fd, FPURegister fs, FPURegister ft);
743 void mul_d(FPURegister fd, FPURegister fs, FPURegister ft);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000744 void madd_d(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000745 void div_d(FPURegister fd, FPURegister fs, FPURegister ft);
746 void abs_d(FPURegister fd, FPURegister fs);
747 void mov_d(FPURegister fd, FPURegister fs);
748 void neg_d(FPURegister fd, FPURegister fs);
749 void sqrt_d(FPURegister fd, FPURegister fs);
ager@chromium.org5c838252010-02-19 08:53:10 +0000750
751 // Conversion.
752 void cvt_w_s(FPURegister fd, FPURegister fs);
753 void cvt_w_d(FPURegister fd, FPURegister fs);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000754 void trunc_w_s(FPURegister fd, FPURegister fs);
755 void trunc_w_d(FPURegister fd, FPURegister fs);
756 void round_w_s(FPURegister fd, FPURegister fs);
757 void round_w_d(FPURegister fd, FPURegister fs);
758 void floor_w_s(FPURegister fd, FPURegister fs);
759 void floor_w_d(FPURegister fd, FPURegister fs);
760 void ceil_w_s(FPURegister fd, FPURegister fs);
761 void ceil_w_d(FPURegister fd, FPURegister fs);
ager@chromium.org5c838252010-02-19 08:53:10 +0000762
763 void cvt_l_s(FPURegister fd, FPURegister fs);
764 void cvt_l_d(FPURegister fd, FPURegister fs);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000765 void trunc_l_s(FPURegister fd, FPURegister fs);
766 void trunc_l_d(FPURegister fd, FPURegister fs);
767 void round_l_s(FPURegister fd, FPURegister fs);
768 void round_l_d(FPURegister fd, FPURegister fs);
769 void floor_l_s(FPURegister fd, FPURegister fs);
770 void floor_l_d(FPURegister fd, FPURegister fs);
771 void ceil_l_s(FPURegister fd, FPURegister fs);
772 void ceil_l_d(FPURegister fd, FPURegister fs);
ager@chromium.org5c838252010-02-19 08:53:10 +0000773
774 void cvt_s_w(FPURegister fd, FPURegister fs);
775 void cvt_s_l(FPURegister fd, FPURegister fs);
776 void cvt_s_d(FPURegister fd, FPURegister fs);
777
778 void cvt_d_w(FPURegister fd, FPURegister fs);
779 void cvt_d_l(FPURegister fd, FPURegister fs);
780 void cvt_d_s(FPURegister fd, FPURegister fs);
781
782 // Conditions and branches.
783 void c(FPUCondition cond, SecondaryField fmt,
784 FPURegister ft, FPURegister fs, uint16_t cc = 0);
785
786 void bc1f(int16_t offset, uint16_t cc = 0);
787 void bc1f(Label* L, uint16_t cc = 0) { bc1f(branch_offset(L, false)>>2, cc); }
788 void bc1t(int16_t offset, uint16_t cc = 0);
789 void bc1t(Label* L, uint16_t cc = 0) { bc1t(branch_offset(L, false)>>2, cc); }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000790 void fcmp(FPURegister src1, const double src2, FPUCondition cond);
ager@chromium.org5c838252010-02-19 08:53:10 +0000791
792 // Check the code size generated from label to here.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000793 int SizeOfCodeGeneratedSince(Label* label) {
794 return pc_offset() - label->pos();
795 }
796
797 // Check the number of instructions generated from label to here.
798 int InstructionsGeneratedSince(Label* label) {
799 return SizeOfCodeGeneratedSince(label) / kInstrSize;
ager@chromium.org5c838252010-02-19 08:53:10 +0000800 }
801
lrn@chromium.org7516f052011-03-30 08:52:27 +0000802 // Class for scoping postponing the trampoline pool generation.
803 class BlockTrampolinePoolScope {
804 public:
805 explicit BlockTrampolinePoolScope(Assembler* assem) : assem_(assem) {
806 assem_->StartBlockTrampolinePool();
807 }
808 ~BlockTrampolinePoolScope() {
809 assem_->EndBlockTrampolinePool();
810 }
811
812 private:
813 Assembler* assem_;
814
815 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockTrampolinePoolScope);
816 };
817
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000818 // Class for postponing the assembly buffer growth. Typically used for
819 // sequences of instructions that must be emitted as a unit, before
820 // buffer growth (and relocation) can occur.
821 // This blocking scope is not nestable.
822 class BlockGrowBufferScope {
823 public:
824 explicit BlockGrowBufferScope(Assembler* assem) : assem_(assem) {
825 assem_->StartBlockGrowBuffer();
826 }
827 ~BlockGrowBufferScope() {
828 assem_->EndBlockGrowBuffer();
829 }
830
831 private:
832 Assembler* assem_;
833
834 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockGrowBufferScope);
835 };
836
ager@chromium.org5c838252010-02-19 08:53:10 +0000837 // Debugging.
838
839 // Mark address of the ExitJSFrame code.
840 void RecordJSReturn();
841
lrn@chromium.org7516f052011-03-30 08:52:27 +0000842 // Mark address of a debug break slot.
843 void RecordDebugBreakSlot();
844
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000845 // Record the AST id of the CallIC being compiled, so that it can be placed
846 // in the relocation information.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000847 void SetRecordedAstId(TypeFeedbackId ast_id) {
848 ASSERT(recorded_ast_id_.IsNone());
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000849 recorded_ast_id_ = ast_id;
850 }
851
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000852 TypeFeedbackId RecordedAstId() {
853 ASSERT(!recorded_ast_id_.IsNone());
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000854 return recorded_ast_id_;
855 }
856
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000857 void ClearRecordedAstId() { recorded_ast_id_ = TypeFeedbackId::None(); }
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000858
ager@chromium.org5c838252010-02-19 08:53:10 +0000859 // Record a comment relocation entry that can be used by a disassembler.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000860 // Use --code-comments to enable.
ager@chromium.org5c838252010-02-19 08:53:10 +0000861 void RecordComment(const char* msg);
862
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000863 static int RelocateInternalReference(byte* pc, intptr_t pc_delta);
864
lrn@chromium.org7516f052011-03-30 08:52:27 +0000865 // Writes a single byte or word of data in the code stream. Used for
866 // inline tables, e.g., jump-tables.
867 void db(uint8_t data);
868 void dd(uint32_t data);
ager@chromium.org5c838252010-02-19 08:53:10 +0000869
lrn@chromium.org7516f052011-03-30 08:52:27 +0000870 PositionsRecorder* positions_recorder() { return &positions_recorder_; }
871
lrn@chromium.org7516f052011-03-30 08:52:27 +0000872 // Postpone the generation of the trampoline pool for the specified number of
873 // instructions.
874 void BlockTrampolinePoolFor(int instructions);
875
ager@chromium.org5c838252010-02-19 08:53:10 +0000876 // Check if there is less than kGap bytes available in the buffer.
877 // If this is the case, we need to grow the buffer before emitting
878 // an instruction or relocation information.
879 inline bool overflow() const { return pc_ >= reloc_info_writer.pos() - kGap; }
880
881 // Get the number of bytes available in the buffer.
882 inline int available_space() const { return reloc_info_writer.pos() - pc_; }
883
ager@chromium.org5c838252010-02-19 08:53:10 +0000884 // Read/patch instructions.
885 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000886 static void instr_at_put(byte* pc, Instr instr) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000887 *reinterpret_cast<Instr*>(pc) = instr;
888 }
889 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
890 void instr_at_put(int pos, Instr instr) {
891 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
892 }
893
894 // Check if an instruction is a branch of some kind.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000895 static bool IsBranch(Instr instr);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000896 static bool IsBeq(Instr instr);
897 static bool IsBne(Instr instr);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000898
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000899 static bool IsJump(Instr instr);
900 static bool IsJ(Instr instr);
901 static bool IsLui(Instr instr);
902 static bool IsOri(Instr instr);
903
lrn@chromium.org34e60782011-09-15 07:25:40 +0000904 static bool IsJal(Instr instr);
905 static bool IsJr(Instr instr);
906 static bool IsJalr(Instr instr);
907
lrn@chromium.org7516f052011-03-30 08:52:27 +0000908 static bool IsNop(Instr instr, unsigned int type);
909 static bool IsPop(Instr instr);
910 static bool IsPush(Instr instr);
911 static bool IsLwRegFpOffset(Instr instr);
912 static bool IsSwRegFpOffset(Instr instr);
913 static bool IsLwRegFpNegOffset(Instr instr);
914 static bool IsSwRegFpNegOffset(Instr instr);
915
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000916 static Register GetRtReg(Instr instr);
917 static Register GetRsReg(Instr instr);
918 static Register GetRdReg(Instr instr);
919
920 static uint32_t GetRt(Instr instr);
921 static uint32_t GetRtField(Instr instr);
922 static uint32_t GetRs(Instr instr);
923 static uint32_t GetRsField(Instr instr);
924 static uint32_t GetRd(Instr instr);
925 static uint32_t GetRdField(Instr instr);
926 static uint32_t GetSa(Instr instr);
927 static uint32_t GetSaField(Instr instr);
928 static uint32_t GetOpcodeField(Instr instr);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000929 static uint32_t GetFunction(Instr instr);
930 static uint32_t GetFunctionField(Instr instr);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000931 static uint32_t GetImmediate16(Instr instr);
932 static uint32_t GetLabelConst(Instr instr);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000933
934 static int32_t GetBranchOffset(Instr instr);
935 static bool IsLw(Instr instr);
936 static int16_t GetLwOffset(Instr instr);
937 static Instr SetLwOffset(Instr instr, int16_t offset);
938
939 static bool IsSw(Instr instr);
940 static Instr SetSwOffset(Instr instr, int16_t offset);
941 static bool IsAddImmediate(Instr instr);
942 static Instr SetAddImmediateOffset(Instr instr, int16_t offset);
943
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000944 static bool IsAndImmediate(Instr instr);
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000945 static bool IsEmittedConstant(Instr instr);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000946
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000947 void CheckTrampolinePool();
lrn@chromium.org7516f052011-03-30 08:52:27 +0000948
949 protected:
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000950 // Relocation for a type-recording IC has the AST id added to it. This
951 // member variable is a way to pass the information from the call site to
952 // the relocation info.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000953 TypeFeedbackId recorded_ast_id_;
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000954
lrn@chromium.org7516f052011-03-30 08:52:27 +0000955 int32_t buffer_space() const { return reloc_info_writer.pos() - pc_; }
ager@chromium.org5c838252010-02-19 08:53:10 +0000956
957 // Decode branch instruction at pos and return branch target pos.
958 int target_at(int32_t pos);
959
960 // Patch branch instruction at pos to branch to given branch target pos.
961 void target_at_put(int32_t pos, int32_t target_pos);
962
963 // Say if we need to relocate with this mode.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000964 bool MustUseReg(RelocInfo::Mode rmode);
ager@chromium.org5c838252010-02-19 08:53:10 +0000965
966 // Record reloc info for current pc_.
967 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
968
lrn@chromium.org7516f052011-03-30 08:52:27 +0000969 // Block the emission of the trampoline pool before pc_offset.
970 void BlockTrampolinePoolBefore(int pc_offset) {
971 if (no_trampoline_pool_before_ < pc_offset)
972 no_trampoline_pool_before_ = pc_offset;
973 }
974
975 void StartBlockTrampolinePool() {
976 trampoline_pool_blocked_nesting_++;
977 }
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000978
lrn@chromium.org7516f052011-03-30 08:52:27 +0000979 void EndBlockTrampolinePool() {
980 trampoline_pool_blocked_nesting_--;
981 }
982
983 bool is_trampoline_pool_blocked() const {
984 return trampoline_pool_blocked_nesting_ > 0;
985 }
986
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000987 bool has_exception() const {
988 return internal_trampoline_exception_;
989 }
990
lrn@chromium.org34e60782011-09-15 07:25:40 +0000991 void DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi);
992
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000993 bool is_trampoline_emitted() const {
994 return trampoline_emitted_;
995 }
996
997 // Temporarily block automatic assembly buffer growth.
998 void StartBlockGrowBuffer() {
999 ASSERT(!block_buffer_growth_);
1000 block_buffer_growth_ = true;
1001 }
1002
1003 void EndBlockGrowBuffer() {
1004 ASSERT(block_buffer_growth_);
1005 block_buffer_growth_ = false;
1006 }
1007
1008 bool is_buffer_growth_blocked() const {
1009 return block_buffer_growth_;
1010 }
1011
ager@chromium.org5c838252010-02-19 08:53:10 +00001012 private:
ager@chromium.org5c838252010-02-19 08:53:10 +00001013 // Buffer size and constant pool distance are checked together at regular
1014 // intervals of kBufferCheckInterval emitted bytes.
1015 static const int kBufferCheckInterval = 1*KB/2;
1016
1017 // Code generation.
1018 // The relocation writer's position is at least kGap bytes below the end of
1019 // the generated instructions. This is so that multi-instruction sequences do
1020 // not have to check for overflow. The same is true for writes of large
1021 // relocation info entries.
1022 static const int kGap = 32;
ager@chromium.org5c838252010-02-19 08:53:10 +00001023
lrn@chromium.org7516f052011-03-30 08:52:27 +00001024
1025 // Repeated checking whether the trampoline pool should be emitted is rather
1026 // expensive. By default we only check again once a number of instructions
1027 // has been generated.
1028 static const int kCheckConstIntervalInst = 32;
1029 static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize;
1030
1031 int next_buffer_check_; // pc offset of next buffer check.
1032
1033 // Emission of the trampoline pool may be blocked in some code sequences.
1034 int trampoline_pool_blocked_nesting_; // Block emission if this is not zero.
1035 int no_trampoline_pool_before_; // Block emission before this pc offset.
1036
1037 // Keep track of the last emitted pool to guarantee a maximal distance.
1038 int last_trampoline_pool_end_; // pc offset of the end of the last pool.
1039
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001040 // Automatic growth of the assembly buffer may be blocked for some sequences.
1041 bool block_buffer_growth_; // Block growth when true.
1042
ager@chromium.org5c838252010-02-19 08:53:10 +00001043 // Relocation information generation.
1044 // Each relocation is encoded as a variable size value.
1045 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1046 RelocInfoWriter reloc_info_writer;
1047
1048 // The bound position, before this we cannot do instruction elimination.
1049 int last_bound_pos_;
1050
ager@chromium.org5c838252010-02-19 08:53:10 +00001051 // Code emission.
1052 inline void CheckBuffer();
1053 void GrowBuffer();
1054 inline void emit(Instr x);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001055 inline void CheckTrampolinePoolQuick();
ager@chromium.org5c838252010-02-19 08:53:10 +00001056
1057 // Instruction generation.
1058 // We have 3 different kind of encoding layout on MIPS.
1059 // However due to many different types of objects encoded in the same fields
1060 // we have quite a few aliases for each mode.
1061 // Using the same structure to refer to Register and FPURegister would spare a
1062 // few aliases, but mixing both does not look clean to me.
1063 // Anyway we could surely implement this differently.
1064
1065 void GenInstrRegister(Opcode opcode,
1066 Register rs,
1067 Register rt,
1068 Register rd,
1069 uint16_t sa = 0,
1070 SecondaryField func = NULLSF);
1071
1072 void GenInstrRegister(Opcode opcode,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001073 Register rs,
1074 Register rt,
1075 uint16_t msb,
1076 uint16_t lsb,
1077 SecondaryField func);
1078
1079 void GenInstrRegister(Opcode opcode,
ager@chromium.org5c838252010-02-19 08:53:10 +00001080 SecondaryField fmt,
1081 FPURegister ft,
1082 FPURegister fs,
1083 FPURegister fd,
1084 SecondaryField func = NULLSF);
1085
1086 void GenInstrRegister(Opcode opcode,
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001087 FPURegister fr,
1088 FPURegister ft,
1089 FPURegister fs,
1090 FPURegister fd,
1091 SecondaryField func = NULLSF);
1092
1093 void GenInstrRegister(Opcode opcode,
ager@chromium.org5c838252010-02-19 08:53:10 +00001094 SecondaryField fmt,
1095 Register rt,
1096 FPURegister fs,
1097 FPURegister fd,
1098 SecondaryField func = NULLSF);
1099
lrn@chromium.org7516f052011-03-30 08:52:27 +00001100 void GenInstrRegister(Opcode opcode,
1101 SecondaryField fmt,
1102 Register rt,
1103 FPUControlRegister fs,
1104 SecondaryField func = NULLSF);
1105
ager@chromium.org5c838252010-02-19 08:53:10 +00001106
1107 void GenInstrImmediate(Opcode opcode,
1108 Register rs,
1109 Register rt,
1110 int32_t j);
1111 void GenInstrImmediate(Opcode opcode,
1112 Register rs,
1113 SecondaryField SF,
1114 int32_t j);
1115 void GenInstrImmediate(Opcode opcode,
1116 Register r1,
1117 FPURegister r2,
1118 int32_t j);
1119
1120
1121 void GenInstrJump(Opcode opcode,
1122 uint32_t address);
1123
lrn@chromium.org7516f052011-03-30 08:52:27 +00001124 // Helpers.
1125 void LoadRegPlusOffsetToAt(const MemOperand& src);
ager@chromium.org5c838252010-02-19 08:53:10 +00001126
1127 // Labels.
1128 void print(Label* L);
1129 void bind_to(Label* L, int pos);
ager@chromium.org5c838252010-02-19 08:53:10 +00001130 void next(Label* L);
1131
lrn@chromium.org7516f052011-03-30 08:52:27 +00001132 // One trampoline consists of:
1133 // - space for trampoline slots,
1134 // - space for labels.
1135 //
1136 // Space for trampoline slots is equal to slot_count * 2 * kInstrSize.
1137 // Space for trampoline slots preceeds space for labels. Each label is of one
1138 // instruction size, so total amount for labels is equal to
1139 // label_count * kInstrSize.
1140 class Trampoline {
1141 public:
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001142 Trampoline() {
1143 start_ = 0;
1144 next_slot_ = 0;
1145 free_slot_count_ = 0;
1146 end_ = 0;
1147 }
1148 Trampoline(int start, int slot_count) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001149 start_ = start;
1150 next_slot_ = start;
1151 free_slot_count_ = slot_count;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001152 end_ = start + slot_count * kTrampolineSlotsSize;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001153 }
1154 int start() {
1155 return start_;
1156 }
1157 int end() {
1158 return end_;
1159 }
1160 int take_slot() {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001161 int trampoline_slot = kInvalidSlotPos;
1162 if (free_slot_count_ <= 0) {
1163 // We have run out of space on trampolines.
1164 // Make sure we fail in debug mode, so we become aware of each case
1165 // when this happens.
1166 ASSERT(0);
1167 // Internal exception will be caught.
1168 } else {
1169 trampoline_slot = next_slot_;
1170 free_slot_count_--;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001171 next_slot_ += kTrampolineSlotsSize;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001172 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001173 return trampoline_slot;
1174 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001175
lrn@chromium.org7516f052011-03-30 08:52:27 +00001176 private:
1177 int start_;
1178 int end_;
1179 int next_slot_;
1180 int free_slot_count_;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001181 };
1182
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001183 int32_t get_trampoline_entry(int32_t pos);
1184 int unbound_labels_count_;
1185 // If trampoline is emitted, generated code is becoming large. As this is
1186 // already a slow case which can possibly break our code generation for the
1187 // extreme case, we use this information to trigger different mode of
1188 // branch instruction generation, where we use jump instructions rather
1189 // than regular branch instructions.
1190 bool trampoline_emitted_;
1191 static const int kTrampolineSlotsSize = 4 * kInstrSize;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001192 static const int kMaxBranchOffset = (1 << (18 - 1)) - 1;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001193 static const int kInvalidSlotPos = -1;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001194
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001195 Trampoline trampoline_;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001196 bool internal_trampoline_exception_;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001197
ager@chromium.org5c838252010-02-19 08:53:10 +00001198 friend class RegExpMacroAssemblerMIPS;
1199 friend class RelocInfo;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001200 friend class CodePatcher;
1201 friend class BlockTrampolinePoolScope;
1202
1203 PositionsRecorder positions_recorder_;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001204 friend class PositionsRecorder;
1205 friend class EnsureSpace;
1206};
1207
1208
1209class EnsureSpace BASE_EMBEDDED {
1210 public:
1211 explicit EnsureSpace(Assembler* assembler) {
1212 assembler->CheckBuffer();
1213 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001214};
1215
1216} } // namespace v8::internal
1217
1218#endif // V8_ARM_ASSEMBLER_MIPS_H_