blob: c595cc9e2e118f77d40b15d3dd42fd71e0f20064 [file] [log] [blame]
Andrei Popescu31002712010-02-23 13:46:05 +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 Murdoch3ef787d2012-04-12 10:51:47 +010033// Copyright 2012 the V8 project authors. All rights reserved.
Andrei Popescu31002712010-02-23 13:46:05 +000034
35
36#ifndef V8_MIPS_ASSEMBLER_MIPS_H_
37#define V8_MIPS_ASSEMBLER_MIPS_H_
38
39#include <stdio.h>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000040
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000041#include <set>
42
Ben Murdochb8a8cc12014-11-26 15:28:44 +000043#include "src/assembler.h"
44#include "src/mips/constants-mips.h"
Andrei Popescu31002712010-02-23 13:46:05 +000045
Andrei Popescu31002712010-02-23 13:46:05 +000046namespace v8 {
47namespace internal {
48
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000049// clang-format off
50#define GENERAL_REGISTERS(V) \
51 V(zero_reg) V(at) V(v0) V(v1) V(a0) V(a1) V(a2) V(a3) \
52 V(t0) V(t1) V(t2) V(t3) V(t4) V(t5) V(t6) V(t7) \
53 V(s0) V(s1) V(s2) V(s3) V(s4) V(s5) V(s6) V(s7) V(t8) V(t9) \
54 V(k0) V(k1) V(gp) V(sp) V(fp) V(ra)
55
56#define ALLOCATABLE_GENERAL_REGISTERS(V) \
57 V(v0) V(v1) V(a0) V(a1) V(a2) V(a3) \
58 V(t0) V(t1) V(t2) V(t3) V(t4) V(t5) V(t6) V(s7)
59
60#define DOUBLE_REGISTERS(V) \
61 V(f0) V(f1) V(f2) V(f3) V(f4) V(f5) V(f6) V(f7) \
62 V(f8) V(f9) V(f10) V(f11) V(f12) V(f13) V(f14) V(f15) \
63 V(f16) V(f17) V(f18) V(f19) V(f20) V(f21) V(f22) V(f23) \
64 V(f24) V(f25) V(f26) V(f27) V(f28) V(f29) V(f30) V(f31)
65
Ben Murdochc5610432016-08-08 18:44:38 +010066#define FLOAT_REGISTERS DOUBLE_REGISTERS
67
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000068#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
69 V(f0) V(f2) V(f4) V(f6) V(f8) V(f10) V(f12) V(f14) \
70 V(f16) V(f18) V(f20) V(f22) V(f24) V(f26)
71// clang-format on
72
Andrei Popescu31002712010-02-23 13:46:05 +000073// CPU Registers.
74//
75// 1) We would prefer to use an enum, but enum values are assignment-
76// compatible with int, which has caused code-generation bugs.
77//
78// 2) We would prefer to use a class instead of a struct but we don't like
79// the register initialization to depend on the particular initialization
80// order (which appears to be different on OS X, Linux, and Windows for the
81// installed versions of C++ we tried). Using a struct permits C-style
82// "initialization". Also, the Register objects cannot be const as this
83// forces initialization stubs in MSVC, making us dependent on initialization
84// order.
85//
86// 3) By not using an enum, we are possibly preventing the compiler from
87// doing certain constant folds, which may significantly reduce the
88// code generated for some assembly instructions (because they boil down
89// to a few constants). If this is a problem, we could change the code
90// such that we use an enum in optimized mode, and the struct in debug
91// mode. This way we get the compile-time error checking in debug mode
92// and best performance in optimized code.
93
94
95// -----------------------------------------------------------------------------
Ben Murdoch257744e2011-11-30 15:57:28 +000096// Implementation of Register and FPURegister.
Andrei Popescu31002712010-02-23 13:46:05 +000097
Andrei Popescu31002712010-02-23 13:46:05 +000098struct Register {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000099 static const int kCpRegister = 23; // cp (s7) is the 23rd register.
100
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000101 enum Code {
102#define REGISTER_CODE(R) kCode_##R,
103 GENERAL_REGISTERS(REGISTER_CODE)
104#undef REGISTER_CODE
105 kAfterLast,
106 kCode_no_reg = -1
107 };
108
109 static const int kNumRegisters = Code::kAfterLast;
110
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000111#if defined(V8_TARGET_LITTLE_ENDIAN)
112 static const int kMantissaOffset = 0;
113 static const int kExponentOffset = 4;
114#elif defined(V8_TARGET_BIG_ENDIAN)
115 static const int kMantissaOffset = 4;
116 static const int kExponentOffset = 0;
117#else
118#error Unknown endianness
119#endif
120
Steve Block44f0eee2011-05-26 01:26:41 +0100121
122 static Register from_code(int code) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000123 DCHECK(code >= 0);
124 DCHECK(code < kNumRegisters);
125 Register r = {code};
Steve Block44f0eee2011-05-26 01:26:41 +0100126 return r;
127 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000128 const char* ToString();
129 bool IsAllocatable() const;
130 bool is_valid() const { return 0 <= reg_code && reg_code < kNumRegisters; }
131 bool is(Register reg) const { return reg_code == reg.reg_code; }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100132 int code() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000133 DCHECK(is_valid());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000134 return reg_code;
Andrei Popescu31002712010-02-23 13:46:05 +0000135 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100136 int bit() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000137 DCHECK(is_valid());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000138 return 1 << reg_code;
Andrei Popescu31002712010-02-23 13:46:05 +0000139 }
140
141 // Unfortunately we can't make this private in a struct.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000142 int reg_code;
Andrei Popescu31002712010-02-23 13:46:05 +0000143};
144
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000145// s7: context register
146// s3: lithium scratch
147// s4: lithium scratch2
148#define DECLARE_REGISTER(R) const Register R = {Register::kCode_##R};
149GENERAL_REGISTERS(DECLARE_REGISTER)
150#undef DECLARE_REGISTER
151const Register no_reg = {Register::kCode_no_reg};
Steve Block44f0eee2011-05-26 01:26:41 +0100152
Andrei Popescu31002712010-02-23 13:46:05 +0000153
154int ToNumber(Register reg);
155
156Register ToRegister(int num);
157
158// Coprocessor register.
Ben Murdochc5610432016-08-08 18:44:38 +0100159struct FPURegister {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000160 enum Code {
161#define REGISTER_CODE(R) kCode_##R,
162 DOUBLE_REGISTERS(REGISTER_CODE)
163#undef REGISTER_CODE
164 kAfterLast,
165 kCode_no_reg = -1
166 };
167
168 static const int kMaxNumRegisters = Code::kAfterLast;
169
170 inline static int NumRegisters();
Ben Murdoch589d6972011-11-30 16:04:58 +0000171
172 // TODO(plind): Warning, inconsistent numbering here. kNumFPURegisters refers
173 // to number of 32-bit FPU regs, but kNumAllocatableRegisters refers to
174 // number of Double regs (64-bit regs, or FPU-reg-pairs).
175
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000176 const char* ToString();
177 bool IsAllocatable() const;
178 bool is_valid() const { return 0 <= reg_code && reg_code < kMaxNumRegisters; }
Ben Murdochc5610432016-08-08 18:44:38 +0100179 bool is(FPURegister reg) const { return reg_code == reg.reg_code; }
180 FPURegister low() const {
Ben Murdoch589d6972011-11-30 16:04:58 +0000181 // Find low reg of a Double-reg pair, which is the reg itself.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000182 DCHECK(reg_code % 2 == 0); // Specified Double reg must be even.
Ben Murdochc5610432016-08-08 18:44:38 +0100183 FPURegister reg;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000184 reg.reg_code = reg_code;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000185 DCHECK(reg.is_valid());
Ben Murdoch589d6972011-11-30 16:04:58 +0000186 return reg;
187 }
Ben Murdochc5610432016-08-08 18:44:38 +0100188 FPURegister high() const {
Ben Murdoch589d6972011-11-30 16:04:58 +0000189 // Find high reg of a Doubel-reg pair, which is reg + 1.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000190 DCHECK(reg_code % 2 == 0); // Specified Double reg must be even.
Ben Murdochc5610432016-08-08 18:44:38 +0100191 FPURegister reg;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000192 reg.reg_code = reg_code + 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000193 DCHECK(reg.is_valid());
Ben Murdoch589d6972011-11-30 16:04:58 +0000194 return reg;
195 }
196
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100197 int code() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000198 DCHECK(is_valid());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000199 return reg_code;
Andrei Popescu31002712010-02-23 13:46:05 +0000200 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100201 int bit() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000202 DCHECK(is_valid());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000203 return 1 << reg_code;
204 }
205
Ben Murdochc5610432016-08-08 18:44:38 +0100206 static FPURegister from_code(int code) {
207 FPURegister r = {code};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000208 return r;
Andrei Popescu31002712010-02-23 13:46:05 +0000209 }
Steve Block44f0eee2011-05-26 01:26:41 +0100210 void setcode(int f) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000211 reg_code = f;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000212 DCHECK(is_valid());
Steve Block44f0eee2011-05-26 01:26:41 +0100213 }
Andrei Popescu31002712010-02-23 13:46:05 +0000214 // Unfortunately we can't make this private in a struct.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000215 int reg_code;
Andrei Popescu31002712010-02-23 13:46:05 +0000216};
217
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000218// A few double registers are reserved: one as a scratch register and one to
219// hold 0.0.
220// f28: 0.0
221// f30: scratch register.
222
Ben Murdoch589d6972011-11-30 16:04:58 +0000223// V8 now supports the O32 ABI, and the FPU Registers are organized as 32
224// 32-bit registers, f0 through f31. When used as 'double' they are used
225// in pairs, starting with the even numbered register. So a double operation
226// on f0 really uses f0 and f1.
227// (Modern mips hardware also supports 32 64-bit registers, via setting
228// (priviledged) Status Register FR bit to 1. This is used by the N32 ABI,
229// but it is not in common use. Someday we will want to support this in v8.)
Andrei Popescu31002712010-02-23 13:46:05 +0000230
Ben Murdoch589d6972011-11-30 16:04:58 +0000231// For O32 ABI, Floats and Doubles refer to same set of 32 32-bit registers.
Ben Murdochc5610432016-08-08 18:44:38 +0100232typedef FPURegister FloatRegister;
233
234typedef FPURegister DoubleRegister;
235
236// TODO(mips) Define SIMD registers.
237typedef FPURegister Simd128Register;
Ben Murdoch589d6972011-11-30 16:04:58 +0000238
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000239const DoubleRegister no_freg = {-1};
Andrei Popescu31002712010-02-23 13:46:05 +0000240
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000241const DoubleRegister f0 = {0}; // Return value in hard float mode.
242const DoubleRegister f1 = {1};
243const DoubleRegister f2 = {2};
244const DoubleRegister f3 = {3};
245const DoubleRegister f4 = {4};
246const DoubleRegister f5 = {5};
247const DoubleRegister f6 = {6};
248const DoubleRegister f7 = {7};
249const DoubleRegister f8 = {8};
250const DoubleRegister f9 = {9};
251const DoubleRegister f10 = {10};
252const DoubleRegister f11 = {11};
253const DoubleRegister f12 = {12}; // Arg 0 in hard float mode.
254const DoubleRegister f13 = {13};
255const DoubleRegister f14 = {14}; // Arg 1 in hard float mode.
256const DoubleRegister f15 = {15};
257const DoubleRegister f16 = {16};
258const DoubleRegister f17 = {17};
259const DoubleRegister f18 = {18};
260const DoubleRegister f19 = {19};
261const DoubleRegister f20 = {20};
262const DoubleRegister f21 = {21};
263const DoubleRegister f22 = {22};
264const DoubleRegister f23 = {23};
265const DoubleRegister f24 = {24};
266const DoubleRegister f25 = {25};
267const DoubleRegister f26 = {26};
268const DoubleRegister f27 = {27};
269const DoubleRegister f28 = {28};
270const DoubleRegister f29 = {29};
271const DoubleRegister f30 = {30};
272const DoubleRegister f31 = {31};
Andrei Popescu31002712010-02-23 13:46:05 +0000273
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100274// Register aliases.
275// cp is assumed to be a callee saved register.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000276// Defined using #define instead of "static const Register&" because Clang
277// complains otherwise when a compilation unit that includes this header
278// doesn't use the variables.
279#define kRootRegister s6
280#define cp s7
281#define kLithiumScratchReg s3
282#define kLithiumScratchReg2 s4
283#define kLithiumScratchDouble f30
284#define kDoubleRegZero f28
285// Used on mips32r6 for compare operations.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000286// We use the last non-callee saved odd register for O32 ABI
287#define kDoubleCompareReg f19
Ben Murdoch589d6972011-11-30 16:04:58 +0000288
Steve Block44f0eee2011-05-26 01:26:41 +0100289// FPU (coprocessor 1) control registers.
290// Currently only FCSR (#31) is implemented.
291struct FPUControlRegister {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000292 bool is_valid() const { return reg_code == kFCSRRegister; }
293 bool is(FPUControlRegister creg) const { return reg_code == creg.reg_code; }
Steve Block44f0eee2011-05-26 01:26:41 +0100294 int code() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000295 DCHECK(is_valid());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000296 return reg_code;
Steve Block44f0eee2011-05-26 01:26:41 +0100297 }
298 int bit() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000299 DCHECK(is_valid());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000300 return 1 << reg_code;
Steve Block44f0eee2011-05-26 01:26:41 +0100301 }
302 void setcode(int f) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000303 reg_code = f;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000304 DCHECK(is_valid());
Steve Block44f0eee2011-05-26 01:26:41 +0100305 }
306 // Unfortunately we can't make this private in a struct.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000307 int reg_code;
Andrei Popescu31002712010-02-23 13:46:05 +0000308};
309
Ben Murdoch257744e2011-11-30 15:57:28 +0000310const FPUControlRegister no_fpucreg = { kInvalidFPUControlRegister };
Steve Block44f0eee2011-05-26 01:26:41 +0100311const FPUControlRegister FCSR = { kFCSRRegister };
Andrei Popescu31002712010-02-23 13:46:05 +0000312
Andrei Popescu31002712010-02-23 13:46:05 +0000313// -----------------------------------------------------------------------------
314// Machine instruction Operands.
315
316// Class Operand represents a shifter operand in data processing instructions.
317class Operand BASE_EMBEDDED {
318 public:
319 // Immediate.
320 INLINE(explicit Operand(int32_t immediate,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000321 RelocInfo::Mode rmode = RelocInfo::NONE32));
Andrei Popescu31002712010-02-23 13:46:05 +0000322 INLINE(explicit Operand(const ExternalReference& f));
323 INLINE(explicit Operand(const char* s));
324 INLINE(explicit Operand(Object** opp));
325 INLINE(explicit Operand(Context** cpp));
326 explicit Operand(Handle<Object> handle);
327 INLINE(explicit Operand(Smi* value));
328
329 // Register.
330 INLINE(explicit Operand(Register rm));
331
332 // Return true if this is a register operand.
333 INLINE(bool is_reg() const);
334
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000335 inline int32_t immediate() const {
336 DCHECK(!is_reg());
337 return imm32_;
338 }
339
Andrei Popescu31002712010-02-23 13:46:05 +0000340 Register rm() const { return rm_; }
341
342 private:
343 Register rm_;
Ben Murdoch257744e2011-11-30 15:57:28 +0000344 int32_t imm32_; // Valid if rm_ == no_reg.
Andrei Popescu31002712010-02-23 13:46:05 +0000345 RelocInfo::Mode rmode_;
346
347 friend class Assembler;
348 friend class MacroAssembler;
349};
350
351
352// On MIPS we have only one adressing mode with base_reg + offset.
353// Class MemOperand represents a memory operand in load and store instructions.
354class MemOperand : public Operand {
355 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000356 // Immediate value attached to offset.
357 enum OffsetAddend {
358 offset_minus_one = -1,
359 offset_zero = 0
360 };
361
Steve Block44f0eee2011-05-26 01:26:41 +0100362 explicit MemOperand(Register rn, int32_t offset = 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000363 explicit MemOperand(Register rn, int32_t unit, int32_t multiplier,
364 OffsetAddend offset_addend = offset_zero);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000365 int32_t offset() const { return offset_; }
Andrei Popescu31002712010-02-23 13:46:05 +0000366
Ben Murdoch589d6972011-11-30 16:04:58 +0000367 bool OffsetIsInt16Encodable() const {
368 return is_int16(offset_);
369 }
370
Andrei Popescu31002712010-02-23 13:46:05 +0000371 private:
Steve Block44f0eee2011-05-26 01:26:41 +0100372 int32_t offset_;
Andrei Popescu31002712010-02-23 13:46:05 +0000373
374 friend class Assembler;
375};
376
377
Steve Block44f0eee2011-05-26 01:26:41 +0100378class Assembler : public AssemblerBase {
Andrei Popescu31002712010-02-23 13:46:05 +0000379 public:
380 // Create an assembler. Instructions and relocation information are emitted
381 // into a buffer, with the instructions starting from the beginning and the
382 // relocation information starting from the end of the buffer. See CodeDesc
383 // for a detailed comment on the layout (globals.h).
384 //
385 // If the provided buffer is NULL, the assembler allocates and grows its own
386 // buffer, and buffer_size determines the initial buffer size. The buffer is
387 // owned by the assembler and deallocated upon destruction of the assembler.
388 //
389 // If the provided buffer is not NULL, the assembler uses the provided buffer
390 // for code generation and assumes its size to be buffer_size. If the buffer
391 // is too small, a fatal error occurs. No deallocation of the buffer is done
392 // upon destruction of the assembler.
Ben Murdoch257744e2011-11-30 15:57:28 +0000393 Assembler(Isolate* isolate, void* buffer, int buffer_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000394 virtual ~Assembler() { }
Steve Block44f0eee2011-05-26 01:26:41 +0100395
Andrei Popescu31002712010-02-23 13:46:05 +0000396 // GetCode emits any pending (non-emitted) code and fills the descriptor
397 // desc. GetCode() is idempotent; it returns the same result if no other
398 // Assembler functions are invoked in between GetCode() calls.
399 void GetCode(CodeDesc* desc);
400
401 // Label operations & relative jumps (PPUM Appendix D).
402 //
403 // Takes a branch opcode (cc) and a label (L) and generates
404 // either a backward branch or a forward branch and links it
405 // to the label fixup chain. Usage:
406 //
407 // Label L; // unbound label
408 // j(cc, &L); // forward branch to unbound label
409 // bind(&L); // bind label to the current pc
410 // j(cc, &L); // backward branch to bound label
411 // bind(&L); // illegal: a label may be bound only once
412 //
413 // Note: The same Label can be used for forward and backward branches
414 // but it may be bound only once.
Ben Murdoch257744e2011-11-30 15:57:28 +0000415 void bind(Label* L); // Binds an unbound label L to current code position.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000416
417 enum OffsetSize : int { kOffset26 = 26, kOffset21 = 21, kOffset16 = 16 };
418
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000419 // Determines if Label is bound and near enough so that branch instruction
420 // can be used to reach it, instead of jump instruction.
421 bool is_near(Label* L);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000422 bool is_near(Label* L, OffsetSize bits);
423 bool is_near_branch(Label* L);
424 inline bool is_near_pre_r6(Label* L) {
425 DCHECK(!IsMipsArchVariant(kMips32r6));
426 return pc_offset() - L->pos() < kMaxBranchOffset - 4 * kInstrSize;
427 }
428 inline bool is_near_r6(Label* L) {
429 DCHECK(IsMipsArchVariant(kMips32r6));
430 return pc_offset() - L->pos() < kMaxCompactBranchOffset - 4 * kInstrSize;
431 }
432
433 int BranchOffset(Instr instr);
Andrei Popescu31002712010-02-23 13:46:05 +0000434
Ben Murdoch257744e2011-11-30 15:57:28 +0000435 // Returns the branch offset to the given label from the current code
436 // position. Links the label to the current position if it is still unbound.
Andrei Popescu31002712010-02-23 13:46:05 +0000437 // Manages the jump elimination optimization if the second parameter is true.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000438 int32_t branch_offset_helper(Label* L, OffsetSize bits);
439 inline int32_t branch_offset(Label* L) {
440 return branch_offset_helper(L, OffsetSize::kOffset16);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000441 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000442 inline int32_t branch_offset21(Label* L) {
443 return branch_offset_helper(L, OffsetSize::kOffset21);
444 }
445 inline int32_t branch_offset26(Label* L) {
446 return branch_offset_helper(L, OffsetSize::kOffset26);
447 }
448 inline int32_t shifted_branch_offset(Label* L) {
449 return branch_offset(L) >> 2;
450 }
451 inline int32_t shifted_branch_offset21(Label* L) {
452 return branch_offset21(L) >> 2;
453 }
454 inline int32_t shifted_branch_offset26(Label* L) {
455 return branch_offset26(L) >> 2;
Andrei Popescu31002712010-02-23 13:46:05 +0000456 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000457 uint32_t jump_address(Label* L);
Andrei Popescu31002712010-02-23 13:46:05 +0000458
459 // Puts a labels target address at the given position.
460 // The high 8 bits are set to zero.
461 void label_at_put(Label* L, int at_offset);
462
Andrei Popescu31002712010-02-23 13:46:05 +0000463 // Read/Modify the code target address in the branch/call instruction at pc.
464 static Address target_address_at(Address pc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000465 static void set_target_address_at(
466 Isolate* isolate, Address pc, Address target,
467 ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000468 // On MIPS there is no Constant Pool so we skip that parameter.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000469 INLINE(static Address target_address_at(Address pc, Address constant_pool)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000470 return target_address_at(pc);
471 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000472 INLINE(static void set_target_address_at(
473 Isolate* isolate, Address pc, Address constant_pool, Address target,
474 ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED)) {
475 set_target_address_at(isolate, pc, target, icache_flush_mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000476 }
477 INLINE(static Address target_address_at(Address pc, Code* code)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000478 Address constant_pool = code ? code->constant_pool() : NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000479 return target_address_at(pc, constant_pool);
480 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000481 INLINE(static void set_target_address_at(
482 Isolate* isolate, Address pc, Code* code, Address target,
483 ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED)) {
484 Address constant_pool = code ? code->constant_pool() : NULL;
485 set_target_address_at(isolate, pc, constant_pool, target,
486 icache_flush_mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000487 }
488
489 // Return the code target address at a call site from the return address
490 // of that call in the instruction stream.
491 inline static Address target_address_from_return_address(Address pc);
492
Ben Murdochdb1b4382012-04-26 19:03:50 +0100493 static void QuietNaN(HeapObject* nan);
494
Andrei Popescu31002712010-02-23 13:46:05 +0000495 // This sets the branch destination (which gets loaded at the call address).
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100496 // This is for calls and branches within generated code. The serializer
497 // has already deserialized the lui/ori instructions etc.
498 inline static void deserialization_set_special_target_at(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000499 Isolate* isolate, Address instruction_payload, Code* code,
500 Address target) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100501 set_target_address_at(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000502 isolate,
503 instruction_payload - kInstructionsFor32BitConstant * kInstrSize, code,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100504 target);
Andrei Popescu31002712010-02-23 13:46:05 +0000505 }
506
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000507 // This sets the internal reference at the pc.
508 inline static void deserialization_set_target_internal_reference_at(
509 Isolate* isolate, Address pc, Address target,
510 RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE);
511
Steve Block44f0eee2011-05-26 01:26:41 +0100512 // Size of an instruction.
513 static const int kInstrSize = sizeof(Instr);
514
515 // Difference between address of current opcode and target address offset.
516 static const int kBranchPCOffset = 4;
517
518 // Here we are patching the address in the LUI/ORI instruction pair.
519 // These values are used in the serialization process and must be zero for
520 // MIPS platform, as Code, Embedded Object or External-reference pointers
521 // are split across two consecutive instructions and don't exist separately
522 // in the code, so the serializer should not step forwards in memory after
523 // a target is resolved and written.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100524 static const int kSpecialTargetSize = 0;
Steve Block44f0eee2011-05-26 01:26:41 +0100525
Ben Murdoch097c5b22016-05-18 11:27:45 +0100526 // Number of consecutive instructions used to store 32bit constant. This
527 // constant is used in RelocInfo::target_address_address() function to tell
528 // serializer address of the instruction that follows LUI/ORI instruction
529 // pair.
530 static const int kInstructionsFor32BitConstant = 2;
Andrei Popescu31002712010-02-23 13:46:05 +0000531
532 // Distance between the instruction referring to the address of the call
533 // target and the return address.
Ben Murdochda12d292016-06-02 14:46:10 +0100534#ifdef _MIPS_ARCH_MIPS32R6
535 static const int kCallTargetAddressOffset = 3 * kInstrSize;
536#else
Andrei Popescu31002712010-02-23 13:46:05 +0000537 static const int kCallTargetAddressOffset = 4 * kInstrSize;
Ben Murdochda12d292016-06-02 14:46:10 +0100538#endif
Andrei Popescu31002712010-02-23 13:46:05 +0000539
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100540 // Distance between start of patched debug break slot and the emitted address
541 // to jump to.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000542 static const int kPatchDebugBreakSlotAddressOffset = 4 * kInstrSize;
Steve Block44f0eee2011-05-26 01:26:41 +0100543
544 // Difference between address of current opcode and value read from pc
545 // register.
546 static const int kPcLoadDelta = 4;
547
Ben Murdochda12d292016-06-02 14:46:10 +0100548#ifdef _MIPS_ARCH_MIPS32R6
549 static const int kDebugBreakSlotInstructions = 3;
550#else
Steve Block44f0eee2011-05-26 01:26:41 +0100551 static const int kDebugBreakSlotInstructions = 4;
Ben Murdochda12d292016-06-02 14:46:10 +0100552#endif
Steve Block44f0eee2011-05-26 01:26:41 +0100553 static const int kDebugBreakSlotLength =
554 kDebugBreakSlotInstructions * kInstrSize;
555
Andrei Popescu31002712010-02-23 13:46:05 +0000556
557 // ---------------------------------------------------------------------------
558 // Code generation.
559
Steve Block44f0eee2011-05-26 01:26:41 +0100560 // Insert the smallest number of nop instructions
561 // possible to align the pc offset to a multiple
562 // of m. m must be a power of 2 (>= 4).
563 void Align(int m);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000564 // Insert the smallest number of zero bytes possible to align the pc offset
565 // to a mulitple of m. m must be a power of 2 (>= 2).
566 void DataAlign(int m);
Steve Block44f0eee2011-05-26 01:26:41 +0100567 // Aligns code to something that's optimal for a jump target for the platform.
568 void CodeTargetAlign();
569
570 // Different nop operations are used by the code generator to detect certain
571 // states of the generated code.
572 enum NopMarkerTypes {
573 NON_MARKING_NOP = 0,
574 DEBUG_BREAK_NOP,
575 // IC markers.
576 PROPERTY_ACCESS_INLINED,
577 PROPERTY_ACCESS_INLINED_CONTEXT,
578 PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE,
579 // Helper values.
580 LAST_CODE_MARKER,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000581 FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED,
582 // Code aging
583 CODE_AGE_MARKER_NOP = 6,
584 CODE_AGE_SEQUENCE_NOP
Steve Block44f0eee2011-05-26 01:26:41 +0100585 };
586
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000587 // Type == 0 is the default non-marking nop. For mips this is a
588 // sll(zero_reg, zero_reg, 0). We use rt_reg == at for non-zero
589 // marking, to avoid conflict with ssnop and ehb instructions.
Steve Block44f0eee2011-05-26 01:26:41 +0100590 void nop(unsigned int type = 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000591 DCHECK(type < 32);
592 Register nop_rt_reg = (type == 0) ? zero_reg : at;
593 sll(zero_reg, nop_rt_reg, type, true);
Steve Block44f0eee2011-05-26 01:26:41 +0100594 }
Andrei Popescu31002712010-02-23 13:46:05 +0000595
596
Ben Murdoch257744e2011-11-30 15:57:28 +0000597 // --------Branch-and-jump-instructions----------
Andrei Popescu31002712010-02-23 13:46:05 +0000598 // We don't use likely variant of instructions.
599 void b(int16_t offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000600 inline void b(Label* L) { b(shifted_branch_offset(L)); }
Andrei Popescu31002712010-02-23 13:46:05 +0000601 void bal(int16_t offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000602 inline void bal(Label* L) { bal(shifted_branch_offset(L)); }
603 void bc(int32_t offset);
604 inline void bc(Label* L) { bc(shifted_branch_offset26(L)); }
605 void balc(int32_t offset);
606 inline void balc(Label* L) { balc(shifted_branch_offset26(L)); }
Andrei Popescu31002712010-02-23 13:46:05 +0000607
608 void beq(Register rs, Register rt, int16_t offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000609 inline void beq(Register rs, Register rt, Label* L) {
610 beq(rs, rt, shifted_branch_offset(L));
Andrei Popescu31002712010-02-23 13:46:05 +0000611 }
612 void bgez(Register rs, int16_t offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000613 void bgezc(Register rt, int16_t offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000614 inline void bgezc(Register rt, Label* L) {
615 bgezc(rt, shifted_branch_offset(L));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000616 }
617 void bgeuc(Register rs, Register rt, int16_t offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000618 inline void bgeuc(Register rs, Register rt, Label* L) {
619 bgeuc(rs, rt, shifted_branch_offset(L));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000620 }
621 void bgec(Register rs, Register rt, int16_t offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000622 inline void bgec(Register rs, Register rt, Label* L) {
623 bgec(rs, rt, shifted_branch_offset(L));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000624 }
Andrei Popescu31002712010-02-23 13:46:05 +0000625 void bgezal(Register rs, int16_t offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000626 void bgezalc(Register rt, int16_t offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000627 inline void bgezalc(Register rt, Label* L) {
628 bgezalc(rt, shifted_branch_offset(L));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000629 }
630 void bgezall(Register rs, int16_t offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000631 inline void bgezall(Register rs, Label* L) {
632 bgezall(rs, branch_offset(L) >> 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000633 }
Andrei Popescu31002712010-02-23 13:46:05 +0000634 void bgtz(Register rs, int16_t offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000635 void bgtzc(Register rt, int16_t offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000636 inline void bgtzc(Register rt, Label* L) {
637 bgtzc(rt, shifted_branch_offset(L));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000638 }
Andrei Popescu31002712010-02-23 13:46:05 +0000639 void blez(Register rs, int16_t offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000640 void blezc(Register rt, int16_t offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000641 inline void blezc(Register rt, Label* L) {
642 blezc(rt, shifted_branch_offset(L));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000643 }
Andrei Popescu31002712010-02-23 13:46:05 +0000644 void bltz(Register rs, int16_t offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000645 void bltzc(Register rt, int16_t offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000646 inline void bltzc(Register rt, Label* L) {
647 bltzc(rt, shifted_branch_offset(L));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000648 }
649 void bltuc(Register rs, Register rt, int16_t offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000650 inline void bltuc(Register rs, Register rt, Label* L) {
651 bltuc(rs, rt, shifted_branch_offset(L));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000652 }
653 void bltc(Register rs, Register rt, int16_t offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000654 inline void bltc(Register rs, Register rt, Label* L) {
655 bltc(rs, rt, shifted_branch_offset(L));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000656 }
Andrei Popescu31002712010-02-23 13:46:05 +0000657 void bltzal(Register rs, int16_t offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000658 void blezalc(Register rt, int16_t offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000659 inline void blezalc(Register rt, Label* L) {
660 blezalc(rt, shifted_branch_offset(L));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000661 }
662 void bltzalc(Register rt, int16_t offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000663 inline void bltzalc(Register rt, Label* L) {
664 bltzalc(rt, shifted_branch_offset(L));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000665 }
666 void bgtzalc(Register rt, int16_t offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000667 inline void bgtzalc(Register rt, Label* L) {
668 bgtzalc(rt, shifted_branch_offset(L));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000669 }
670 void beqzalc(Register rt, int16_t offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000671 inline void beqzalc(Register rt, Label* L) {
672 beqzalc(rt, shifted_branch_offset(L));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000673 }
674 void beqc(Register rs, Register rt, int16_t offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000675 inline void beqc(Register rs, Register rt, Label* L) {
676 beqc(rs, rt, shifted_branch_offset(L));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000677 }
678 void beqzc(Register rs, int32_t offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000679 inline void beqzc(Register rs, Label* L) {
680 beqzc(rs, shifted_branch_offset21(L));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000681 }
682 void bnezalc(Register rt, int16_t offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000683 inline void bnezalc(Register rt, Label* L) {
684 bnezalc(rt, shifted_branch_offset(L));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000685 }
686 void bnec(Register rs, Register rt, int16_t offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000687 inline void bnec(Register rs, Register rt, Label* L) {
688 bnec(rs, rt, shifted_branch_offset(L));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000689 }
690 void bnezc(Register rt, int32_t offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000691 inline void bnezc(Register rt, Label* L) {
692 bnezc(rt, shifted_branch_offset21(L));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000693 }
Andrei Popescu31002712010-02-23 13:46:05 +0000694 void bne(Register rs, Register rt, int16_t offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000695 inline void bne(Register rs, Register rt, Label* L) {
696 bne(rs, rt, shifted_branch_offset(L));
Andrei Popescu31002712010-02-23 13:46:05 +0000697 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000698 void bovc(Register rs, Register rt, int16_t offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000699 inline void bovc(Register rs, Register rt, Label* L) {
700 bovc(rs, rt, shifted_branch_offset(L));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000701 }
702 void bnvc(Register rs, Register rt, int16_t offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000703 inline void bnvc(Register rs, Register rt, Label* L) {
704 bnvc(rs, rt, shifted_branch_offset(L));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000705 }
Andrei Popescu31002712010-02-23 13:46:05 +0000706
707 // Never use the int16_t b(l)cond version with a branch offset
Ben Murdoch257744e2011-11-30 15:57:28 +0000708 // instead of using the Label* version.
Andrei Popescu31002712010-02-23 13:46:05 +0000709
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100710 // Jump targets must be in the current 256 MB-aligned region. i.e. 28 bits.
Andrei Popescu31002712010-02-23 13:46:05 +0000711 void j(int32_t target);
712 void jal(int32_t target);
713 void jalr(Register rs, Register rd = ra);
714 void jr(Register target);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000715 void jic(Register rt, int16_t offset);
716 void jialc(Register rt, int16_t offset);
Andrei Popescu31002712010-02-23 13:46:05 +0000717
718
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000719 // -------Data-processing-instructions---------
Andrei Popescu31002712010-02-23 13:46:05 +0000720
721 // Arithmetic.
Andrei Popescu31002712010-02-23 13:46:05 +0000722 void addu(Register rd, Register rs, Register rt);
Andrei Popescu31002712010-02-23 13:46:05 +0000723 void subu(Register rd, Register rs, Register rt);
724 void mult(Register rs, Register rt);
725 void multu(Register rs, Register rt);
726 void div(Register rs, Register rt);
727 void divu(Register rs, Register rt);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000728 void div(Register rd, Register rs, Register rt);
729 void divu(Register rd, Register rs, Register rt);
730 void mod(Register rd, Register rs, Register rt);
731 void modu(Register rd, Register rs, Register rt);
Andrei Popescu31002712010-02-23 13:46:05 +0000732 void mul(Register rd, Register rs, Register rt);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000733 void muh(Register rd, Register rs, Register rt);
734 void mulu(Register rd, Register rs, Register rt);
735 void muhu(Register rd, Register rs, Register rt);
Andrei Popescu31002712010-02-23 13:46:05 +0000736
Andrei Popescu31002712010-02-23 13:46:05 +0000737 void addiu(Register rd, Register rs, int32_t j);
738
739 // Logical.
740 void and_(Register rd, Register rs, Register rt);
741 void or_(Register rd, Register rs, Register rt);
742 void xor_(Register rd, Register rs, Register rt);
743 void nor(Register rd, Register rs, Register rt);
744
745 void andi(Register rd, Register rs, int32_t j);
746 void ori(Register rd, Register rs, int32_t j);
747 void xori(Register rd, Register rs, int32_t j);
748 void lui(Register rd, int32_t j);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000749 void aui(Register rs, Register rt, int32_t j);
Andrei Popescu31002712010-02-23 13:46:05 +0000750
751 // Shifts.
Steve Block44f0eee2011-05-26 01:26:41 +0100752 // Please note: sll(zero_reg, zero_reg, x) instructions are reserved as nop
753 // and may cause problems in normal code. coming_from_nop makes sure this
754 // doesn't happen.
755 void sll(Register rd, Register rt, uint16_t sa, bool coming_from_nop = false);
Andrei Popescu31002712010-02-23 13:46:05 +0000756 void sllv(Register rd, Register rt, Register rs);
757 void srl(Register rd, Register rt, uint16_t sa);
758 void srlv(Register rd, Register rt, Register rs);
759 void sra(Register rt, Register rd, uint16_t sa);
760 void srav(Register rt, Register rd, Register rs);
Steve Block44f0eee2011-05-26 01:26:41 +0100761 void rotr(Register rd, Register rt, uint16_t sa);
762 void rotrv(Register rd, Register rt, Register rs);
Andrei Popescu31002712010-02-23 13:46:05 +0000763
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000764 // ------------Memory-instructions-------------
Andrei Popescu31002712010-02-23 13:46:05 +0000765
766 void lb(Register rd, const MemOperand& rs);
767 void lbu(Register rd, const MemOperand& rs);
Steve Block44f0eee2011-05-26 01:26:41 +0100768 void lh(Register rd, const MemOperand& rs);
769 void lhu(Register rd, const MemOperand& rs);
Andrei Popescu31002712010-02-23 13:46:05 +0000770 void lw(Register rd, const MemOperand& rs);
Steve Block44f0eee2011-05-26 01:26:41 +0100771 void lwl(Register rd, const MemOperand& rs);
772 void lwr(Register rd, const MemOperand& rs);
Andrei Popescu31002712010-02-23 13:46:05 +0000773 void sb(Register rd, const MemOperand& rs);
Steve Block44f0eee2011-05-26 01:26:41 +0100774 void sh(Register rd, const MemOperand& rs);
Andrei Popescu31002712010-02-23 13:46:05 +0000775 void sw(Register rd, const MemOperand& rs);
Steve Block44f0eee2011-05-26 01:26:41 +0100776 void swl(Register rd, const MemOperand& rs);
777 void swr(Register rd, const MemOperand& rs);
Andrei Popescu31002712010-02-23 13:46:05 +0000778
779
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000780 // ---------PC-Relative-instructions-----------
781
782 void addiupc(Register rs, int32_t imm19);
783 void lwpc(Register rs, int32_t offset19);
784 void auipc(Register rs, int16_t imm16);
785 void aluipc(Register rs, int16_t imm16);
786
787
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000788 // ----------------Prefetch--------------------
789
790 void pref(int32_t hint, const MemOperand& rs);
791
792
793 // -------------Misc-instructions--------------
Andrei Popescu31002712010-02-23 13:46:05 +0000794
795 // Break / Trap instructions.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000796 void break_(uint32_t code, bool break_as_stop = false);
797 void stop(const char* msg, uint32_t code = kMaxStopCode);
Andrei Popescu31002712010-02-23 13:46:05 +0000798 void tge(Register rs, Register rt, uint16_t code);
799 void tgeu(Register rs, Register rt, uint16_t code);
800 void tlt(Register rs, Register rt, uint16_t code);
801 void tltu(Register rs, Register rt, uint16_t code);
802 void teq(Register rs, Register rt, uint16_t code);
803 void tne(Register rs, Register rt, uint16_t code);
804
Ben Murdochc5610432016-08-08 18:44:38 +0100805 // Memory barrier instruction.
806 void sync();
807
Andrei Popescu31002712010-02-23 13:46:05 +0000808 // Move from HI/LO register.
809 void mfhi(Register rd);
810 void mflo(Register rd);
811
812 // Set on less than.
813 void slt(Register rd, Register rs, Register rt);
814 void sltu(Register rd, Register rs, Register rt);
815 void slti(Register rd, Register rs, int32_t j);
816 void sltiu(Register rd, Register rs, int32_t j);
817
Steve Block44f0eee2011-05-26 01:26:41 +0100818 // Conditional move.
819 void movz(Register rd, Register rs, Register rt);
820 void movn(Register rd, Register rs, Register rt);
821 void movt(Register rd, Register rs, uint16_t cc = 0);
822 void movf(Register rd, Register rs, uint16_t cc = 0);
823
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000824 void sel(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
825 void sel_s(FPURegister fd, FPURegister fs, FPURegister ft);
826 void sel_d(FPURegister fd, FPURegister fs, FPURegister ft);
827 void seleqz(Register rd, Register rs, Register rt);
828 void seleqz(SecondaryField fmt, FPURegister fd, FPURegister fs,
829 FPURegister ft);
830 void selnez(Register rd, Register rs, Register rt);
831 void selnez(SecondaryField fmt, FPURegister fd, FPURegister fs,
832 FPURegister ft);
833 void seleqz_d(FPURegister fd, FPURegister fs, FPURegister ft);
834 void seleqz_s(FPURegister fd, FPURegister fs, FPURegister ft);
835 void selnez_d(FPURegister fd, FPURegister fs, FPURegister ft);
836 void selnez_s(FPURegister fd, FPURegister fs, FPURegister ft);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000837
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000838 void movz_s(FPURegister fd, FPURegister fs, Register rt);
839 void movz_d(FPURegister fd, FPURegister fs, Register rt);
840 void movt_s(FPURegister fd, FPURegister fs, uint16_t cc = 0);
841 void movt_d(FPURegister fd, FPURegister fs, uint16_t cc = 0);
842 void movf_s(FPURegister fd, FPURegister fs, uint16_t cc = 0);
843 void movf_d(FPURegister fd, FPURegister fs, uint16_t cc = 0);
844 void movn_s(FPURegister fd, FPURegister fs, Register rt);
845 void movn_d(FPURegister fd, FPURegister fs, Register rt);
Steve Block44f0eee2011-05-26 01:26:41 +0100846 // Bit twiddling.
847 void clz(Register rd, Register rs);
848 void ins_(Register rt, Register rs, uint16_t pos, uint16_t size);
849 void ext_(Register rt, Register rs, uint16_t pos, uint16_t size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000850 void bitswap(Register rd, Register rt);
851 void align(Register rd, Register rs, Register rt, uint8_t bp);
Andrei Popescu31002712010-02-23 13:46:05 +0000852
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000853 // --------Coprocessor-instructions----------------
Andrei Popescu31002712010-02-23 13:46:05 +0000854
855 // Load, store, and move.
856 void lwc1(FPURegister fd, const MemOperand& src);
857 void ldc1(FPURegister fd, const MemOperand& src);
858
859 void swc1(FPURegister fs, const MemOperand& dst);
860 void sdc1(FPURegister fs, const MemOperand& dst);
861
Steve Block44f0eee2011-05-26 01:26:41 +0100862 void mtc1(Register rt, FPURegister fs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000863 void mthc1(Register rt, FPURegister fs);
864
Steve Block44f0eee2011-05-26 01:26:41 +0100865 void mfc1(Register rt, FPURegister fs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000866 void mfhc1(Register rt, FPURegister fs);
Steve Block44f0eee2011-05-26 01:26:41 +0100867
868 void ctc1(Register rt, FPUControlRegister fs);
869 void cfc1(Register rt, FPUControlRegister fs);
870
871 // Arithmetic.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000872 void add_s(FPURegister fd, FPURegister fs, FPURegister ft);
Steve Block44f0eee2011-05-26 01:26:41 +0100873 void add_d(FPURegister fd, FPURegister fs, FPURegister ft);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000874 void sub_s(FPURegister fd, FPURegister fs, FPURegister ft);
Steve Block44f0eee2011-05-26 01:26:41 +0100875 void sub_d(FPURegister fd, FPURegister fs, FPURegister ft);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000876 void mul_s(FPURegister fd, FPURegister fs, FPURegister ft);
Steve Block44f0eee2011-05-26 01:26:41 +0100877 void mul_d(FPURegister fd, FPURegister fs, FPURegister ft);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000878 void madd_d(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000879 void div_s(FPURegister fd, FPURegister fs, FPURegister ft);
Steve Block44f0eee2011-05-26 01:26:41 +0100880 void div_d(FPURegister fd, FPURegister fs, FPURegister ft);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000881 void abs_s(FPURegister fd, FPURegister fs);
Steve Block44f0eee2011-05-26 01:26:41 +0100882 void abs_d(FPURegister fd, FPURegister fs);
883 void mov_d(FPURegister fd, FPURegister fs);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000884 void mov_s(FPURegister fd, FPURegister fs);
885 void neg_s(FPURegister fd, FPURegister fs);
Steve Block44f0eee2011-05-26 01:26:41 +0100886 void neg_d(FPURegister fd, FPURegister fs);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000887 void sqrt_s(FPURegister fd, FPURegister fs);
Steve Block44f0eee2011-05-26 01:26:41 +0100888 void sqrt_d(FPURegister fd, FPURegister fs);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000889 void rsqrt_s(FPURegister fd, FPURegister fs);
890 void rsqrt_d(FPURegister fd, FPURegister fs);
891 void recip_d(FPURegister fd, FPURegister fs);
892 void recip_s(FPURegister fd, FPURegister fs);
Andrei Popescu31002712010-02-23 13:46:05 +0000893
894 // Conversion.
895 void cvt_w_s(FPURegister fd, FPURegister fs);
896 void cvt_w_d(FPURegister fd, FPURegister fs);
Steve Block44f0eee2011-05-26 01:26:41 +0100897 void trunc_w_s(FPURegister fd, FPURegister fs);
898 void trunc_w_d(FPURegister fd, FPURegister fs);
899 void round_w_s(FPURegister fd, FPURegister fs);
900 void round_w_d(FPURegister fd, FPURegister fs);
901 void floor_w_s(FPURegister fd, FPURegister fs);
902 void floor_w_d(FPURegister fd, FPURegister fs);
903 void ceil_w_s(FPURegister fd, FPURegister fs);
904 void ceil_w_d(FPURegister fd, FPURegister fs);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000905 void rint_s(FPURegister fd, FPURegister fs);
906 void rint_d(FPURegister fd, FPURegister fs);
907 void rint(SecondaryField fmt, FPURegister fd, FPURegister fs);
Andrei Popescu31002712010-02-23 13:46:05 +0000908
909 void cvt_l_s(FPURegister fd, FPURegister fs);
910 void cvt_l_d(FPURegister fd, FPURegister fs);
Steve Block44f0eee2011-05-26 01:26:41 +0100911 void trunc_l_s(FPURegister fd, FPURegister fs);
912 void trunc_l_d(FPURegister fd, FPURegister fs);
913 void round_l_s(FPURegister fd, FPURegister fs);
914 void round_l_d(FPURegister fd, FPURegister fs);
915 void floor_l_s(FPURegister fd, FPURegister fs);
916 void floor_l_d(FPURegister fd, FPURegister fs);
917 void ceil_l_s(FPURegister fd, FPURegister fs);
918 void ceil_l_d(FPURegister fd, FPURegister fs);
Andrei Popescu31002712010-02-23 13:46:05 +0000919
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000920 void class_s(FPURegister fd, FPURegister fs);
921 void class_d(FPURegister fd, FPURegister fs);
922
923 void min(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
924 void mina(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
925 void max(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
926 void maxa(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
927 void min_s(FPURegister fd, FPURegister fs, FPURegister ft);
928 void min_d(FPURegister fd, FPURegister fs, FPURegister ft);
929 void max_s(FPURegister fd, FPURegister fs, FPURegister ft);
930 void max_d(FPURegister fd, FPURegister fs, FPURegister ft);
931 void mina_s(FPURegister fd, FPURegister fs, FPURegister ft);
932 void mina_d(FPURegister fd, FPURegister fs, FPURegister ft);
933 void maxa_s(FPURegister fd, FPURegister fs, FPURegister ft);
934 void maxa_d(FPURegister fd, FPURegister fs, FPURegister ft);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000935
Andrei Popescu31002712010-02-23 13:46:05 +0000936 void cvt_s_w(FPURegister fd, FPURegister fs);
937 void cvt_s_l(FPURegister fd, FPURegister fs);
938 void cvt_s_d(FPURegister fd, FPURegister fs);
939
940 void cvt_d_w(FPURegister fd, FPURegister fs);
941 void cvt_d_l(FPURegister fd, FPURegister fs);
942 void cvt_d_s(FPURegister fd, FPURegister fs);
943
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000944 // Conditions and branches for MIPSr6.
945 void cmp(FPUCondition cond, SecondaryField fmt,
946 FPURegister fd, FPURegister ft, FPURegister fs);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000947 void cmp_s(FPUCondition cond, FPURegister fd, FPURegister fs, FPURegister ft);
948 void cmp_d(FPUCondition cond, FPURegister fd, FPURegister fs, FPURegister ft);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000949
950 void bc1eqz(int16_t offset, FPURegister ft);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000951 inline void bc1eqz(Label* L, FPURegister ft) {
952 bc1eqz(shifted_branch_offset(L), ft);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000953 }
954 void bc1nez(int16_t offset, FPURegister ft);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000955 inline void bc1nez(Label* L, FPURegister ft) {
956 bc1nez(shifted_branch_offset(L), ft);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000957 }
958
959 // Conditions and branches for non MIPSr6.
Andrei Popescu31002712010-02-23 13:46:05 +0000960 void c(FPUCondition cond, SecondaryField fmt,
961 FPURegister ft, FPURegister fs, uint16_t cc = 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000962 void c_s(FPUCondition cond, FPURegister ft, FPURegister fs, uint16_t cc = 0);
963 void c_d(FPUCondition cond, FPURegister ft, FPURegister fs, uint16_t cc = 0);
Andrei Popescu31002712010-02-23 13:46:05 +0000964
965 void bc1f(int16_t offset, uint16_t cc = 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000966 inline void bc1f(Label* L, uint16_t cc = 0) {
967 bc1f(shifted_branch_offset(L), cc);
968 }
Andrei Popescu31002712010-02-23 13:46:05 +0000969 void bc1t(int16_t offset, uint16_t cc = 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000970 inline void bc1t(Label* L, uint16_t cc = 0) {
971 bc1t(shifted_branch_offset(L), cc);
972 }
Steve Block44f0eee2011-05-26 01:26:41 +0100973 void fcmp(FPURegister src1, const double src2, FPUCondition cond);
Andrei Popescu31002712010-02-23 13:46:05 +0000974
975 // Check the code size generated from label to here.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000976 int SizeOfCodeGeneratedSince(Label* label) {
977 return pc_offset() - label->pos();
978 }
979
980 // Check the number of instructions generated from label to here.
981 int InstructionsGeneratedSince(Label* label) {
982 return SizeOfCodeGeneratedSince(label) / kInstrSize;
Andrei Popescu31002712010-02-23 13:46:05 +0000983 }
984
Steve Block44f0eee2011-05-26 01:26:41 +0100985 // Class for scoping postponing the trampoline pool generation.
986 class BlockTrampolinePoolScope {
987 public:
988 explicit BlockTrampolinePoolScope(Assembler* assem) : assem_(assem) {
989 assem_->StartBlockTrampolinePool();
990 }
991 ~BlockTrampolinePoolScope() {
992 assem_->EndBlockTrampolinePool();
993 }
994
995 private:
996 Assembler* assem_;
997
998 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockTrampolinePoolScope);
999 };
1000
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001001 // Class for postponing the assembly buffer growth. Typically used for
1002 // sequences of instructions that must be emitted as a unit, before
1003 // buffer growth (and relocation) can occur.
1004 // This blocking scope is not nestable.
1005 class BlockGrowBufferScope {
1006 public:
1007 explicit BlockGrowBufferScope(Assembler* assem) : assem_(assem) {
1008 assem_->StartBlockGrowBuffer();
1009 }
1010 ~BlockGrowBufferScope() {
1011 assem_->EndBlockGrowBuffer();
1012 }
1013
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001014 private:
1015 Assembler* assem_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001016
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001017 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockGrowBufferScope);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001018 };
1019
Andrei Popescu31002712010-02-23 13:46:05 +00001020 // Debugging.
1021
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001022 // Mark generator continuation.
1023 void RecordGeneratorContinuation();
Andrei Popescu31002712010-02-23 13:46:05 +00001024
Steve Block44f0eee2011-05-26 01:26:41 +01001025 // Mark address of a debug break slot.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001026 void RecordDebugBreakSlot(RelocInfo::Mode mode);
Steve Block44f0eee2011-05-26 01:26:41 +01001027
Ben Murdoch257744e2011-11-30 15:57:28 +00001028 // Record the AST id of the CallIC being compiled, so that it can be placed
1029 // in the relocation information.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001030 void SetRecordedAstId(TypeFeedbackId ast_id) {
1031 DCHECK(recorded_ast_id_.IsNone());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001032 recorded_ast_id_ = ast_id;
1033 }
1034
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001035 TypeFeedbackId RecordedAstId() {
1036 DCHECK(!recorded_ast_id_.IsNone());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001037 return recorded_ast_id_;
1038 }
1039
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001040 void ClearRecordedAstId() { recorded_ast_id_ = TypeFeedbackId::None(); }
Ben Murdoch257744e2011-11-30 15:57:28 +00001041
Andrei Popescu31002712010-02-23 13:46:05 +00001042 // Record a comment relocation entry that can be used by a disassembler.
Steve Block44f0eee2011-05-26 01:26:41 +01001043 // Use --code-comments to enable.
Andrei Popescu31002712010-02-23 13:46:05 +00001044 void RecordComment(const char* msg);
1045
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001046 // Record a deoptimization reason that can be used by a log or cpu profiler.
1047 // Use --trace-deopt to enable.
Ben Murdochc5610432016-08-08 18:44:38 +01001048 void RecordDeoptReason(const int reason, int raw_position, int id);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001049
1050 static int RelocateInternalReference(RelocInfo::Mode rmode, byte* pc,
1051 intptr_t pc_delta);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001052
Steve Block44f0eee2011-05-26 01:26:41 +01001053 // Writes a single byte or word of data in the code stream. Used for
1054 // inline tables, e.g., jump-tables.
1055 void db(uint8_t data);
1056 void dd(uint32_t data);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001057 void dq(uint64_t data);
1058 void dp(uintptr_t data) { dd(data); }
1059 void dd(Label* label);
Steve Block44f0eee2011-05-26 01:26:41 +01001060
Ben Murdochda12d292016-06-02 14:46:10 +01001061 AssemblerPositionsRecorder* positions_recorder() {
1062 return &positions_recorder_;
1063 }
Steve Block44f0eee2011-05-26 01:26:41 +01001064
Steve Block44f0eee2011-05-26 01:26:41 +01001065 // Postpone the generation of the trampoline pool for the specified number of
1066 // instructions.
1067 void BlockTrampolinePoolFor(int instructions);
1068
Andrei Popescu31002712010-02-23 13:46:05 +00001069 // Check if there is less than kGap bytes available in the buffer.
1070 // If this is the case, we need to grow the buffer before emitting
1071 // an instruction or relocation information.
1072 inline bool overflow() const { return pc_ >= reloc_info_writer.pos() - kGap; }
1073
1074 // Get the number of bytes available in the buffer.
1075 inline int available_space() const { return reloc_info_writer.pos() - pc_; }
1076
Andrei Popescu31002712010-02-23 13:46:05 +00001077 // Read/patch instructions.
1078 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
Steve Block44f0eee2011-05-26 01:26:41 +01001079 static void instr_at_put(byte* pc, Instr instr) {
Andrei Popescu31002712010-02-23 13:46:05 +00001080 *reinterpret_cast<Instr*>(pc) = instr;
1081 }
1082 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
1083 void instr_at_put(int pos, Instr instr) {
1084 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
1085 }
1086
1087 // Check if an instruction is a branch of some kind.
Steve Block44f0eee2011-05-26 01:26:41 +01001088 static bool IsBranch(Instr instr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001089 static bool IsBc(Instr instr);
1090 static bool IsBzc(Instr instr);
Ben Murdoch257744e2011-11-30 15:57:28 +00001091 static bool IsBeq(Instr instr);
1092 static bool IsBne(Instr instr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001093 static bool IsBeqzc(Instr instr);
1094 static bool IsBnezc(Instr instr);
1095 static bool IsBeqc(Instr instr);
1096 static bool IsBnec(Instr instr);
Ben Murdochda12d292016-06-02 14:46:10 +01001097 static bool IsJicOrJialc(Instr instr);
Steve Block44f0eee2011-05-26 01:26:41 +01001098
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001099 static bool IsJump(Instr instr);
1100 static bool IsJ(Instr instr);
1101 static bool IsLui(Instr instr);
1102 static bool IsOri(Instr instr);
1103
Ben Murdoch589d6972011-11-30 16:04:58 +00001104 static bool IsJal(Instr instr);
1105 static bool IsJr(Instr instr);
1106 static bool IsJalr(Instr instr);
1107
Steve Block44f0eee2011-05-26 01:26:41 +01001108 static bool IsNop(Instr instr, unsigned int type);
1109 static bool IsPop(Instr instr);
1110 static bool IsPush(Instr instr);
1111 static bool IsLwRegFpOffset(Instr instr);
1112 static bool IsSwRegFpOffset(Instr instr);
1113 static bool IsLwRegFpNegOffset(Instr instr);
1114 static bool IsSwRegFpNegOffset(Instr instr);
1115
Ben Murdoch257744e2011-11-30 15:57:28 +00001116 static Register GetRtReg(Instr instr);
1117 static Register GetRsReg(Instr instr);
1118 static Register GetRdReg(Instr instr);
1119
1120 static uint32_t GetRt(Instr instr);
1121 static uint32_t GetRtField(Instr instr);
1122 static uint32_t GetRs(Instr instr);
1123 static uint32_t GetRsField(Instr instr);
1124 static uint32_t GetRd(Instr instr);
1125 static uint32_t GetRdField(Instr instr);
1126 static uint32_t GetSa(Instr instr);
1127 static uint32_t GetSaField(Instr instr);
1128 static uint32_t GetOpcodeField(Instr instr);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001129 static uint32_t GetFunction(Instr instr);
1130 static uint32_t GetFunctionField(Instr instr);
Ben Murdoch257744e2011-11-30 15:57:28 +00001131 static uint32_t GetImmediate16(Instr instr);
1132 static uint32_t GetLabelConst(Instr instr);
Steve Block44f0eee2011-05-26 01:26:41 +01001133
1134 static int32_t GetBranchOffset(Instr instr);
1135 static bool IsLw(Instr instr);
1136 static int16_t GetLwOffset(Instr instr);
Ben Murdochda12d292016-06-02 14:46:10 +01001137 static int16_t GetJicOrJialcOffset(Instr instr);
1138 static int16_t GetLuiOffset(Instr instr);
Steve Block44f0eee2011-05-26 01:26:41 +01001139 static Instr SetLwOffset(Instr instr, int16_t offset);
1140
1141 static bool IsSw(Instr instr);
1142 static Instr SetSwOffset(Instr instr, int16_t offset);
1143 static bool IsAddImmediate(Instr instr);
1144 static Instr SetAddImmediateOffset(Instr instr, int16_t offset);
Ben Murdochda12d292016-06-02 14:46:10 +01001145 static uint32_t CreateTargetAddress(Instr instr_lui, Instr instr_jic);
1146 static void UnpackTargetAddress(uint32_t address, int16_t& lui_offset,
1147 int16_t& jic_offset);
1148 static void UnpackTargetAddressUnsigned(uint32_t address,
1149 uint32_t& lui_offset,
1150 uint32_t& jic_offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001151
Ben Murdoch257744e2011-11-30 15:57:28 +00001152 static bool IsAndImmediate(Instr instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001153 static bool IsEmittedConstant(Instr instr);
Ben Murdoch257744e2011-11-30 15:57:28 +00001154
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001155 void CheckTrampolinePool();
Steve Block44f0eee2011-05-26 01:26:41 +01001156
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001157 void PatchConstantPoolAccessInstruction(int pc_offset, int offset,
1158 ConstantPoolEntry::Access access,
1159 ConstantPoolEntry::Type type) {
1160 // No embedded constant pool support.
1161 UNREACHABLE();
1162 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001163
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001164 bool IsPrevInstrCompactBranch() { return prev_instr_compact_branch_; }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001165
Ben Murdochc5610432016-08-08 18:44:38 +01001166 inline int UnboundLabelsCount() { return unbound_labels_count_; }
1167
Steve Block44f0eee2011-05-26 01:26:41 +01001168 protected:
Ben Murdochda12d292016-06-02 14:46:10 +01001169 // Load Scaled Address instruction.
1170 void lsa(Register rd, Register rt, Register rs, uint8_t sa);
1171
Ben Murdochc5610432016-08-08 18:44:38 +01001172 // Helpers.
1173 void LoadRegPlusOffsetToAt(const MemOperand& src);
1174
Ben Murdoch257744e2011-11-30 15:57:28 +00001175 // Relocation for a type-recording IC has the AST id added to it. This
1176 // member variable is a way to pass the information from the call site to
1177 // the relocation info.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001178 TypeFeedbackId recorded_ast_id_;
Steve Block44f0eee2011-05-26 01:26:41 +01001179
1180 int32_t buffer_space() const { return reloc_info_writer.pos() - pc_; }
Andrei Popescu31002712010-02-23 13:46:05 +00001181
1182 // Decode branch instruction at pos and return branch target pos.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001183 int target_at(int pos, bool is_internal);
Andrei Popescu31002712010-02-23 13:46:05 +00001184
1185 // Patch branch instruction at pos to branch to given branch target pos.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001186 void target_at_put(int pos, int target_pos, bool is_internal);
Andrei Popescu31002712010-02-23 13:46:05 +00001187
1188 // Say if we need to relocate with this mode.
Steve Block44f0eee2011-05-26 01:26:41 +01001189 bool MustUseReg(RelocInfo::Mode rmode);
Andrei Popescu31002712010-02-23 13:46:05 +00001190
1191 // Record reloc info for current pc_.
1192 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
1193
Steve Block44f0eee2011-05-26 01:26:41 +01001194 // Block the emission of the trampoline pool before pc_offset.
1195 void BlockTrampolinePoolBefore(int pc_offset) {
1196 if (no_trampoline_pool_before_ < pc_offset)
1197 no_trampoline_pool_before_ = pc_offset;
1198 }
1199
1200 void StartBlockTrampolinePool() {
1201 trampoline_pool_blocked_nesting_++;
1202 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001203
Steve Block44f0eee2011-05-26 01:26:41 +01001204 void EndBlockTrampolinePool() {
1205 trampoline_pool_blocked_nesting_--;
1206 }
1207
1208 bool is_trampoline_pool_blocked() const {
1209 return trampoline_pool_blocked_nesting_ > 0;
1210 }
1211
Ben Murdoch257744e2011-11-30 15:57:28 +00001212 bool has_exception() const {
1213 return internal_trampoline_exception_;
1214 }
1215
Ben Murdoch589d6972011-11-30 16:04:58 +00001216 void DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi);
1217
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001218 bool is_trampoline_emitted() const {
1219 return trampoline_emitted_;
1220 }
1221
1222 // Temporarily block automatic assembly buffer growth.
1223 void StartBlockGrowBuffer() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001224 DCHECK(!block_buffer_growth_);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001225 block_buffer_growth_ = true;
1226 }
1227
1228 void EndBlockGrowBuffer() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001229 DCHECK(block_buffer_growth_);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001230 block_buffer_growth_ = false;
1231 }
1232
1233 bool is_buffer_growth_blocked() const {
1234 return block_buffer_growth_;
1235 }
1236
Ben Murdoch097c5b22016-05-18 11:27:45 +01001237 void EmitForbiddenSlotInstruction() {
1238 if (IsPrevInstrCompactBranch()) {
1239 nop();
1240 }
1241 }
1242
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001243 inline void CheckTrampolinePoolQuick(int extra_instructions = 0);
1244
Ben Murdochda12d292016-06-02 14:46:10 +01001245 inline void CheckBuffer();
1246
Andrei Popescu31002712010-02-23 13:46:05 +00001247 private:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001248 inline static void set_target_internal_reference_encoded_at(Address pc,
1249 Address target);
1250
Andrei Popescu31002712010-02-23 13:46:05 +00001251 // Buffer size and constant pool distance are checked together at regular
1252 // intervals of kBufferCheckInterval emitted bytes.
1253 static const int kBufferCheckInterval = 1*KB/2;
1254
1255 // Code generation.
1256 // The relocation writer's position is at least kGap bytes below the end of
1257 // the generated instructions. This is so that multi-instruction sequences do
1258 // not have to check for overflow. The same is true for writes of large
1259 // relocation info entries.
1260 static const int kGap = 32;
Andrei Popescu31002712010-02-23 13:46:05 +00001261
Steve Block44f0eee2011-05-26 01:26:41 +01001262
1263 // Repeated checking whether the trampoline pool should be emitted is rather
1264 // expensive. By default we only check again once a number of instructions
1265 // has been generated.
1266 static const int kCheckConstIntervalInst = 32;
1267 static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize;
1268
1269 int next_buffer_check_; // pc offset of next buffer check.
1270
1271 // Emission of the trampoline pool may be blocked in some code sequences.
1272 int trampoline_pool_blocked_nesting_; // Block emission if this is not zero.
1273 int no_trampoline_pool_before_; // Block emission before this pc offset.
1274
1275 // Keep track of the last emitted pool to guarantee a maximal distance.
1276 int last_trampoline_pool_end_; // pc offset of the end of the last pool.
1277
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001278 // Automatic growth of the assembly buffer may be blocked for some sequences.
1279 bool block_buffer_growth_; // Block growth when true.
1280
Andrei Popescu31002712010-02-23 13:46:05 +00001281 // Relocation information generation.
1282 // Each relocation is encoded as a variable size value.
1283 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1284 RelocInfoWriter reloc_info_writer;
1285
1286 // The bound position, before this we cannot do instruction elimination.
1287 int last_bound_pos_;
1288
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001289 // Readable constants for compact branch handling in emit()
1290 enum class CompactBranchType : bool { NO = false, COMPACT_BRANCH = true };
1291
Andrei Popescu31002712010-02-23 13:46:05 +00001292 // Code emission.
Andrei Popescu31002712010-02-23 13:46:05 +00001293 void GrowBuffer();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001294 inline void emit(Instr x,
1295 CompactBranchType is_compact_branch = CompactBranchType::NO);
1296 inline void emit(uint64_t x);
1297 inline void CheckForEmitInForbiddenSlot();
1298 template <typename T>
1299 inline void EmitHelper(T x);
1300 inline void EmitHelper(Instr x, CompactBranchType is_compact_branch);
Andrei Popescu31002712010-02-23 13:46:05 +00001301
1302 // Instruction generation.
1303 // We have 3 different kind of encoding layout on MIPS.
1304 // However due to many different types of objects encoded in the same fields
1305 // we have quite a few aliases for each mode.
1306 // Using the same structure to refer to Register and FPURegister would spare a
1307 // few aliases, but mixing both does not look clean to me.
1308 // Anyway we could surely implement this differently.
1309
1310 void GenInstrRegister(Opcode opcode,
1311 Register rs,
1312 Register rt,
1313 Register rd,
1314 uint16_t sa = 0,
1315 SecondaryField func = NULLSF);
1316
1317 void GenInstrRegister(Opcode opcode,
Steve Block44f0eee2011-05-26 01:26:41 +01001318 Register rs,
1319 Register rt,
1320 uint16_t msb,
1321 uint16_t lsb,
1322 SecondaryField func);
1323
1324 void GenInstrRegister(Opcode opcode,
Andrei Popescu31002712010-02-23 13:46:05 +00001325 SecondaryField fmt,
1326 FPURegister ft,
1327 FPURegister fs,
1328 FPURegister fd,
1329 SecondaryField func = NULLSF);
1330
1331 void GenInstrRegister(Opcode opcode,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001332 FPURegister fr,
1333 FPURegister ft,
1334 FPURegister fs,
1335 FPURegister fd,
1336 SecondaryField func = NULLSF);
1337
1338 void GenInstrRegister(Opcode opcode,
Andrei Popescu31002712010-02-23 13:46:05 +00001339 SecondaryField fmt,
1340 Register rt,
1341 FPURegister fs,
1342 FPURegister fd,
1343 SecondaryField func = NULLSF);
1344
Steve Block44f0eee2011-05-26 01:26:41 +01001345 void GenInstrRegister(Opcode opcode,
1346 SecondaryField fmt,
1347 Register rt,
1348 FPUControlRegister fs,
1349 SecondaryField func = NULLSF);
1350
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001351 void GenInstrImmediate(
1352 Opcode opcode, Register rs, Register rt, int32_t j,
1353 CompactBranchType is_compact_branch = CompactBranchType::NO);
1354 void GenInstrImmediate(
1355 Opcode opcode, Register rs, SecondaryField SF, int32_t j,
1356 CompactBranchType is_compact_branch = CompactBranchType::NO);
1357 void GenInstrImmediate(
1358 Opcode opcode, Register r1, FPURegister r2, int32_t j,
1359 CompactBranchType is_compact_branch = CompactBranchType::NO);
1360 void GenInstrImmediate(
1361 Opcode opcode, Register rs, int32_t offset21,
1362 CompactBranchType is_compact_branch = CompactBranchType::NO);
1363 void GenInstrImmediate(Opcode opcode, Register rs, uint32_t offset21);
1364 void GenInstrImmediate(
1365 Opcode opcode, int32_t offset26,
1366 CompactBranchType is_compact_branch = CompactBranchType::NO);
Andrei Popescu31002712010-02-23 13:46:05 +00001367
1368
1369 void GenInstrJump(Opcode opcode,
1370 uint32_t address);
1371
1372
1373 // Labels.
1374 void print(Label* L);
1375 void bind_to(Label* L, int pos);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001376 void next(Label* L, bool is_internal);
Andrei Popescu31002712010-02-23 13:46:05 +00001377
Steve Block44f0eee2011-05-26 01:26:41 +01001378 // One trampoline consists of:
1379 // - space for trampoline slots,
1380 // - space for labels.
1381 //
1382 // Space for trampoline slots is equal to slot_count * 2 * kInstrSize.
1383 // Space for trampoline slots preceeds space for labels. Each label is of one
1384 // instruction size, so total amount for labels is equal to
1385 // label_count * kInstrSize.
1386 class Trampoline {
1387 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001388 Trampoline() {
1389 start_ = 0;
1390 next_slot_ = 0;
1391 free_slot_count_ = 0;
1392 end_ = 0;
1393 }
1394 Trampoline(int start, int slot_count) {
Steve Block44f0eee2011-05-26 01:26:41 +01001395 start_ = start;
1396 next_slot_ = start;
1397 free_slot_count_ = slot_count;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001398 end_ = start + slot_count * kTrampolineSlotsSize;
Steve Block44f0eee2011-05-26 01:26:41 +01001399 }
1400 int start() {
1401 return start_;
1402 }
1403 int end() {
1404 return end_;
1405 }
1406 int take_slot() {
Ben Murdoch257744e2011-11-30 15:57:28 +00001407 int trampoline_slot = kInvalidSlotPos;
1408 if (free_slot_count_ <= 0) {
1409 // We have run out of space on trampolines.
1410 // Make sure we fail in debug mode, so we become aware of each case
1411 // when this happens.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001412 DCHECK(0);
Ben Murdoch257744e2011-11-30 15:57:28 +00001413 // Internal exception will be caught.
1414 } else {
1415 trampoline_slot = next_slot_;
1416 free_slot_count_--;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001417 next_slot_ += kTrampolineSlotsSize;
Ben Murdoch257744e2011-11-30 15:57:28 +00001418 }
Steve Block44f0eee2011-05-26 01:26:41 +01001419 return trampoline_slot;
1420 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001421
Steve Block44f0eee2011-05-26 01:26:41 +01001422 private:
1423 int start_;
1424 int end_;
1425 int next_slot_;
1426 int free_slot_count_;
Steve Block44f0eee2011-05-26 01:26:41 +01001427 };
1428
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001429 int32_t get_trampoline_entry(int32_t pos);
1430 int unbound_labels_count_;
1431 // If trampoline is emitted, generated code is becoming large. As this is
1432 // already a slow case which can possibly break our code generation for the
1433 // extreme case, we use this information to trigger different mode of
1434 // branch instruction generation, where we use jump instructions rather
1435 // than regular branch instructions.
1436 bool trampoline_emitted_;
Ben Murdochda12d292016-06-02 14:46:10 +01001437#ifdef _MIPS_ARCH_MIPS32R6
1438 static const int kTrampolineSlotsSize = 2 * kInstrSize;
1439#else
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001440 static const int kTrampolineSlotsSize = 4 * kInstrSize;
Ben Murdochda12d292016-06-02 14:46:10 +01001441#endif
Steve Block44f0eee2011-05-26 01:26:41 +01001442 static const int kMaxBranchOffset = (1 << (18 - 1)) - 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001443 static const int kMaxCompactBranchOffset = (1 << (28 - 1)) - 1;
Ben Murdoch257744e2011-11-30 15:57:28 +00001444 static const int kInvalidSlotPos = -1;
Steve Block44f0eee2011-05-26 01:26:41 +01001445
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001446 // Internal reference positions, required for unbounded internal reference
1447 // labels.
1448 std::set<int> internal_reference_positions_;
1449
1450 void EmittedCompactBranchInstruction() { prev_instr_compact_branch_ = true; }
1451 void ClearCompactBranchState() { prev_instr_compact_branch_ = false; }
1452 bool prev_instr_compact_branch_ = false;
1453
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001454 Trampoline trampoline_;
Ben Murdoch257744e2011-11-30 15:57:28 +00001455 bool internal_trampoline_exception_;
Steve Block44f0eee2011-05-26 01:26:41 +01001456
Andrei Popescu31002712010-02-23 13:46:05 +00001457 friend class RegExpMacroAssemblerMIPS;
1458 friend class RelocInfo;
Steve Block44f0eee2011-05-26 01:26:41 +01001459 friend class CodePatcher;
1460 friend class BlockTrampolinePoolScope;
1461
Ben Murdochda12d292016-06-02 14:46:10 +01001462 AssemblerPositionsRecorder positions_recorder_;
1463 friend class AssemblerPositionsRecorder;
Steve Block44f0eee2011-05-26 01:26:41 +01001464 friend class EnsureSpace;
1465};
1466
1467
1468class EnsureSpace BASE_EMBEDDED {
1469 public:
1470 explicit EnsureSpace(Assembler* assembler) {
1471 assembler->CheckBuffer();
1472 }
Andrei Popescu31002712010-02-23 13:46:05 +00001473};
1474
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001475} // namespace internal
1476} // namespace v8
Andrei Popescu31002712010-02-23 13:46:05 +00001477
1478#endif // V8_ARM_ASSEMBLER_MIPS_H_