blob: 1abf1ab6a6975bc85d3c0dde645c0e32f77af979 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright (c) 1994-2006 Sun Microsystems Inc.
2// All Rights Reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions
6// are 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
14// distribution.
15//
16// - Neither the name of Sun Microsystems or the names of contributors may
17// be used to endorse or promote products derived from this software without
18// specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31// OF THE POSSIBILITY OF SUCH DAMAGE.
32
Leon Clarked91b9f72010-01-27 17:25:45 +000033// The original source code covered by the above license above has been
34// modified significantly by Google Inc.
Ben Murdoch692be652012-01-10 18:47:50 +000035// Copyright 2012 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +000036
37// A light-weight ARM Assembler
38// Generates user mode instructions for the ARM architecture up to version 5
39
40#ifndef V8_ARM_ASSEMBLER_ARM_H_
41#define V8_ARM_ASSEMBLER_ARM_H_
Ben Murdochb8a8cc12014-11-26 15:28:44 +000042
Steve Blocka7e24c12009-10-30 11:49:00 +000043#include <stdio.h>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000044#include <vector>
45
46#include "src/arm/constants-arm.h"
47#include "src/assembler.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000048
49namespace v8 {
50namespace internal {
51
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000052// clang-format off
53#define GENERAL_REGISTERS(V) \
54 V(r0) V(r1) V(r2) V(r3) V(r4) V(r5) V(r6) V(r7) \
55 V(r8) V(r9) V(r10) V(fp) V(ip) V(sp) V(lr) V(pc)
56
57#define ALLOCATABLE_GENERAL_REGISTERS(V) \
58 V(r0) V(r1) V(r2) V(r3) V(r4) V(r5) V(r6) V(r7) V(r8)
59
60#define DOUBLE_REGISTERS(V) \
61 V(d0) V(d1) V(d2) V(d3) V(d4) V(d5) V(d6) V(d7) \
62 V(d8) V(d9) V(d10) V(d11) V(d12) V(d13) V(d14) V(d15) \
63 V(d16) V(d17) V(d18) V(d19) V(d20) V(d21) V(d22) V(d23) \
64 V(d24) V(d25) V(d26) V(d27) V(d28) V(d29) V(d30) V(d31)
65
66#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
67 V(d0) V(d1) V(d2) V(d3) V(d4) V(d5) V(d6) V(d7) \
68 V(d8) V(d9) V(d10) V(d11) V(d12) V(d13) \
69 V(d16) V(d17) V(d18) V(d19) V(d20) V(d21) V(d22) V(d23) \
70 V(d24) V(d25) V(d26) V(d27) V(d28) V(d29) V(d30) V(d31)
71
72#define ALLOCATABLE_NO_VFP32_DOUBLE_REGISTERS(V) \
73 V(d0) V(d1) V(d2) V(d3) V(d4) V(d5) V(d6) V(d7) \
74 V(d8) V(d9) V(d10) V(d11) V(d12) V(d13) \
75// clang-format on
76
Steve Blocka7e24c12009-10-30 11:49:00 +000077// CPU Registers.
78//
79// 1) We would prefer to use an enum, but enum values are assignment-
80// compatible with int, which has caused code-generation bugs.
81//
82// 2) We would prefer to use a class instead of a struct but we don't like
83// the register initialization to depend on the particular initialization
84// order (which appears to be different on OS X, Linux, and Windows for the
85// installed versions of C++ we tried). Using a struct permits C-style
86// "initialization". Also, the Register objects cannot be const as this
87// forces initialization stubs in MSVC, making us dependent on initialization
88// order.
89//
90// 3) By not using an enum, we are possibly preventing the compiler from
91// doing certain constant folds, which may significantly reduce the
92// code generated for some assembly instructions (because they boil down
93// to a few constants). If this is a problem, we could change the code
94// such that we use an enum in optimized mode, and the struct in debug
95// mode. This way we get the compile-time error checking in debug mode
96// and best performance in optimized code.
Steve Block9fac8402011-05-12 15:51:54 +010097
Ben Murdochb8a8cc12014-11-26 15:28:44 +000098struct Register {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000099 enum Code {
100#define REGISTER_CODE(R) kCode_##R,
101 GENERAL_REGISTERS(REGISTER_CODE)
102#undef REGISTER_CODE
103 kAfterLast,
104 kCode_no_reg = -1
105 };
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000106
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000107 static const int kNumRegisters = Code::kAfterLast;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000108
109 static Register from_code(int code) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000110 DCHECK(code >= 0);
111 DCHECK(code < kNumRegisters);
112 Register r = {code};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000113 return r;
114 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000115 const char* ToString();
116 bool IsAllocatable() const;
117 bool is_valid() const { return 0 <= reg_code && reg_code < kNumRegisters; }
118 bool is(Register reg) const { return reg_code == reg.reg_code; }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000119 int code() const {
120 DCHECK(is_valid());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000121 return reg_code;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000122 }
123 int bit() const {
124 DCHECK(is_valid());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000125 return 1 << reg_code;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000126 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000127 void set_code(int code) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000128 reg_code = code;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000129 DCHECK(is_valid());
130 }
131
132 // Unfortunately we can't make this private in a struct.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000133 int reg_code;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000134};
135
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000136// r7: context register
137// r8: constant pool pointer register if FLAG_enable_embedded_constant_pool.
138// r9: lithium scratch
139#define DECLARE_REGISTER(R) const Register R = {Register::kCode_##R};
140GENERAL_REGISTERS(DECLARE_REGISTER)
141#undef DECLARE_REGISTER
142const Register no_reg = {Register::kCode_no_reg};
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100143
Leon Clarkee46be812010-01-19 14:06:41 +0000144// Single word VFP register.
145struct SwVfpRegister {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000146 static const int kSizeInBytes = 4;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000147 bool is_valid() const { return 0 <= reg_code && reg_code < 32; }
148 bool is(SwVfpRegister reg) const { return reg_code == reg.reg_code; }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100149 int code() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000150 DCHECK(is_valid());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000151 return reg_code;
Leon Clarkee46be812010-01-19 14:06:41 +0000152 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100153 int bit() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000154 DCHECK(is_valid());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000155 return 1 << reg_code;
Leon Clarkee46be812010-01-19 14:06:41 +0000156 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100157 void split_code(int* vm, int* m) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000158 DCHECK(is_valid());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000159 *m = reg_code & 0x1;
160 *vm = reg_code >> 1;
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100161 }
Leon Clarkee46be812010-01-19 14:06:41 +0000162
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000163 int reg_code;
Leon Clarkee46be812010-01-19 14:06:41 +0000164};
165
166
167// Double word VFP register.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000168struct DoubleRegister {
169 enum Code {
170#define REGISTER_CODE(R) kCode_##R,
171 DOUBLE_REGISTERS(REGISTER_CODE)
172#undef REGISTER_CODE
173 kAfterLast,
174 kCode_no_reg = -1
175 };
176
177 static const int kMaxNumRegisters = Code::kAfterLast;
178
179 inline static int NumRegisters();
180
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000181 // A few double registers are reserved: one as a scratch register and one to
182 // hold 0.0, that does not fit in the immediate field of vmov instructions.
183 // d14: 0.0
184 // d15: scratch register.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000185 static const int kSizeInBytes = 8;
186
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000187 const char* ToString();
188 bool IsAllocatable() const;
189 bool is_valid() const { return 0 <= reg_code && reg_code < kMaxNumRegisters; }
190 bool is(DoubleRegister reg) const { return reg_code == reg.reg_code; }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100191 int code() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000192 DCHECK(is_valid());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000193 return reg_code;
Leon Clarkee46be812010-01-19 14:06:41 +0000194 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100195 int bit() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000196 DCHECK(is_valid());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000197 return 1 << reg_code;
198 }
199
200 static DoubleRegister from_code(int code) {
201 DoubleRegister r = {code};
202 return r;
Leon Clarkee46be812010-01-19 14:06:41 +0000203 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100204 void split_code(int* vm, int* m) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000205 DCHECK(is_valid());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000206 *m = (reg_code & 0x10) >> 4;
207 *vm = reg_code & 0x0F;
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100208 }
Leon Clarkee46be812010-01-19 14:06:41 +0000209
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000210 int reg_code;
Leon Clarkee46be812010-01-19 14:06:41 +0000211};
212
213
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000214typedef DoubleRegister DwVfpRegister;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100215
216
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000217// Double word VFP register d0-15.
218struct LowDwVfpRegister {
219 public:
220 static const int kMaxNumLowRegisters = 16;
221 operator DwVfpRegister() const {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000222 DwVfpRegister r = { reg_code };
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000223 return r;
224 }
225 static LowDwVfpRegister from_code(int code) {
226 LowDwVfpRegister r = { code };
227 return r;
228 }
229
230 bool is_valid() const {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000231 return 0 <= reg_code && reg_code < kMaxNumLowRegisters;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000232 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000233 bool is(DwVfpRegister reg) const { return reg_code == reg.reg_code; }
234 bool is(LowDwVfpRegister reg) const { return reg_code == reg.reg_code; }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000235 int code() const {
236 DCHECK(is_valid());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000237 return reg_code;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000238 }
239 SwVfpRegister low() const {
240 SwVfpRegister reg;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000241 reg.reg_code = reg_code * 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000242
243 DCHECK(reg.is_valid());
244 return reg;
245 }
246 SwVfpRegister high() const {
247 SwVfpRegister reg;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000248 reg.reg_code = (reg_code * 2) + 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000249
250 DCHECK(reg.is_valid());
251 return reg;
252 }
253
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000254 int reg_code;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000255};
256
257
258// Quad word NEON register.
259struct QwNeonRegister {
260 static const int kMaxNumRegisters = 16;
261
262 static QwNeonRegister from_code(int code) {
263 QwNeonRegister r = { code };
264 return r;
265 }
266
267 bool is_valid() const {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000268 return (0 <= reg_code) && (reg_code < kMaxNumRegisters);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000269 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000270 bool is(QwNeonRegister reg) const { return reg_code == reg.reg_code; }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000271 int code() const {
272 DCHECK(is_valid());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000273 return reg_code;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000274 }
275 void split_code(int* vm, int* m) const {
276 DCHECK(is_valid());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000277 int encoded_code = reg_code << 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000278 *m = (encoded_code & 0x10) >> 4;
279 *vm = encoded_code & 0x0F;
280 }
281
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000282 int reg_code;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000283};
284
285
286typedef QwNeonRegister QuadRegister;
287
288
Steve Block6ded16b2010-05-10 14:33:55 +0100289// Support for the VFP registers s0 to s31 (d0 to d15).
Leon Clarkee46be812010-01-19 14:06:41 +0000290// Note that "s(N):s(N+1)" is the same as "d(N/2)".
Steve Block6ded16b2010-05-10 14:33:55 +0100291const SwVfpRegister s0 = { 0 };
292const SwVfpRegister s1 = { 1 };
293const SwVfpRegister s2 = { 2 };
294const SwVfpRegister s3 = { 3 };
295const SwVfpRegister s4 = { 4 };
296const SwVfpRegister s5 = { 5 };
297const SwVfpRegister s6 = { 6 };
298const SwVfpRegister s7 = { 7 };
299const SwVfpRegister s8 = { 8 };
300const SwVfpRegister s9 = { 9 };
301const SwVfpRegister s10 = { 10 };
302const SwVfpRegister s11 = { 11 };
303const SwVfpRegister s12 = { 12 };
304const SwVfpRegister s13 = { 13 };
305const SwVfpRegister s14 = { 14 };
306const SwVfpRegister s15 = { 15 };
307const SwVfpRegister s16 = { 16 };
308const SwVfpRegister s17 = { 17 };
309const SwVfpRegister s18 = { 18 };
310const SwVfpRegister s19 = { 19 };
311const SwVfpRegister s20 = { 20 };
312const SwVfpRegister s21 = { 21 };
313const SwVfpRegister s22 = { 22 };
314const SwVfpRegister s23 = { 23 };
315const SwVfpRegister s24 = { 24 };
316const SwVfpRegister s25 = { 25 };
317const SwVfpRegister s26 = { 26 };
318const SwVfpRegister s27 = { 27 };
319const SwVfpRegister s28 = { 28 };
320const SwVfpRegister s29 = { 29 };
321const SwVfpRegister s30 = { 30 };
322const SwVfpRegister s31 = { 31 };
Leon Clarkee46be812010-01-19 14:06:41 +0000323
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100324const DwVfpRegister no_dreg = { -1 };
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000325const LowDwVfpRegister d0 = { 0 };
326const LowDwVfpRegister d1 = { 1 };
327const LowDwVfpRegister d2 = { 2 };
328const LowDwVfpRegister d3 = { 3 };
329const LowDwVfpRegister d4 = { 4 };
330const LowDwVfpRegister d5 = { 5 };
331const LowDwVfpRegister d6 = { 6 };
332const LowDwVfpRegister d7 = { 7 };
333const LowDwVfpRegister d8 = { 8 };
334const LowDwVfpRegister d9 = { 9 };
335const LowDwVfpRegister d10 = { 10 };
336const LowDwVfpRegister d11 = { 11 };
337const LowDwVfpRegister d12 = { 12 };
338const LowDwVfpRegister d13 = { 13 };
339const LowDwVfpRegister d14 = { 14 };
340const LowDwVfpRegister d15 = { 15 };
341const DwVfpRegister d16 = { 16 };
342const DwVfpRegister d17 = { 17 };
343const DwVfpRegister d18 = { 18 };
344const DwVfpRegister d19 = { 19 };
345const DwVfpRegister d20 = { 20 };
346const DwVfpRegister d21 = { 21 };
347const DwVfpRegister d22 = { 22 };
348const DwVfpRegister d23 = { 23 };
349const DwVfpRegister d24 = { 24 };
350const DwVfpRegister d25 = { 25 };
351const DwVfpRegister d26 = { 26 };
352const DwVfpRegister d27 = { 27 };
353const DwVfpRegister d28 = { 28 };
354const DwVfpRegister d29 = { 29 };
355const DwVfpRegister d30 = { 30 };
356const DwVfpRegister d31 = { 31 };
357
358const QwNeonRegister q0 = { 0 };
359const QwNeonRegister q1 = { 1 };
360const QwNeonRegister q2 = { 2 };
361const QwNeonRegister q3 = { 3 };
362const QwNeonRegister q4 = { 4 };
363const QwNeonRegister q5 = { 5 };
364const QwNeonRegister q6 = { 6 };
365const QwNeonRegister q7 = { 7 };
366const QwNeonRegister q8 = { 8 };
367const QwNeonRegister q9 = { 9 };
368const QwNeonRegister q10 = { 10 };
369const QwNeonRegister q11 = { 11 };
370const QwNeonRegister q12 = { 12 };
371const QwNeonRegister q13 = { 13 };
372const QwNeonRegister q14 = { 14 };
373const QwNeonRegister q15 = { 15 };
374
Leon Clarkee46be812010-01-19 14:06:41 +0000375
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100376// Aliases for double registers. Defined using #define instead of
377// "static const DwVfpRegister&" because Clang complains otherwise when a
378// compilation unit that includes this header doesn't use the variables.
379#define kFirstCalleeSavedDoubleReg d8
380#define kLastCalleeSavedDoubleReg d15
381#define kDoubleRegZero d14
382#define kScratchDoubleReg d15
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +0100383
Steve Blocka7e24c12009-10-30 11:49:00 +0000384
385// Coprocessor register
386struct CRegister {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000387 bool is_valid() const { return 0 <= reg_code && reg_code < 16; }
388 bool is(CRegister creg) const { return reg_code == creg.reg_code; }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100389 int code() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000390 DCHECK(is_valid());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000391 return reg_code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000392 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100393 int bit() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000394 DCHECK(is_valid());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000395 return 1 << reg_code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000396 }
397
Andrei Popescu31002712010-02-23 13:46:05 +0000398 // Unfortunately we can't make this private in a struct.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000399 int reg_code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000400};
401
402
Steve Block6ded16b2010-05-10 14:33:55 +0100403const CRegister no_creg = { -1 };
404
405const CRegister cr0 = { 0 };
406const CRegister cr1 = { 1 };
407const CRegister cr2 = { 2 };
408const CRegister cr3 = { 3 };
409const CRegister cr4 = { 4 };
410const CRegister cr5 = { 5 };
411const CRegister cr6 = { 6 };
412const CRegister cr7 = { 7 };
413const CRegister cr8 = { 8 };
414const CRegister cr9 = { 9 };
415const CRegister cr10 = { 10 };
416const CRegister cr11 = { 11 };
417const CRegister cr12 = { 12 };
418const CRegister cr13 = { 13 };
419const CRegister cr14 = { 14 };
420const CRegister cr15 = { 15 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000421
422
423// Coprocessor number
424enum Coprocessor {
425 p0 = 0,
426 p1 = 1,
427 p2 = 2,
428 p3 = 3,
429 p4 = 4,
430 p5 = 5,
431 p6 = 6,
432 p7 = 7,
433 p8 = 8,
434 p9 = 9,
435 p10 = 10,
436 p11 = 11,
437 p12 = 12,
438 p13 = 13,
439 p14 = 14,
440 p15 = 15
441};
442
443
Steve Blocka7e24c12009-10-30 11:49:00 +0000444// -----------------------------------------------------------------------------
445// Machine instruction Operands
446
447// Class Operand represents a shifter operand in data processing instructions
448class Operand BASE_EMBEDDED {
449 public:
450 // immediate
451 INLINE(explicit Operand(int32_t immediate,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000452 RelocInfo::Mode rmode = RelocInfo::NONE32));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000453 INLINE(static Operand Zero()) {
454 return Operand(static_cast<int32_t>(0));
455 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000456 INLINE(explicit Operand(const ExternalReference& f));
Steve Blocka7e24c12009-10-30 11:49:00 +0000457 explicit Operand(Handle<Object> handle);
458 INLINE(explicit Operand(Smi* value));
459
460 // rm
461 INLINE(explicit Operand(Register rm));
462
463 // rm <shift_op> shift_imm
464 explicit Operand(Register rm, ShiftOp shift_op, int shift_imm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000465 INLINE(static Operand SmiUntag(Register rm)) {
466 return Operand(rm, ASR, kSmiTagSize);
467 }
468 INLINE(static Operand PointerOffsetFromSmiKey(Register key)) {
469 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
470 return Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize);
471 }
472 INLINE(static Operand DoubleOffsetFromSmiKey(Register key)) {
473 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kDoubleSizeLog2);
474 return Operand(key, LSL, kDoubleSizeLog2 - kSmiTagSize);
475 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000476
477 // rm <shift_op> rs
478 explicit Operand(Register rm, ShiftOp shift_op, Register rs);
479
480 // Return true if this is a register operand.
481 INLINE(bool is_reg() const);
482
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000483 // Return the number of actual instructions required to implement the given
484 // instruction for this particular operand. This can be a single instruction,
485 // if no load into the ip register is necessary, or anything between 2 and 4
486 // instructions when we need to load from the constant pool (depending upon
487 // whether the constant pool entry is in the small or extended section). If
Steve Block44f0eee2011-05-26 01:26:41 +0100488 // the instruction this operand is used for is a MOV or MVN instruction the
489 // actual instruction to use is required for this calculation. For other
490 // instructions instr is ignored.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000491 //
492 // The value returned is only valid as long as no entries are added to the
493 // constant pool between this call and the actual instruction being emitted.
494 int instructions_required(const Assembler* assembler, Instr instr = 0) const;
495 bool must_output_reloc_info(const Assembler* assembler) const;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100496
497 inline int32_t immediate() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000498 DCHECK(!rm_.is_valid());
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100499 return imm32_;
500 }
501
Steve Blocka7e24c12009-10-30 11:49:00 +0000502 Register rm() const { return rm_; }
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100503 Register rs() const { return rs_; }
504 ShiftOp shift_op() const { return shift_op_; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000505
506 private:
507 Register rm_;
508 Register rs_;
509 ShiftOp shift_op_;
510 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
511 int32_t imm32_; // valid if rm_ == no_reg
512 RelocInfo::Mode rmode_;
513
514 friend class Assembler;
515};
516
517
518// Class MemOperand represents a memory operand in load and store instructions
519class MemOperand BASE_EMBEDDED {
520 public:
521 // [rn +/- offset] Offset/NegOffset
522 // [rn +/- offset]! PreIndex/NegPreIndex
523 // [rn], +/- offset PostIndex/NegPostIndex
524 // offset is any signed 32-bit value; offset is first loaded to register ip if
525 // it does not fit the addressing mode (12-bit unsigned and sign bit)
526 explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset);
527
528 // [rn +/- rm] Offset/NegOffset
529 // [rn +/- rm]! PreIndex/NegPreIndex
530 // [rn], +/- rm PostIndex/NegPostIndex
531 explicit MemOperand(Register rn, Register rm, AddrMode am = Offset);
532
533 // [rn +/- rm <shift_op> shift_imm] Offset/NegOffset
534 // [rn +/- rm <shift_op> shift_imm]! PreIndex/NegPreIndex
535 // [rn], +/- rm <shift_op> shift_imm PostIndex/NegPostIndex
536 explicit MemOperand(Register rn, Register rm,
537 ShiftOp shift_op, int shift_imm, AddrMode am = Offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000538 INLINE(static MemOperand PointerAddressFromSmiKey(Register array,
539 Register key,
540 AddrMode am = Offset)) {
541 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
542 return MemOperand(array, key, LSL, kPointerSizeLog2 - kSmiTagSize, am);
543 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000544
Kristian Monsen25f61362010-05-21 11:50:48 +0100545 void set_offset(int32_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000546 DCHECK(rm_.is(no_reg));
Kristian Monsen25f61362010-05-21 11:50:48 +0100547 offset_ = offset;
548 }
549
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100550 uint32_t offset() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000551 DCHECK(rm_.is(no_reg));
Kristian Monsen25f61362010-05-21 11:50:48 +0100552 return offset_;
553 }
554
Leon Clarkef7060e22010-06-03 12:02:55 +0100555 Register rn() const { return rn_; }
556 Register rm() const { return rm_; }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000557 AddrMode am() const { return am_; }
Kristian Monsen25f61362010-05-21 11:50:48 +0100558
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100559 bool OffsetIsUint12Encodable() const {
560 return offset_ >= 0 ? is_uint12(offset_) : is_uint12(-offset_);
561 }
562
Steve Blocka7e24c12009-10-30 11:49:00 +0000563 private:
564 Register rn_; // base
565 Register rm_; // register offset
566 int32_t offset_; // valid if rm_ == no_reg
567 ShiftOp shift_op_;
568 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
569 AddrMode am_; // bits P, U, and W
570
571 friend class Assembler;
572};
573
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000574
575// Class NeonMemOperand represents a memory operand in load and
576// store NEON instructions
577class NeonMemOperand BASE_EMBEDDED {
Steve Blockd0582a62009-12-15 09:54:21 +0000578 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000579 // [rn {:align}] Offset
580 // [rn {:align}]! PostIndex
581 explicit NeonMemOperand(Register rn, AddrMode am = Offset, int align = 0);
Steve Blockd0582a62009-12-15 09:54:21 +0000582
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000583 // [rn {:align}], rm PostIndex
584 explicit NeonMemOperand(Register rn, Register rm, int align = 0);
Steve Blockd0582a62009-12-15 09:54:21 +0000585
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000586 Register rn() const { return rn_; }
587 Register rm() const { return rm_; }
588 int align() const { return align_; }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100589
Steve Blockd0582a62009-12-15 09:54:21 +0000590 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000591 void SetAlignment(int align);
Steve Block44f0eee2011-05-26 01:26:41 +0100592
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000593 Register rn_; // base
594 Register rm_; // register increment
595 int align_;
Steve Blockd0582a62009-12-15 09:54:21 +0000596};
597
Steve Blocka7e24c12009-10-30 11:49:00 +0000598
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000599// Class NeonListOperand represents a list of NEON registers
600class NeonListOperand BASE_EMBEDDED {
601 public:
602 explicit NeonListOperand(DoubleRegister base, int registers_count = 1);
603 DoubleRegister base() const { return base_; }
604 NeonListType type() const { return type_; }
605 private:
606 DoubleRegister base_;
607 NeonListType type_;
608};
Steve Blocka7e24c12009-10-30 11:49:00 +0000609
Steve Block1e0659c2011-05-24 12:43:12 +0100610
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000611struct VmovIndex {
612 unsigned char index;
613};
614const VmovIndex VmovIndexLo = { 0 };
615const VmovIndex VmovIndexHi = { 1 };
Steve Block1e0659c2011-05-24 12:43:12 +0100616
Steve Block44f0eee2011-05-26 01:26:41 +0100617class Assembler : public AssemblerBase {
Steve Blocka7e24c12009-10-30 11:49:00 +0000618 public:
619 // Create an assembler. Instructions and relocation information are emitted
620 // into a buffer, with the instructions starting from the beginning and the
621 // relocation information starting from the end of the buffer. See CodeDesc
622 // for a detailed comment on the layout (globals.h).
623 //
624 // If the provided buffer is NULL, the assembler allocates and grows its own
625 // buffer, and buffer_size determines the initial buffer size. The buffer is
626 // owned by the assembler and deallocated upon destruction of the assembler.
627 //
628 // If the provided buffer is not NULL, the assembler uses the provided buffer
629 // for code generation and assumes its size to be buffer_size. If the buffer
630 // is too small, a fatal error occurs. No deallocation of the buffer is done
631 // upon destruction of the assembler.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100632 Assembler(Isolate* isolate, void* buffer, int buffer_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000633 virtual ~Assembler();
Steve Block44f0eee2011-05-26 01:26:41 +0100634
Steve Blocka7e24c12009-10-30 11:49:00 +0000635 // GetCode emits any pending (non-emitted) code and fills the descriptor
636 // desc. GetCode() is idempotent; it returns the same result if no other
637 // Assembler functions are invoked in between GetCode() calls.
638 void GetCode(CodeDesc* desc);
639
640 // Label operations & relative jumps (PPUM Appendix D)
641 //
642 // Takes a branch opcode (cc) and a label (L) and generates
643 // either a backward branch or a forward branch and links it
644 // to the label fixup chain. Usage:
645 //
646 // Label L; // unbound label
647 // j(cc, &L); // forward branch to unbound label
648 // bind(&L); // bind label to the current pc
649 // j(cc, &L); // backward branch to bound label
650 // bind(&L); // illegal: a label may be bound only once
651 //
652 // Note: The same Label can be used for forward and backward branches
653 // but it may be bound only once.
654
655 void bind(Label* L); // binds an unbound label L to the current code position
656
657 // Returns the branch offset to the given label from the current code position
658 // Links the label to the current position if it is still unbound
659 // Manages the jump elimination optimization if the second parameter is true.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000660 int branch_offset(Label* L);
Steve Blocka7e24c12009-10-30 11:49:00 +0000661
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000662 // Returns true if the given pc address is the start of a constant pool load
663 // instruction sequence.
664 INLINE(static bool is_constant_pool_load(Address pc));
Steve Blocka7e24c12009-10-30 11:49:00 +0000665
666 // Return the address in the constant pool of the code target address used by
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000667 // the branch/call instruction at pc, or the object in a mov.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000668 INLINE(static Address constant_pool_entry_address(Address pc,
669 Address constant_pool));
Steve Blocka7e24c12009-10-30 11:49:00 +0000670
671 // Read/Modify the code target address in the branch/call instruction at pc.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000672 INLINE(static Address target_address_at(Address pc, Address constant_pool));
673 INLINE(static void set_target_address_at(
674 Isolate* isolate, Address pc, Address constant_pool, Address target,
675 ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000676 INLINE(static Address target_address_at(Address pc, Code* code)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000677 Address constant_pool = code ? code->constant_pool() : NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000678 return target_address_at(pc, constant_pool);
679 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000680 INLINE(static void set_target_address_at(
681 Isolate* isolate, Address pc, Code* code, Address target,
682 ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED)) {
683 Address constant_pool = code ? code->constant_pool() : NULL;
684 set_target_address_at(isolate, pc, constant_pool, target,
685 icache_flush_mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000686 }
687
688 // Return the code target address at a call site from the return address
689 // of that call in the instruction stream.
690 INLINE(static Address target_address_from_return_address(Address pc));
691
692 // Given the address of the beginning of a call, return the address
693 // in the instruction stream that the call will return from.
694 INLINE(static Address return_address_from_call_start(Address pc));
695
Steve Blockd0582a62009-12-15 09:54:21 +0000696 // This sets the branch destination (which is in the constant pool on ARM).
697 // This is for calls and branches within generated code.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100698 inline static void deserialization_set_special_target_at(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000699 Isolate* isolate, Address constant_pool_entry, Code* code,
700 Address target);
701
702 // This sets the internal reference at the pc.
703 inline static void deserialization_set_target_internal_reference_at(
704 Isolate* isolate, Address pc, Address target,
705 RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE);
Steve Blockd0582a62009-12-15 09:54:21 +0000706
707 // Here we are patching the address in the constant pool, not the actual call
708 // instruction. The address in the constant pool is the same size as a
709 // pointer.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100710 static const int kSpecialTargetSize = kPointerSize;
Steve Blockd0582a62009-12-15 09:54:21 +0000711
Steve Blocka7e24c12009-10-30 11:49:00 +0000712 // Size of an instruction.
713 static const int kInstrSize = sizeof(Instr);
714
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100715 // Distance between start of patched debug break slot and the emitted address
716 // to jump to.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100717 // Patched debug break slot code is:
718 // ldr ip, [pc, #0] @ emited address and start
719 // blx ip
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000720 static const int kPatchDebugBreakSlotAddressOffset = 2 * kInstrSize;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100721
Steve Blocka7e24c12009-10-30 11:49:00 +0000722 // Difference between address of current opcode and value read from pc
723 // register.
724 static const int kPcLoadDelta = 8;
725
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000726 static const int kDebugBreakSlotInstructions = 4;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100727 static const int kDebugBreakSlotLength =
728 kDebugBreakSlotInstructions * kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +0000729
730 // ---------------------------------------------------------------------------
731 // Code generation
732
733 // Insert the smallest number of nop instructions
734 // possible to align the pc offset to a multiple
735 // of m. m must be a power of 2 (>= 4).
736 void Align(int m);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000737 // Insert the smallest number of zero bytes possible to align the pc offset
738 // to a mulitple of m. m must be a power of 2 (>= 2).
739 void DataAlign(int m);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100740 // Aligns code to something that's optimal for a jump target for the platform.
741 void CodeTargetAlign();
Steve Blocka7e24c12009-10-30 11:49:00 +0000742
743 // Branch instructions
744 void b(int branch_offset, Condition cond = al);
745 void bl(int branch_offset, Condition cond = al);
746 void blx(int branch_offset); // v5 and above
747 void blx(Register target, Condition cond = al); // v5 and above
748 void bx(Register target, Condition cond = al); // v5 and above, plus v4t
749
750 // Convenience branch instructions using labels
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000751 void b(Label* L, Condition cond = al);
752 void b(Condition cond, Label* L) { b(L, cond); }
753 void bl(Label* L, Condition cond = al);
754 void bl(Condition cond, Label* L) { bl(L, cond); }
755 void blx(Label* L); // v5 and above
Steve Blocka7e24c12009-10-30 11:49:00 +0000756
757 // Data-processing instructions
Andrei Popescu31002712010-02-23 13:46:05 +0000758
Steve Blocka7e24c12009-10-30 11:49:00 +0000759 void and_(Register dst, Register src1, const Operand& src2,
760 SBit s = LeaveCC, Condition cond = al);
761
762 void eor(Register dst, Register src1, const Operand& src2,
763 SBit s = LeaveCC, Condition cond = al);
764
765 void sub(Register dst, Register src1, const Operand& src2,
766 SBit s = LeaveCC, Condition cond = al);
767 void sub(Register dst, Register src1, Register src2,
768 SBit s = LeaveCC, Condition cond = al) {
769 sub(dst, src1, Operand(src2), s, cond);
770 }
771
772 void rsb(Register dst, Register src1, const Operand& src2,
773 SBit s = LeaveCC, Condition cond = al);
774
775 void add(Register dst, Register src1, const Operand& src2,
776 SBit s = LeaveCC, Condition cond = al);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100777 void add(Register dst, Register src1, Register src2,
778 SBit s = LeaveCC, Condition cond = al) {
779 add(dst, src1, Operand(src2), s, cond);
780 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000781
782 void adc(Register dst, Register src1, const Operand& src2,
783 SBit s = LeaveCC, Condition cond = al);
784
785 void sbc(Register dst, Register src1, const Operand& src2,
786 SBit s = LeaveCC, Condition cond = al);
787
788 void rsc(Register dst, Register src1, const Operand& src2,
789 SBit s = LeaveCC, Condition cond = al);
790
791 void tst(Register src1, const Operand& src2, Condition cond = al);
792 void tst(Register src1, Register src2, Condition cond = al) {
793 tst(src1, Operand(src2), cond);
794 }
795
796 void teq(Register src1, const Operand& src2, Condition cond = al);
797
798 void cmp(Register src1, const Operand& src2, Condition cond = al);
799 void cmp(Register src1, Register src2, Condition cond = al) {
800 cmp(src1, Operand(src2), cond);
801 }
Steve Block1e0659c2011-05-24 12:43:12 +0100802 void cmp_raw_immediate(Register src1, int raw_immediate, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000803
804 void cmn(Register src1, const Operand& src2, Condition cond = al);
805
806 void orr(Register dst, Register src1, const Operand& src2,
807 SBit s = LeaveCC, Condition cond = al);
808 void orr(Register dst, Register src1, Register src2,
809 SBit s = LeaveCC, Condition cond = al) {
810 orr(dst, src1, Operand(src2), s, cond);
811 }
812
813 void mov(Register dst, const Operand& src,
814 SBit s = LeaveCC, Condition cond = al);
815 void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
816 mov(dst, Operand(src), s, cond);
817 }
818
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000819 // Load the position of the label relative to the generated code object
820 // pointer in a register.
821 void mov_label_offset(Register dst, Label* label);
822
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100823 // ARMv7 instructions for loading a 32 bit immediate in two instructions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000824 // The constant for movw and movt should be in the range 0-0xffff.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100825 void movw(Register reg, uint32_t immediate, Condition cond = al);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100826 void movt(Register reg, uint32_t immediate, Condition cond = al);
827
Steve Blocka7e24c12009-10-30 11:49:00 +0000828 void bic(Register dst, Register src1, const Operand& src2,
829 SBit s = LeaveCC, Condition cond = al);
830
831 void mvn(Register dst, const Operand& src,
832 SBit s = LeaveCC, Condition cond = al);
833
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000834 // Shift instructions
835
836 void asr(Register dst, Register src1, const Operand& src2, SBit s = LeaveCC,
837 Condition cond = al) {
838 if (src2.is_reg()) {
839 mov(dst, Operand(src1, ASR, src2.rm()), s, cond);
840 } else {
841 mov(dst, Operand(src1, ASR, src2.immediate()), s, cond);
842 }
843 }
844
845 void lsl(Register dst, Register src1, const Operand& src2, SBit s = LeaveCC,
846 Condition cond = al) {
847 if (src2.is_reg()) {
848 mov(dst, Operand(src1, LSL, src2.rm()), s, cond);
849 } else {
850 mov(dst, Operand(src1, LSL, src2.immediate()), s, cond);
851 }
852 }
853
854 void lsr(Register dst, Register src1, const Operand& src2, SBit s = LeaveCC,
855 Condition cond = al) {
856 if (src2.is_reg()) {
857 mov(dst, Operand(src1, LSR, src2.rm()), s, cond);
858 } else {
859 mov(dst, Operand(src1, LSR, src2.immediate()), s, cond);
860 }
861 }
862
Steve Blocka7e24c12009-10-30 11:49:00 +0000863 // Multiply instructions
864
865 void mla(Register dst, Register src1, Register src2, Register srcA,
866 SBit s = LeaveCC, Condition cond = al);
867
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000868 void mls(Register dst, Register src1, Register src2, Register srcA,
869 Condition cond = al);
870
871 void sdiv(Register dst, Register src1, Register src2,
872 Condition cond = al);
873
874 void udiv(Register dst, Register src1, Register src2, Condition cond = al);
875
Steve Blocka7e24c12009-10-30 11:49:00 +0000876 void mul(Register dst, Register src1, Register src2,
877 SBit s = LeaveCC, Condition cond = al);
878
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400879 void smmla(Register dst, Register src1, Register src2, Register srcA,
880 Condition cond = al);
881
882 void smmul(Register dst, Register src1, Register src2, Condition cond = al);
883
Steve Blocka7e24c12009-10-30 11:49:00 +0000884 void smlal(Register dstL, Register dstH, Register src1, Register src2,
885 SBit s = LeaveCC, Condition cond = al);
886
887 void smull(Register dstL, Register dstH, Register src1, Register src2,
888 SBit s = LeaveCC, Condition cond = al);
889
890 void umlal(Register dstL, Register dstH, Register src1, Register src2,
891 SBit s = LeaveCC, Condition cond = al);
892
893 void umull(Register dstL, Register dstH, Register src1, Register src2,
894 SBit s = LeaveCC, Condition cond = al);
895
896 // Miscellaneous arithmetic instructions
897
898 void clz(Register dst, Register src, Condition cond = al); // v5 and above
899
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100900 // Saturating instructions. v6 and above.
901
902 // Unsigned saturate.
903 //
904 // Saturate an optionally shifted signed value to an unsigned range.
905 //
906 // usat dst, #satpos, src
907 // usat dst, #satpos, src, lsl #sh
908 // usat dst, #satpos, src, asr #sh
909 //
910 // Register dst will contain:
911 //
912 // 0, if s < 0
913 // (1 << satpos) - 1, if s > ((1 << satpos) - 1)
914 // s, otherwise
915 //
916 // where s is the contents of src after shifting (if used.)
917 void usat(Register dst, int satpos, const Operand& src, Condition cond = al);
918
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100919 // Bitfield manipulation instructions. v7 and above.
920
921 void ubfx(Register dst, Register src, int lsb, int width,
922 Condition cond = al);
923
924 void sbfx(Register dst, Register src, int lsb, int width,
925 Condition cond = al);
926
927 void bfc(Register dst, int lsb, int width, Condition cond = al);
928
929 void bfi(Register dst, Register src, int lsb, int width,
930 Condition cond = al);
931
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000932 void pkhbt(Register dst, Register src1, const Operand& src2,
933 Condition cond = al);
934
935 void pkhtb(Register dst, Register src1, const Operand& src2,
936 Condition cond = al);
937
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400938 void sxtb(Register dst, Register src, int rotate = 0, Condition cond = al);
939 void sxtab(Register dst, Register src1, Register src2, int rotate = 0,
940 Condition cond = al);
941 void sxth(Register dst, Register src, int rotate = 0, Condition cond = al);
942 void sxtah(Register dst, Register src1, Register src2, int rotate = 0,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000943 Condition cond = al);
944
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400945 void uxtb(Register dst, Register src, int rotate = 0, Condition cond = al);
946 void uxtab(Register dst, Register src1, Register src2, int rotate = 0,
947 Condition cond = al);
948 void uxtb16(Register dst, Register src, int rotate = 0, Condition cond = al);
949 void uxth(Register dst, Register src, int rotate = 0, Condition cond = al);
950 void uxtah(Register dst, Register src1, Register src2, int rotate = 0,
951 Condition cond = al);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000952
Steve Blocka7e24c12009-10-30 11:49:00 +0000953 // Status register access instructions
954
955 void mrs(Register dst, SRegister s, Condition cond = al);
956 void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al);
957
958 // Load/Store instructions
959 void ldr(Register dst, const MemOperand& src, Condition cond = al);
960 void str(Register src, const MemOperand& dst, Condition cond = al);
961 void ldrb(Register dst, const MemOperand& src, Condition cond = al);
962 void strb(Register src, const MemOperand& dst, Condition cond = al);
963 void ldrh(Register dst, const MemOperand& src, Condition cond = al);
964 void strh(Register src, const MemOperand& dst, Condition cond = al);
965 void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
966 void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
Leon Clarkef7060e22010-06-03 12:02:55 +0100967 void ldrd(Register dst1,
968 Register dst2,
969 const MemOperand& src, Condition cond = al);
970 void strd(Register src1,
971 Register src2,
972 const MemOperand& dst, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000973
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000974 // Preload instructions
975 void pld(const MemOperand& address);
976
Steve Blocka7e24c12009-10-30 11:49:00 +0000977 // Load/Store multiple instructions
978 void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
979 void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
980
Steve Blocka7e24c12009-10-30 11:49:00 +0000981 // Exception-generating instructions and debugging support
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800982 void stop(const char* msg,
983 Condition cond = al,
984 int32_t code = kDefaultStopCode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000985
986 void bkpt(uint32_t imm16); // v5 and above
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800987 void svc(uint32_t imm24, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000988
989 // Coprocessor instructions
990
991 void cdp(Coprocessor coproc, int opcode_1,
992 CRegister crd, CRegister crn, CRegister crm,
993 int opcode_2, Condition cond = al);
994
995 void cdp2(Coprocessor coproc, int opcode_1,
996 CRegister crd, CRegister crn, CRegister crm,
997 int opcode_2); // v5 and above
998
999 void mcr(Coprocessor coproc, int opcode_1,
1000 Register rd, CRegister crn, CRegister crm,
1001 int opcode_2 = 0, Condition cond = al);
1002
1003 void mcr2(Coprocessor coproc, int opcode_1,
1004 Register rd, CRegister crn, CRegister crm,
1005 int opcode_2 = 0); // v5 and above
1006
1007 void mrc(Coprocessor coproc, int opcode_1,
1008 Register rd, CRegister crn, CRegister crm,
1009 int opcode_2 = 0, Condition cond = al);
1010
1011 void mrc2(Coprocessor coproc, int opcode_1,
1012 Register rd, CRegister crn, CRegister crm,
1013 int opcode_2 = 0); // v5 and above
1014
1015 void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src,
1016 LFlag l = Short, Condition cond = al);
1017 void ldc(Coprocessor coproc, CRegister crd, Register base, int option,
1018 LFlag l = Short, Condition cond = al);
1019
1020 void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
1021 LFlag l = Short); // v5 and above
1022 void ldc2(Coprocessor coproc, CRegister crd, Register base, int option,
1023 LFlag l = Short); // v5 and above
1024
Steve Blockd0582a62009-12-15 09:54:21 +00001025 // Support for VFP.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001026 // All these APIs support S0 to S31 and D0 to D31.
Steve Blockd0582a62009-12-15 09:54:21 +00001027
Leon Clarked91b9f72010-01-27 17:25:45 +00001028 void vldr(const DwVfpRegister dst,
1029 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001030 int offset,
1031 const Condition cond = al);
1032 void vldr(const DwVfpRegister dst,
1033 const MemOperand& src,
Leon Clarked91b9f72010-01-27 17:25:45 +00001034 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +01001035
1036 void vldr(const SwVfpRegister dst,
1037 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001038 int offset,
1039 const Condition cond = al);
1040 void vldr(const SwVfpRegister dst,
1041 const MemOperand& src,
Steve Block6ded16b2010-05-10 14:33:55 +01001042 const Condition cond = al);
1043
Leon Clarked91b9f72010-01-27 17:25:45 +00001044 void vstr(const DwVfpRegister src,
1045 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001046 int offset,
1047 const Condition cond = al);
1048 void vstr(const DwVfpRegister src,
1049 const MemOperand& dst,
Leon Clarked91b9f72010-01-27 17:25:45 +00001050 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +01001051
Iain Merrick75681382010-08-19 15:07:18 +01001052 void vstr(const SwVfpRegister src,
1053 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001054 int offset,
1055 const Condition cond = al);
1056 void vstr(const SwVfpRegister src,
1057 const MemOperand& dst,
Iain Merrick75681382010-08-19 15:07:18 +01001058 const Condition cond = al);
1059
Ben Murdoch8b112d22011-06-08 16:22:53 +01001060 void vldm(BlockAddrMode am,
1061 Register base,
1062 DwVfpRegister first,
1063 DwVfpRegister last,
1064 Condition cond = al);
1065
1066 void vstm(BlockAddrMode am,
1067 Register base,
1068 DwVfpRegister first,
1069 DwVfpRegister last,
1070 Condition cond = al);
1071
1072 void vldm(BlockAddrMode am,
1073 Register base,
1074 SwVfpRegister first,
1075 SwVfpRegister last,
1076 Condition cond = al);
1077
1078 void vstm(BlockAddrMode am,
1079 Register base,
1080 SwVfpRegister first,
1081 SwVfpRegister last,
1082 Condition cond = al);
1083
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001084 void vmov(const SwVfpRegister dst, float imm);
Steve Block8defd9f2010-07-08 12:39:36 +01001085 void vmov(const DwVfpRegister dst,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001086 double imm,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001087 const Register scratch = no_reg);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001088 void vmov(const SwVfpRegister dst,
1089 const SwVfpRegister src,
1090 const Condition cond = al);
1091 void vmov(const DwVfpRegister dst,
Steve Block8defd9f2010-07-08 12:39:36 +01001092 const DwVfpRegister src,
1093 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001094 void vmov(const DwVfpRegister dst,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001095 const VmovIndex index,
1096 const Register src,
1097 const Condition cond = al);
1098 void vmov(const Register dst,
1099 const VmovIndex index,
1100 const DwVfpRegister src,
1101 const Condition cond = al);
1102 void vmov(const DwVfpRegister dst,
Leon Clarkee46be812010-01-19 14:06:41 +00001103 const Register src1,
Steve Blockd0582a62009-12-15 09:54:21 +00001104 const Register src2,
Leon Clarkee46be812010-01-19 14:06:41 +00001105 const Condition cond = al);
1106 void vmov(const Register dst1,
1107 const Register dst2,
1108 const DwVfpRegister src,
1109 const Condition cond = al);
1110 void vmov(const SwVfpRegister dst,
1111 const Register src,
1112 const Condition cond = al);
1113 void vmov(const Register dst,
1114 const SwVfpRegister src,
1115 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +01001116 void vcvt_f64_s32(const DwVfpRegister dst,
1117 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001118 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001119 const Condition cond = al);
1120 void vcvt_f32_s32(const SwVfpRegister dst,
1121 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001122 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001123 const Condition cond = al);
1124 void vcvt_f64_u32(const DwVfpRegister dst,
1125 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001126 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001127 const Condition cond = al);
1128 void vcvt_s32_f64(const SwVfpRegister dst,
1129 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001130 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001131 const Condition cond = al);
1132 void vcvt_u32_f64(const SwVfpRegister dst,
1133 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001134 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001135 const Condition cond = al);
1136 void vcvt_f64_f32(const DwVfpRegister dst,
1137 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001138 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001139 const Condition cond = al);
1140 void vcvt_f32_f64(const SwVfpRegister dst,
1141 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001142 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001143 const Condition cond = al);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001144 void vcvt_f64_s32(const DwVfpRegister dst,
1145 int fraction_bits,
1146 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001147
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001148 void vmrs(const Register dst, const Condition cond = al);
1149 void vmsr(const Register dst, const Condition cond = al);
1150
Steve Block44f0eee2011-05-26 01:26:41 +01001151 void vneg(const DwVfpRegister dst,
1152 const DwVfpRegister src,
1153 const Condition cond = al);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001154 void vneg(const SwVfpRegister dst, const SwVfpRegister src,
1155 const Condition cond = al);
Steve Block1e0659c2011-05-24 12:43:12 +01001156 void vabs(const DwVfpRegister dst,
1157 const DwVfpRegister src,
1158 const Condition cond = al);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001159 void vabs(const SwVfpRegister dst, const SwVfpRegister src,
1160 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001161 void vadd(const DwVfpRegister dst,
1162 const DwVfpRegister src1,
1163 const DwVfpRegister src2,
1164 const Condition cond = al);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001165 void vadd(const SwVfpRegister dst, const SwVfpRegister src1,
1166 const SwVfpRegister src2, const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001167 void vsub(const DwVfpRegister dst,
1168 const DwVfpRegister src1,
1169 const DwVfpRegister src2,
1170 const Condition cond = al);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001171 void vsub(const SwVfpRegister dst, const SwVfpRegister src1,
1172 const SwVfpRegister src2, const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001173 void vmul(const DwVfpRegister dst,
1174 const DwVfpRegister src1,
1175 const DwVfpRegister src2,
1176 const Condition cond = al);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001177 void vmul(const SwVfpRegister dst, const SwVfpRegister src1,
1178 const SwVfpRegister src2, const Condition cond = al);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001179 void vmla(const DwVfpRegister dst,
1180 const DwVfpRegister src1,
1181 const DwVfpRegister src2,
1182 const Condition cond = al);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001183 void vmla(const SwVfpRegister dst, const SwVfpRegister src1,
1184 const SwVfpRegister src2, const Condition cond = al);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001185 void vmls(const DwVfpRegister dst,
1186 const DwVfpRegister src1,
1187 const DwVfpRegister src2,
1188 const Condition cond = al);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001189 void vmls(const SwVfpRegister dst, const SwVfpRegister src1,
1190 const SwVfpRegister src2, const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001191 void vdiv(const DwVfpRegister dst,
1192 const DwVfpRegister src1,
1193 const DwVfpRegister src2,
1194 const Condition cond = al);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001195 void vdiv(const SwVfpRegister dst, const SwVfpRegister src1,
1196 const SwVfpRegister src2, const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001197 void vcmp(const DwVfpRegister src1,
1198 const DwVfpRegister src2,
Steve Blockd0582a62009-12-15 09:54:21 +00001199 const Condition cond = al);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001200 void vcmp(const SwVfpRegister src1, const SwVfpRegister src2,
1201 const Condition cond = al);
Iain Merrick75681382010-08-19 15:07:18 +01001202 void vcmp(const DwVfpRegister src1,
1203 const double src2,
Iain Merrick75681382010-08-19 15:07:18 +01001204 const Condition cond = al);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001205 void vcmp(const SwVfpRegister src1, const float src2,
Russell Brenner90bac252010-11-18 13:33:46 -08001206 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +01001207 void vsqrt(const DwVfpRegister dst,
1208 const DwVfpRegister src,
1209 const Condition cond = al);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001210 void vsqrt(const SwVfpRegister dst, const SwVfpRegister src,
1211 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001212
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001213 // ARMv8 rounding instructions.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001214 void vrinta(const SwVfpRegister dst, const SwVfpRegister src);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001215 void vrinta(const DwVfpRegister dst, const DwVfpRegister src);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001216 void vrintn(const SwVfpRegister dst, const SwVfpRegister src);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001217 void vrintn(const DwVfpRegister dst, const DwVfpRegister src);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001218 void vrintm(const SwVfpRegister dst, const SwVfpRegister src);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001219 void vrintm(const DwVfpRegister dst, const DwVfpRegister src);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001220 void vrintp(const SwVfpRegister dst, const SwVfpRegister src);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001221 void vrintp(const DwVfpRegister dst, const DwVfpRegister src);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001222 void vrintz(const SwVfpRegister dst, const SwVfpRegister src,
1223 const Condition cond = al);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001224 void vrintz(const DwVfpRegister dst, const DwVfpRegister src,
1225 const Condition cond = al);
1226
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001227 // Support for NEON.
1228 // All these APIs support D0 to D31 and Q0 to Q15.
1229
1230 void vld1(NeonSize size,
1231 const NeonListOperand& dst,
1232 const NeonMemOperand& src);
1233 void vst1(NeonSize size,
1234 const NeonListOperand& src,
1235 const NeonMemOperand& dst);
1236 void vmovl(NeonDataType dt, QwNeonRegister dst, DwVfpRegister src);
1237
Steve Blocka7e24c12009-10-30 11:49:00 +00001238 // Pseudo instructions
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001239
1240 // Different nop operations are used by the code generator to detect certain
1241 // states of the generated code.
1242 enum NopMarkerTypes {
1243 NON_MARKING_NOP = 0,
1244 DEBUG_BREAK_NOP,
1245 // IC markers.
1246 PROPERTY_ACCESS_INLINED,
1247 PROPERTY_ACCESS_INLINED_CONTEXT,
1248 PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE,
1249 // Helper values.
1250 LAST_CODE_MARKER,
1251 FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED
1252 };
1253
1254 void nop(int type = 0); // 0 is the default non-marking type.
Steve Blocka7e24c12009-10-30 11:49:00 +00001255
1256 void push(Register src, Condition cond = al) {
1257 str(src, MemOperand(sp, 4, NegPreIndex), cond);
1258 }
1259
1260 void pop(Register dst, Condition cond = al) {
1261 ldr(dst, MemOperand(sp, 4, PostIndex), cond);
1262 }
1263
1264 void pop() {
1265 add(sp, sp, Operand(kPointerSize));
1266 }
1267
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001268 void vpush(DwVfpRegister src, Condition cond = al) {
1269 vstm(db_w, sp, src, src, cond);
1270 }
1271
1272 void vpop(DwVfpRegister dst, Condition cond = al) {
1273 vldm(ia_w, sp, dst, dst, cond);
1274 }
1275
Steve Blocka7e24c12009-10-30 11:49:00 +00001276 // Jump unconditionally to given label.
1277 void jmp(Label* L) { b(L, al); }
1278
1279 // Check the code size generated from label to here.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001280 int SizeOfCodeGeneratedSince(Label* label) {
1281 return pc_offset() - label->pos();
1282 }
1283
1284 // Check the number of instructions generated from label to here.
1285 int InstructionsGeneratedSince(Label* label) {
1286 return SizeOfCodeGeneratedSince(label) / kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +00001287 }
1288
Steve Blockd0582a62009-12-15 09:54:21 +00001289 // Check whether an immediate fits an addressing mode 1 instruction.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001290 static bool ImmediateFitsAddrMode1Instruction(int32_t imm32);
1291
1292 // Check whether an immediate fits an addressing mode 2 instruction.
1293 bool ImmediateFitsAddrMode2Instruction(int32_t imm32);
Steve Blockd0582a62009-12-15 09:54:21 +00001294
Steve Block6ded16b2010-05-10 14:33:55 +01001295 // Class for scoping postponing the constant pool generation.
1296 class BlockConstPoolScope {
1297 public:
1298 explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) {
1299 assem_->StartBlockConstPool();
1300 }
1301 ~BlockConstPoolScope() {
1302 assem_->EndBlockConstPool();
1303 }
1304
1305 private:
1306 Assembler* assem_;
1307
1308 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstPoolScope);
1309 };
1310
Steve Blocka7e24c12009-10-30 11:49:00 +00001311 // Debugging
1312
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001313 // Mark generator continuation.
1314 void RecordGeneratorContinuation();
Steve Blocka7e24c12009-10-30 11:49:00 +00001315
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001316 // Mark address of a debug break slot.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001317 void RecordDebugBreakSlot(RelocInfo::Mode mode);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001318
Ben Murdoch257744e2011-11-30 15:57:28 +00001319 // Record the AST id of the CallIC being compiled, so that it can be placed
1320 // in the relocation information.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001321 void SetRecordedAstId(TypeFeedbackId ast_id) {
1322 DCHECK(recorded_ast_id_.IsNone());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001323 recorded_ast_id_ = ast_id;
1324 }
1325
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001326 TypeFeedbackId RecordedAstId() {
1327 DCHECK(!recorded_ast_id_.IsNone());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001328 return recorded_ast_id_;
1329 }
1330
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001331 void ClearRecordedAstId() { recorded_ast_id_ = TypeFeedbackId::None(); }
Ben Murdoch257744e2011-11-30 15:57:28 +00001332
Steve Blocka7e24c12009-10-30 11:49:00 +00001333 // Record a comment relocation entry that can be used by a disassembler.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001334 // Use --code-comments to enable.
Steve Blocka7e24c12009-10-30 11:49:00 +00001335 void RecordComment(const char* msg);
1336
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001337 // Record a deoptimization reason that can be used by a log or cpu profiler.
1338 // Use --trace-deopt to enable.
1339 void RecordDeoptReason(const int reason, const SourcePosition position);
1340
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001341 // Record the emission of a constant pool.
1342 //
1343 // The emission of constant pool depends on the size of the code generated and
1344 // the number of RelocInfo recorded.
1345 // The Debug mechanism needs to map code offsets between two versions of a
1346 // function, compiled with and without debugger support (see for example
1347 // Debug::PrepareForBreakPoints()).
1348 // Compiling functions with debugger support generates additional code
1349 // (DebugCodegen::GenerateSlot()). This may affect the emission of the
1350 // constant pools and cause the version of the code with debugger support to
1351 // have constant pools generated in different places.
1352 // Recording the position and size of emitted constant pools allows to
1353 // correctly compute the offset mappings between the different versions of a
1354 // function in all situations.
1355 //
1356 // The parameter indicates the size of the constant pool (in bytes), including
1357 // the marker and branch over the data.
1358 void RecordConstPool(int size);
1359
Ben Murdochb8e0da22011-05-16 14:20:40 +01001360 // Writes a single byte or word of data in the code stream. Used
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001361 // for inline tables, e.g., jump-tables. CheckConstantPool() should be
1362 // called before any use of db/dd/dq/dp to ensure that constant pools
Ben Murdochb8e0da22011-05-16 14:20:40 +01001363 // are not emitted as part of the tables generated.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001364 void db(uint8_t data);
1365 void dd(uint32_t data);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001366 void dq(uint64_t data);
1367 void dp(uintptr_t data) { dd(data); }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001368
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001369 // Emits the address of the code stub's first instruction.
1370 void emit_code_stub_address(Code* stub);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001371
1372 PositionsRecorder* positions_recorder() { return &positions_recorder_; }
Steve Block6ded16b2010-05-10 14:33:55 +01001373
1374 // Read/patch instructions
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001375 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
1376 void instr_at_put(int pos, Instr instr) {
1377 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
1378 }
Steve Block6ded16b2010-05-10 14:33:55 +01001379 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
1380 static void instr_at_put(byte* pc, Instr instr) {
1381 *reinterpret_cast<Instr*>(pc) = instr;
1382 }
Steve Block1e0659c2011-05-24 12:43:12 +01001383 static Condition GetCondition(Instr instr);
Steve Block6ded16b2010-05-10 14:33:55 +01001384 static bool IsBranch(Instr instr);
1385 static int GetBranchOffset(Instr instr);
1386 static bool IsLdrRegisterImmediate(Instr instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001387 static bool IsVldrDRegisterImmediate(Instr instr);
1388 static Instr GetConsantPoolLoadPattern();
1389 static Instr GetConsantPoolLoadMask();
1390 static bool IsLdrPpRegOffset(Instr instr);
1391 static Instr GetLdrPpRegOffsetPattern();
1392 static bool IsLdrPpImmediateOffset(Instr instr);
1393 static bool IsVldrDPpImmediateOffset(Instr instr);
Steve Block6ded16b2010-05-10 14:33:55 +01001394 static int GetLdrRegisterImmediateOffset(Instr instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001395 static int GetVldrDRegisterImmediateOffset(Instr instr);
Steve Block6ded16b2010-05-10 14:33:55 +01001396 static Instr SetLdrRegisterImmediateOffset(Instr instr, int offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001397 static Instr SetVldrDRegisterImmediateOffset(Instr instr, int offset);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001398 static bool IsStrRegisterImmediate(Instr instr);
1399 static Instr SetStrRegisterImmediateOffset(Instr instr, int offset);
1400 static bool IsAddRegisterImmediate(Instr instr);
1401 static Instr SetAddRegisterImmediateOffset(Instr instr, int offset);
Leon Clarkef7060e22010-06-03 12:02:55 +01001402 static Register GetRd(Instr instr);
Steve Block1e0659c2011-05-24 12:43:12 +01001403 static Register GetRn(Instr instr);
1404 static Register GetRm(Instr instr);
Leon Clarkef7060e22010-06-03 12:02:55 +01001405 static bool IsPush(Instr instr);
1406 static bool IsPop(Instr instr);
1407 static bool IsStrRegFpOffset(Instr instr);
1408 static bool IsLdrRegFpOffset(Instr instr);
1409 static bool IsStrRegFpNegOffset(Instr instr);
1410 static bool IsLdrRegFpNegOffset(Instr instr);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001411 static bool IsLdrPcImmediateOffset(Instr instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001412 static bool IsVldrDPcImmediateOffset(Instr instr);
1413 static bool IsBlxReg(Instr instr);
1414 static bool IsBlxIp(Instr instr);
Steve Block1e0659c2011-05-24 12:43:12 +01001415 static bool IsTstImmediate(Instr instr);
1416 static bool IsCmpRegister(Instr instr);
1417 static bool IsCmpImmediate(Instr instr);
1418 static Register GetCmpImmediateRegister(Instr instr);
1419 static int GetCmpImmediateRawImmediate(Instr instr);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001420 static bool IsNop(Instr instr, int type = NON_MARKING_NOP);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001421 static bool IsMovImmed(Instr instr);
1422 static bool IsOrrImmed(Instr instr);
1423 static bool IsMovT(Instr instr);
1424 static Instr GetMovTPattern();
1425 static bool IsMovW(Instr instr);
1426 static Instr GetMovWPattern();
1427 static Instr EncodeMovwImmediate(uint32_t immediate);
1428 static Instr PatchMovwImmediate(Instr instruction, uint32_t immediate);
1429 static int DecodeShiftImm(Instr instr);
1430 static Instr PatchShiftImm(Instr instr, int immed);
Steve Block6ded16b2010-05-10 14:33:55 +01001431
Ben Murdoch257744e2011-11-30 15:57:28 +00001432 // Constants in pools are accessed via pc relative addressing, which can
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001433 // reach +/-4KB for integer PC-relative loads and +/-1KB for floating-point
1434 // PC-relative loads, thereby defining a maximum distance between the
1435 // instruction and the accessed constant.
1436 static const int kMaxDistToIntPool = 4*KB;
1437 static const int kMaxDistToFPPool = 1*KB;
1438 // All relocations could be integer, it therefore acts as the limit.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001439 static const int kMinNumPendingConstants = 4;
1440 static const int kMaxNumPending32Constants = kMaxDistToIntPool / kInstrSize;
1441 static const int kMaxNumPending64Constants = kMaxDistToFPPool / kInstrSize;
Ben Murdoch257744e2011-11-30 15:57:28 +00001442
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001443 // Postpone the generation of the constant pool for the specified number of
1444 // instructions.
1445 void BlockConstPoolFor(int instructions);
1446
1447 // Check if is time to emit a constant pool.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001448 void CheckConstPool(bool force_emit, bool require_jump);
Steve Blocka7e24c12009-10-30 11:49:00 +00001449
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001450 void MaybeCheckConstPool() {
1451 if (pc_offset() >= next_buffer_check_) {
1452 CheckConstPool(false, true);
1453 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001454 }
1455
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001456 int EmitEmbeddedConstantPool() {
1457 DCHECK(FLAG_enable_embedded_constant_pool);
1458 return constant_pool_builder_.Emit(this);
1459 }
1460
1461 bool ConstantPoolAccessIsInOverflow() const {
1462 return constant_pool_builder_.NextAccess(ConstantPoolEntry::INTPTR) ==
1463 ConstantPoolEntry::OVERFLOWED;
1464 }
1465
1466 void PatchConstantPoolAccessInstruction(int pc_offset, int offset,
1467 ConstantPoolEntry::Access access,
1468 ConstantPoolEntry::Type type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001469
Steve Blocka7e24c12009-10-30 11:49:00 +00001470 protected:
Ben Murdoch257744e2011-11-30 15:57:28 +00001471 // Relocation for a type-recording IC has the AST id added to it. This
1472 // member variable is a way to pass the information from the call site to
1473 // the relocation info.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001474 TypeFeedbackId recorded_ast_id_;
Steve Block44f0eee2011-05-26 01:26:41 +01001475
Steve Blocka7e24c12009-10-30 11:49:00 +00001476 int buffer_space() const { return reloc_info_writer.pos() - pc_; }
1477
Steve Blocka7e24c12009-10-30 11:49:00 +00001478 // Decode branch instruction at pos and return branch target pos
1479 int target_at(int pos);
1480
1481 // Patch branch instruction at pos to branch to given branch target pos
1482 void target_at_put(int pos, int target_pos);
1483
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001484 // Prevent contant pool emission until EndBlockConstPool is called.
1485 // Call to this function can be nested but must be followed by an equal
1486 // number of call to EndBlockConstpool.
1487 void StartBlockConstPool() {
1488 if (const_pool_blocked_nesting_++ == 0) {
1489 // Prevent constant pool checks happening by setting the next check to
1490 // the biggest possible offset.
1491 next_buffer_check_ = kMaxInt;
1492 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001493 }
1494
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001495 // Resume constant pool emission. Need to be called as many time as
1496 // StartBlockConstPool to have an effect.
Steve Block6ded16b2010-05-10 14:33:55 +01001497 void EndBlockConstPool() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001498 if (--const_pool_blocked_nesting_ == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001499#ifdef DEBUG
1500 // Max pool start (if we need a jump and an alignment).
1501 int start = pc_offset() + kInstrSize + 2 * kPointerSize;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001502 // Check the constant pool hasn't been blocked for too long.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001503 DCHECK((num_pending_32_bit_constants_ == 0) ||
1504 (start + num_pending_64_bit_constants_ * kDoubleSize <
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001505 (first_const_pool_32_use_ + kMaxDistToIntPool)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001506 DCHECK((num_pending_64_bit_constants_ == 0) ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001507 (start < (first_const_pool_64_use_ + kMaxDistToFPPool)));
1508#endif
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001509 // Two cases:
1510 // * no_const_pool_before_ >= next_buffer_check_ and the emission is
1511 // still blocked
1512 // * no_const_pool_before_ < next_buffer_check_ and the next emit will
1513 // trigger a check.
1514 next_buffer_check_ = no_const_pool_before_;
1515 }
Steve Block6ded16b2010-05-10 14:33:55 +01001516 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001517
1518 bool is_const_pool_blocked() const {
1519 return (const_pool_blocked_nesting_ > 0) ||
1520 (pc_offset() < no_const_pool_before_);
1521 }
Steve Block6ded16b2010-05-10 14:33:55 +01001522
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001523 private:
Steve Blocka7e24c12009-10-30 11:49:00 +00001524 int next_buffer_check_; // pc offset of next buffer check
1525
1526 // Code generation
1527 // The relocation writer's position is at least kGap bytes below the end of
1528 // the generated instructions. This is so that multi-instruction sequences do
1529 // not have to check for overflow. The same is true for writes of large
1530 // relocation info entries.
1531 static const int kGap = 32;
Steve Blocka7e24c12009-10-30 11:49:00 +00001532
1533 // Constant pool generation
1534 // Pools are emitted in the instruction stream, preferably after unconditional
1535 // jumps or after returns from functions (in dead code locations).
1536 // If a long code sequence does not contain unconditional jumps, it is
1537 // necessary to emit the constant pool before the pool gets too far from the
1538 // location it is accessed from. In this case, we emit a jump over the emitted
1539 // constant pool.
1540 // Constants in the pool may be addresses of functions that gets relocated;
1541 // if so, a relocation info entry is associated to the constant pool entry.
1542
1543 // Repeated checking whether the constant pool should be emitted is rather
1544 // expensive. By default we only check again once a number of instructions
1545 // has been generated. That also means that the sizing of the buffers is not
1546 // an exact science, and that we rely on some slop to not overrun buffers.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001547 static const int kCheckPoolIntervalInst = 32;
1548 static const int kCheckPoolInterval = kCheckPoolIntervalInst * kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +00001549
1550
Steve Block6ded16b2010-05-10 14:33:55 +01001551 // Emission of the constant pool may be blocked in some code sequences.
1552 int const_pool_blocked_nesting_; // Block emission if this is not zero.
1553 int no_const_pool_before_; // Block emission before this pc offset.
Steve Blocka7e24c12009-10-30 11:49:00 +00001554
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001555 // Keep track of the first instruction requiring a constant pool entry
1556 // since the previous constant pool was emitted.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001557 int first_const_pool_32_use_;
1558 int first_const_pool_64_use_;
Steve Blocka7e24c12009-10-30 11:49:00 +00001559
1560 // Relocation info generation
1561 // Each relocation is encoded as a variable size value
1562 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1563 RelocInfoWriter reloc_info_writer;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001564
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001565 // ConstantPoolEntry records are used during code generation as temporary
Steve Blocka7e24c12009-10-30 11:49:00 +00001566 // containers for constants and code target addresses until they are emitted
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001567 // to the constant pool. These records are temporarily stored in a separate
1568 // buffer until a constant pool is emitted.
Steve Blocka7e24c12009-10-30 11:49:00 +00001569 // If every instruction in a long sequence is accessing the pool, we need one
1570 // pending relocation entry per instruction.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001571
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001572 // The buffers of pending constant pool entries.
1573 ConstantPoolEntry pending_32_bit_constants_buffer_[kMinNumPendingConstants];
1574 ConstantPoolEntry pending_64_bit_constants_buffer_[kMinNumPendingConstants];
1575 ConstantPoolEntry* pending_32_bit_constants_;
1576 ConstantPoolEntry* pending_64_bit_constants_;
1577 // Number of pending constant pool entries in the 32 bits buffer.
1578 int num_pending_32_bit_constants_;
1579 // Number of pending constant pool entries in the 64 bits buffer.
1580 int num_pending_64_bit_constants_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001581
1582 ConstantPoolBuilder constant_pool_builder_;
Steve Blocka7e24c12009-10-30 11:49:00 +00001583
1584 // The bound position, before this we cannot do instruction elimination.
1585 int last_bound_pos_;
1586
Steve Blocka7e24c12009-10-30 11:49:00 +00001587 // Code emission
1588 inline void CheckBuffer();
1589 void GrowBuffer();
1590 inline void emit(Instr x);
1591
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001592 // 32-bit immediate values
1593 void move_32_bit_immediate(Register rd,
1594 const Operand& x,
1595 Condition cond = al);
1596
Steve Blocka7e24c12009-10-30 11:49:00 +00001597 // Instruction generation
1598 void addrmod1(Instr instr, Register rn, Register rd, const Operand& x);
1599 void addrmod2(Instr instr, Register rd, const MemOperand& x);
1600 void addrmod3(Instr instr, Register rd, const MemOperand& x);
1601 void addrmod4(Instr instr, Register rn, RegList rl);
1602 void addrmod5(Instr instr, CRegister crd, const MemOperand& x);
1603
1604 // Labels
1605 void print(Label* L);
1606 void bind_to(Label* L, int pos);
Steve Blocka7e24c12009-10-30 11:49:00 +00001607 void next(Label* L);
1608
1609 // Record reloc info for current pc_
1610 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001611 ConstantPoolEntry::Access ConstantPoolAddEntry(int position,
1612 RelocInfo::Mode rmode,
1613 intptr_t value);
1614 ConstantPoolEntry::Access ConstantPoolAddEntry(int position, double value);
Steve Blocka7e24c12009-10-30 11:49:00 +00001615
Steve Blocka7e24c12009-10-30 11:49:00 +00001616 friend class RelocInfo;
1617 friend class CodePatcher;
Steve Block6ded16b2010-05-10 14:33:55 +01001618 friend class BlockConstPoolScope;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001619 PositionsRecorder positions_recorder_;
1620 friend class PositionsRecorder;
1621 friend class EnsureSpace;
Steve Blocka7e24c12009-10-30 11:49:00 +00001622};
1623
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001624
1625class EnsureSpace BASE_EMBEDDED {
1626 public:
1627 explicit EnsureSpace(Assembler* assembler) {
1628 assembler->CheckBuffer();
1629 }
1630};
1631
1632
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001633} // namespace internal
1634} // namespace v8
Steve Blocka7e24c12009-10-30 11:49:00 +00001635
1636#endif // V8_ARM_ASSEMBLER_ARM_H_