blob: 4a719e6aafb2518bc3326ffd722bde5a887e06dd [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"
48#include "src/serialize.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000049
50namespace v8 {
51namespace internal {
52
53// CPU Registers.
54//
55// 1) We would prefer to use an enum, but enum values are assignment-
56// compatible with int, which has caused code-generation bugs.
57//
58// 2) We would prefer to use a class instead of a struct but we don't like
59// the register initialization to depend on the particular initialization
60// order (which appears to be different on OS X, Linux, and Windows for the
61// installed versions of C++ we tried). Using a struct permits C-style
62// "initialization". Also, the Register objects cannot be const as this
63// forces initialization stubs in MSVC, making us dependent on initialization
64// order.
65//
66// 3) By not using an enum, we are possibly preventing the compiler from
67// doing certain constant folds, which may significantly reduce the
68// code generated for some assembly instructions (because they boil down
69// to a few constants). If this is a problem, we could change the code
70// such that we use an enum in optimized mode, and the struct in debug
71// mode. This way we get the compile-time error checking in debug mode
72// and best performance in optimized code.
Steve Block9fac8402011-05-12 15:51:54 +010073
Ben Murdoch3ef787d2012-04-12 10:51:47 +010074// These constants are used in several locations, including static initializers
75const int kRegister_no_reg_Code = -1;
76const int kRegister_r0_Code = 0;
77const int kRegister_r1_Code = 1;
78const int kRegister_r2_Code = 2;
79const int kRegister_r3_Code = 3;
80const int kRegister_r4_Code = 4;
81const int kRegister_r5_Code = 5;
82const int kRegister_r6_Code = 6;
83const int kRegister_r7_Code = 7;
84const int kRegister_r8_Code = 8;
85const int kRegister_r9_Code = 9;
86const int kRegister_r10_Code = 10;
87const int kRegister_fp_Code = 11;
88const int kRegister_ip_Code = 12;
89const int kRegister_sp_Code = 13;
90const int kRegister_lr_Code = 14;
91const int kRegister_pc_Code = 15;
Steve Blocka7e24c12009-10-30 11:49:00 +000092
Ben Murdochb8a8cc12014-11-26 15:28:44 +000093// Core register
94struct Register {
95 static const int kNumRegisters = 16;
96 static const int kMaxNumAllocatableRegisters =
97 FLAG_enable_ool_constant_pool ? 8 : 9;
98 static const int kSizeInBytes = 4;
99
100 inline static int NumAllocatableRegisters();
101
102 static int ToAllocationIndex(Register reg) {
103 DCHECK(reg.code() < kMaxNumAllocatableRegisters);
104 return reg.code();
105 }
106
107 static Register FromAllocationIndex(int index) {
108 DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
109 return from_code(index);
110 }
111
112 static const char* AllocationIndexToString(int index) {
113 DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
114 const char* const names[] = {
115 "r0",
116 "r1",
117 "r2",
118 "r3",
119 "r4",
120 "r5",
121 "r6",
122 "r7",
123 "r8",
124 };
125 if (FLAG_enable_ool_constant_pool && (index >= 7)) {
126 return names[index + 1];
127 }
128 return names[index];
129 }
130
131 static Register from_code(int code) {
132 Register r = { code };
133 return r;
134 }
135
136 bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; }
137 bool is(Register reg) const { return code_ == reg.code_; }
138 int code() const {
139 DCHECK(is_valid());
140 return code_;
141 }
142 int bit() const {
143 DCHECK(is_valid());
144 return 1 << code_;
145 }
146
147 void set_code(int code) {
148 code_ = code;
149 DCHECK(is_valid());
150 }
151
152 // Unfortunately we can't make this private in a struct.
153 int code_;
154};
155
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100156const Register no_reg = { kRegister_no_reg_Code };
157
158const Register r0 = { kRegister_r0_Code };
159const Register r1 = { kRegister_r1_Code };
160const Register r2 = { kRegister_r2_Code };
161const Register r3 = { kRegister_r3_Code };
162const Register r4 = { kRegister_r4_Code };
163const Register r5 = { kRegister_r5_Code };
164const Register r6 = { kRegister_r6_Code };
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000165// Used as constant pool pointer register if FLAG_enable_ool_constant_pool.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100166const Register r7 = { kRegister_r7_Code };
167// Used as context register.
168const Register r8 = { kRegister_r8_Code };
169// Used as lithium codegen scratch register.
170const Register r9 = { kRegister_r9_Code };
171// Used as roots register.
172const Register r10 = { kRegister_r10_Code };
173const Register fp = { kRegister_fp_Code };
174const Register ip = { kRegister_ip_Code };
175const Register sp = { kRegister_sp_Code };
176const Register lr = { kRegister_lr_Code };
177const Register pc = { kRegister_pc_Code };
178
Leon Clarkee46be812010-01-19 14:06:41 +0000179// Single word VFP register.
180struct SwVfpRegister {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000181 static const int kSizeInBytes = 4;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100182 bool is_valid() const { return 0 <= code_ && code_ < 32; }
183 bool is(SwVfpRegister reg) const { return code_ == reg.code_; }
184 int code() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000185 DCHECK(is_valid());
Leon Clarkee46be812010-01-19 14:06:41 +0000186 return code_;
187 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100188 int bit() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000189 DCHECK(is_valid());
Leon Clarkee46be812010-01-19 14:06:41 +0000190 return 1 << code_;
191 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100192 void split_code(int* vm, int* m) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000193 DCHECK(is_valid());
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100194 *m = code_ & 0x1;
195 *vm = code_ >> 1;
196 }
Leon Clarkee46be812010-01-19 14:06:41 +0000197
198 int code_;
199};
200
201
202// Double word VFP register.
203struct DwVfpRegister {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000204 static const int kMaxNumRegisters = 32;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000205 // A few double registers are reserved: one as a scratch register and one to
206 // hold 0.0, that does not fit in the immediate field of vmov instructions.
207 // d14: 0.0
208 // d15: scratch register.
209 static const int kNumReservedRegisters = 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000210 static const int kMaxNumAllocatableRegisters = kMaxNumRegisters -
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000211 kNumReservedRegisters;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000212 static const int kSizeInBytes = 8;
213
214 // Note: the number of registers can be different at snapshot and run-time.
215 // Any code included in the snapshot must be able to run both with 16 or 32
216 // registers.
217 inline static int NumRegisters();
218 inline static int NumReservedRegisters();
219 inline static int NumAllocatableRegisters();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100220
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400221 // TODO(turbofan): This is a temporary work-around required because our
222 // register allocator does not yet support the aliasing of single/double
223 // registers on ARM.
224 inline static int NumAllocatableAliasedRegisters();
225
Ben Murdoch692be652012-01-10 18:47:50 +0000226 inline static int ToAllocationIndex(DwVfpRegister reg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000227 static const char* AllocationIndexToString(int index);
228 inline static DwVfpRegister FromAllocationIndex(int index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100229
230 static DwVfpRegister from_code(int code) {
231 DwVfpRegister r = { code };
232 return r;
233 }
234
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000235 bool is_valid() const {
236 return 0 <= code_ && code_ < kMaxNumRegisters;
237 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100238 bool is(DwVfpRegister reg) const { return code_ == reg.code_; }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100239 int code() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000240 DCHECK(is_valid());
Leon Clarkee46be812010-01-19 14:06:41 +0000241 return code_;
242 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100243 int bit() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000244 DCHECK(is_valid());
Leon Clarkee46be812010-01-19 14:06:41 +0000245 return 1 << code_;
246 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100247 void split_code(int* vm, int* m) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000248 DCHECK(is_valid());
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100249 *m = (code_ & 0x10) >> 4;
250 *vm = code_ & 0x0F;
251 }
Leon Clarkee46be812010-01-19 14:06:41 +0000252
253 int code_;
254};
255
256
Ben Murdochb0fe1622011-05-05 13:52:32 +0100257typedef DwVfpRegister DoubleRegister;
258
259
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000260// Double word VFP register d0-15.
261struct LowDwVfpRegister {
262 public:
263 static const int kMaxNumLowRegisters = 16;
264 operator DwVfpRegister() const {
265 DwVfpRegister r = { code_ };
266 return r;
267 }
268 static LowDwVfpRegister from_code(int code) {
269 LowDwVfpRegister r = { code };
270 return r;
271 }
272
273 bool is_valid() const {
274 return 0 <= code_ && code_ < kMaxNumLowRegisters;
275 }
276 bool is(DwVfpRegister reg) const { return code_ == reg.code_; }
277 bool is(LowDwVfpRegister reg) const { return code_ == reg.code_; }
278 int code() const {
279 DCHECK(is_valid());
280 return code_;
281 }
282 SwVfpRegister low() const {
283 SwVfpRegister reg;
284 reg.code_ = code_ * 2;
285
286 DCHECK(reg.is_valid());
287 return reg;
288 }
289 SwVfpRegister high() const {
290 SwVfpRegister reg;
291 reg.code_ = (code_ * 2) + 1;
292
293 DCHECK(reg.is_valid());
294 return reg;
295 }
296
297 int code_;
298};
299
300
301// Quad word NEON register.
302struct QwNeonRegister {
303 static const int kMaxNumRegisters = 16;
304
305 static QwNeonRegister from_code(int code) {
306 QwNeonRegister r = { code };
307 return r;
308 }
309
310 bool is_valid() const {
311 return (0 <= code_) && (code_ < kMaxNumRegisters);
312 }
313 bool is(QwNeonRegister reg) const { return code_ == reg.code_; }
314 int code() const {
315 DCHECK(is_valid());
316 return code_;
317 }
318 void split_code(int* vm, int* m) const {
319 DCHECK(is_valid());
320 int encoded_code = code_ << 1;
321 *m = (encoded_code & 0x10) >> 4;
322 *vm = encoded_code & 0x0F;
323 }
324
325 int code_;
326};
327
328
329typedef QwNeonRegister QuadRegister;
330
331
Steve Block6ded16b2010-05-10 14:33:55 +0100332// Support for the VFP registers s0 to s31 (d0 to d15).
Leon Clarkee46be812010-01-19 14:06:41 +0000333// Note that "s(N):s(N+1)" is the same as "d(N/2)".
Steve Block6ded16b2010-05-10 14:33:55 +0100334const SwVfpRegister s0 = { 0 };
335const SwVfpRegister s1 = { 1 };
336const SwVfpRegister s2 = { 2 };
337const SwVfpRegister s3 = { 3 };
338const SwVfpRegister s4 = { 4 };
339const SwVfpRegister s5 = { 5 };
340const SwVfpRegister s6 = { 6 };
341const SwVfpRegister s7 = { 7 };
342const SwVfpRegister s8 = { 8 };
343const SwVfpRegister s9 = { 9 };
344const SwVfpRegister s10 = { 10 };
345const SwVfpRegister s11 = { 11 };
346const SwVfpRegister s12 = { 12 };
347const SwVfpRegister s13 = { 13 };
348const SwVfpRegister s14 = { 14 };
349const SwVfpRegister s15 = { 15 };
350const SwVfpRegister s16 = { 16 };
351const SwVfpRegister s17 = { 17 };
352const SwVfpRegister s18 = { 18 };
353const SwVfpRegister s19 = { 19 };
354const SwVfpRegister s20 = { 20 };
355const SwVfpRegister s21 = { 21 };
356const SwVfpRegister s22 = { 22 };
357const SwVfpRegister s23 = { 23 };
358const SwVfpRegister s24 = { 24 };
359const SwVfpRegister s25 = { 25 };
360const SwVfpRegister s26 = { 26 };
361const SwVfpRegister s27 = { 27 };
362const SwVfpRegister s28 = { 28 };
363const SwVfpRegister s29 = { 29 };
364const SwVfpRegister s30 = { 30 };
365const SwVfpRegister s31 = { 31 };
Leon Clarkee46be812010-01-19 14:06:41 +0000366
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100367const DwVfpRegister no_dreg = { -1 };
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000368const LowDwVfpRegister d0 = { 0 };
369const LowDwVfpRegister d1 = { 1 };
370const LowDwVfpRegister d2 = { 2 };
371const LowDwVfpRegister d3 = { 3 };
372const LowDwVfpRegister d4 = { 4 };
373const LowDwVfpRegister d5 = { 5 };
374const LowDwVfpRegister d6 = { 6 };
375const LowDwVfpRegister d7 = { 7 };
376const LowDwVfpRegister d8 = { 8 };
377const LowDwVfpRegister d9 = { 9 };
378const LowDwVfpRegister d10 = { 10 };
379const LowDwVfpRegister d11 = { 11 };
380const LowDwVfpRegister d12 = { 12 };
381const LowDwVfpRegister d13 = { 13 };
382const LowDwVfpRegister d14 = { 14 };
383const LowDwVfpRegister d15 = { 15 };
384const DwVfpRegister d16 = { 16 };
385const DwVfpRegister d17 = { 17 };
386const DwVfpRegister d18 = { 18 };
387const DwVfpRegister d19 = { 19 };
388const DwVfpRegister d20 = { 20 };
389const DwVfpRegister d21 = { 21 };
390const DwVfpRegister d22 = { 22 };
391const DwVfpRegister d23 = { 23 };
392const DwVfpRegister d24 = { 24 };
393const DwVfpRegister d25 = { 25 };
394const DwVfpRegister d26 = { 26 };
395const DwVfpRegister d27 = { 27 };
396const DwVfpRegister d28 = { 28 };
397const DwVfpRegister d29 = { 29 };
398const DwVfpRegister d30 = { 30 };
399const DwVfpRegister d31 = { 31 };
400
401const QwNeonRegister q0 = { 0 };
402const QwNeonRegister q1 = { 1 };
403const QwNeonRegister q2 = { 2 };
404const QwNeonRegister q3 = { 3 };
405const QwNeonRegister q4 = { 4 };
406const QwNeonRegister q5 = { 5 };
407const QwNeonRegister q6 = { 6 };
408const QwNeonRegister q7 = { 7 };
409const QwNeonRegister q8 = { 8 };
410const QwNeonRegister q9 = { 9 };
411const QwNeonRegister q10 = { 10 };
412const QwNeonRegister q11 = { 11 };
413const QwNeonRegister q12 = { 12 };
414const QwNeonRegister q13 = { 13 };
415const QwNeonRegister q14 = { 14 };
416const QwNeonRegister q15 = { 15 };
417
Leon Clarkee46be812010-01-19 14:06:41 +0000418
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100419// Aliases for double registers. Defined using #define instead of
420// "static const DwVfpRegister&" because Clang complains otherwise when a
421// compilation unit that includes this header doesn't use the variables.
422#define kFirstCalleeSavedDoubleReg d8
423#define kLastCalleeSavedDoubleReg d15
424#define kDoubleRegZero d14
425#define kScratchDoubleReg d15
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +0100426
Steve Blocka7e24c12009-10-30 11:49:00 +0000427
428// Coprocessor register
429struct CRegister {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100430 bool is_valid() const { return 0 <= code_ && code_ < 16; }
431 bool is(CRegister creg) const { return code_ == creg.code_; }
432 int code() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000433 DCHECK(is_valid());
Steve Blocka7e24c12009-10-30 11:49:00 +0000434 return code_;
435 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100436 int bit() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000437 DCHECK(is_valid());
Steve Blocka7e24c12009-10-30 11:49:00 +0000438 return 1 << code_;
439 }
440
Andrei Popescu31002712010-02-23 13:46:05 +0000441 // Unfortunately we can't make this private in a struct.
Steve Blocka7e24c12009-10-30 11:49:00 +0000442 int code_;
443};
444
445
Steve Block6ded16b2010-05-10 14:33:55 +0100446const CRegister no_creg = { -1 };
447
448const CRegister cr0 = { 0 };
449const CRegister cr1 = { 1 };
450const CRegister cr2 = { 2 };
451const CRegister cr3 = { 3 };
452const CRegister cr4 = { 4 };
453const CRegister cr5 = { 5 };
454const CRegister cr6 = { 6 };
455const CRegister cr7 = { 7 };
456const CRegister cr8 = { 8 };
457const CRegister cr9 = { 9 };
458const CRegister cr10 = { 10 };
459const CRegister cr11 = { 11 };
460const CRegister cr12 = { 12 };
461const CRegister cr13 = { 13 };
462const CRegister cr14 = { 14 };
463const CRegister cr15 = { 15 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000464
465
466// Coprocessor number
467enum Coprocessor {
468 p0 = 0,
469 p1 = 1,
470 p2 = 2,
471 p3 = 3,
472 p4 = 4,
473 p5 = 5,
474 p6 = 6,
475 p7 = 7,
476 p8 = 8,
477 p9 = 9,
478 p10 = 10,
479 p11 = 11,
480 p12 = 12,
481 p13 = 13,
482 p14 = 14,
483 p15 = 15
484};
485
486
Steve Blocka7e24c12009-10-30 11:49:00 +0000487// -----------------------------------------------------------------------------
488// Machine instruction Operands
489
490// Class Operand represents a shifter operand in data processing instructions
491class Operand BASE_EMBEDDED {
492 public:
493 // immediate
494 INLINE(explicit Operand(int32_t immediate,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000495 RelocInfo::Mode rmode = RelocInfo::NONE32));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000496 INLINE(static Operand Zero()) {
497 return Operand(static_cast<int32_t>(0));
498 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000499 INLINE(explicit Operand(const ExternalReference& f));
Steve Blocka7e24c12009-10-30 11:49:00 +0000500 explicit Operand(Handle<Object> handle);
501 INLINE(explicit Operand(Smi* value));
502
503 // rm
504 INLINE(explicit Operand(Register rm));
505
506 // rm <shift_op> shift_imm
507 explicit Operand(Register rm, ShiftOp shift_op, int shift_imm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000508 INLINE(static Operand SmiUntag(Register rm)) {
509 return Operand(rm, ASR, kSmiTagSize);
510 }
511 INLINE(static Operand PointerOffsetFromSmiKey(Register key)) {
512 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
513 return Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize);
514 }
515 INLINE(static Operand DoubleOffsetFromSmiKey(Register key)) {
516 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kDoubleSizeLog2);
517 return Operand(key, LSL, kDoubleSizeLog2 - kSmiTagSize);
518 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000519
520 // rm <shift_op> rs
521 explicit Operand(Register rm, ShiftOp shift_op, Register rs);
522
523 // Return true if this is a register operand.
524 INLINE(bool is_reg() const);
525
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000526 // Return the number of actual instructions required to implement the given
527 // instruction for this particular operand. This can be a single instruction,
528 // if no load into the ip register is necessary, or anything between 2 and 4
529 // instructions when we need to load from the constant pool (depending upon
530 // whether the constant pool entry is in the small or extended section). If
Steve Block44f0eee2011-05-26 01:26:41 +0100531 // the instruction this operand is used for is a MOV or MVN instruction the
532 // actual instruction to use is required for this calculation. For other
533 // instructions instr is ignored.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000534 //
535 // The value returned is only valid as long as no entries are added to the
536 // constant pool between this call and the actual instruction being emitted.
537 int instructions_required(const Assembler* assembler, Instr instr = 0) const;
538 bool must_output_reloc_info(const Assembler* assembler) const;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100539
540 inline int32_t immediate() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000541 DCHECK(!rm_.is_valid());
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100542 return imm32_;
543 }
544
Steve Blocka7e24c12009-10-30 11:49:00 +0000545 Register rm() const { return rm_; }
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100546 Register rs() const { return rs_; }
547 ShiftOp shift_op() const { return shift_op_; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000548
549 private:
550 Register rm_;
551 Register rs_;
552 ShiftOp shift_op_;
553 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
554 int32_t imm32_; // valid if rm_ == no_reg
555 RelocInfo::Mode rmode_;
556
557 friend class Assembler;
558};
559
560
561// Class MemOperand represents a memory operand in load and store instructions
562class MemOperand BASE_EMBEDDED {
563 public:
564 // [rn +/- offset] Offset/NegOffset
565 // [rn +/- offset]! PreIndex/NegPreIndex
566 // [rn], +/- offset PostIndex/NegPostIndex
567 // offset is any signed 32-bit value; offset is first loaded to register ip if
568 // it does not fit the addressing mode (12-bit unsigned and sign bit)
569 explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset);
570
571 // [rn +/- rm] Offset/NegOffset
572 // [rn +/- rm]! PreIndex/NegPreIndex
573 // [rn], +/- rm PostIndex/NegPostIndex
574 explicit MemOperand(Register rn, Register rm, AddrMode am = Offset);
575
576 // [rn +/- rm <shift_op> shift_imm] Offset/NegOffset
577 // [rn +/- rm <shift_op> shift_imm]! PreIndex/NegPreIndex
578 // [rn], +/- rm <shift_op> shift_imm PostIndex/NegPostIndex
579 explicit MemOperand(Register rn, Register rm,
580 ShiftOp shift_op, int shift_imm, AddrMode am = Offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000581 INLINE(static MemOperand PointerAddressFromSmiKey(Register array,
582 Register key,
583 AddrMode am = Offset)) {
584 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
585 return MemOperand(array, key, LSL, kPointerSizeLog2 - kSmiTagSize, am);
586 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000587
Kristian Monsen25f61362010-05-21 11:50:48 +0100588 void set_offset(int32_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000589 DCHECK(rm_.is(no_reg));
Kristian Monsen25f61362010-05-21 11:50:48 +0100590 offset_ = offset;
591 }
592
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100593 uint32_t offset() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000594 DCHECK(rm_.is(no_reg));
Kristian Monsen25f61362010-05-21 11:50:48 +0100595 return offset_;
596 }
597
Leon Clarkef7060e22010-06-03 12:02:55 +0100598 Register rn() const { return rn_; }
599 Register rm() const { return rm_; }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000600 AddrMode am() const { return am_; }
Kristian Monsen25f61362010-05-21 11:50:48 +0100601
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100602 bool OffsetIsUint12Encodable() const {
603 return offset_ >= 0 ? is_uint12(offset_) : is_uint12(-offset_);
604 }
605
Steve Blocka7e24c12009-10-30 11:49:00 +0000606 private:
607 Register rn_; // base
608 Register rm_; // register offset
609 int32_t offset_; // valid if rm_ == no_reg
610 ShiftOp shift_op_;
611 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
612 AddrMode am_; // bits P, U, and W
613
614 friend class Assembler;
615};
616
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000617
618// Class NeonMemOperand represents a memory operand in load and
619// store NEON instructions
620class NeonMemOperand BASE_EMBEDDED {
Steve Blockd0582a62009-12-15 09:54:21 +0000621 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000622 // [rn {:align}] Offset
623 // [rn {:align}]! PostIndex
624 explicit NeonMemOperand(Register rn, AddrMode am = Offset, int align = 0);
Steve Blockd0582a62009-12-15 09:54:21 +0000625
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000626 // [rn {:align}], rm PostIndex
627 explicit NeonMemOperand(Register rn, Register rm, int align = 0);
Steve Blockd0582a62009-12-15 09:54:21 +0000628
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000629 Register rn() const { return rn_; }
630 Register rm() const { return rm_; }
631 int align() const { return align_; }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100632
Steve Blockd0582a62009-12-15 09:54:21 +0000633 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000634 void SetAlignment(int align);
Steve Block44f0eee2011-05-26 01:26:41 +0100635
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000636 Register rn_; // base
637 Register rm_; // register increment
638 int align_;
Steve Blockd0582a62009-12-15 09:54:21 +0000639};
640
Steve Blocka7e24c12009-10-30 11:49:00 +0000641
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000642// Class NeonListOperand represents a list of NEON registers
643class NeonListOperand BASE_EMBEDDED {
644 public:
645 explicit NeonListOperand(DoubleRegister base, int registers_count = 1);
646 DoubleRegister base() const { return base_; }
647 NeonListType type() const { return type_; }
648 private:
649 DoubleRegister base_;
650 NeonListType type_;
651};
Steve Blocka7e24c12009-10-30 11:49:00 +0000652
Steve Block1e0659c2011-05-24 12:43:12 +0100653
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000654// Class used to build a constant pool.
655class ConstantPoolBuilder BASE_EMBEDDED {
656 public:
657 ConstantPoolBuilder();
658 ConstantPoolArray::LayoutSection AddEntry(Assembler* assm,
659 const RelocInfo& rinfo);
660 void Relocate(int pc_delta);
661 bool IsEmpty();
662 Handle<ConstantPoolArray> New(Isolate* isolate);
663 void Populate(Assembler* assm, ConstantPoolArray* constant_pool);
664
665 inline ConstantPoolArray::LayoutSection current_section() const {
666 return current_section_;
667 }
668
669 inline ConstantPoolArray::NumberOfEntries* number_of_entries(
670 ConstantPoolArray::LayoutSection section) {
671 return &number_of_entries_[section];
672 }
673
674 inline ConstantPoolArray::NumberOfEntries* small_entries() {
675 return number_of_entries(ConstantPoolArray::SMALL_SECTION);
676 }
677
678 inline ConstantPoolArray::NumberOfEntries* extended_entries() {
679 return number_of_entries(ConstantPoolArray::EXTENDED_SECTION);
680 }
681
682 private:
683 struct ConstantPoolEntry {
684 ConstantPoolEntry(RelocInfo rinfo, ConstantPoolArray::LayoutSection section,
685 int merged_index)
686 : rinfo_(rinfo), section_(section), merged_index_(merged_index) {}
687
688 RelocInfo rinfo_;
689 ConstantPoolArray::LayoutSection section_;
690 int merged_index_;
691 };
692
693 ConstantPoolArray::Type GetConstantPoolType(RelocInfo::Mode rmode);
694
695 std::vector<ConstantPoolEntry> entries_;
696 ConstantPoolArray::LayoutSection current_section_;
697 ConstantPoolArray::NumberOfEntries number_of_entries_[2];
698};
699
700struct VmovIndex {
701 unsigned char index;
702};
703const VmovIndex VmovIndexLo = { 0 };
704const VmovIndex VmovIndexHi = { 1 };
Steve Block1e0659c2011-05-24 12:43:12 +0100705
Steve Block44f0eee2011-05-26 01:26:41 +0100706class Assembler : public AssemblerBase {
Steve Blocka7e24c12009-10-30 11:49:00 +0000707 public:
708 // Create an assembler. Instructions and relocation information are emitted
709 // into a buffer, with the instructions starting from the beginning and the
710 // relocation information starting from the end of the buffer. See CodeDesc
711 // for a detailed comment on the layout (globals.h).
712 //
713 // If the provided buffer is NULL, the assembler allocates and grows its own
714 // buffer, and buffer_size determines the initial buffer size. The buffer is
715 // owned by the assembler and deallocated upon destruction of the assembler.
716 //
717 // If the provided buffer is not NULL, the assembler uses the provided buffer
718 // for code generation and assumes its size to be buffer_size. If the buffer
719 // is too small, a fatal error occurs. No deallocation of the buffer is done
720 // upon destruction of the assembler.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100721 Assembler(Isolate* isolate, void* buffer, int buffer_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000722 virtual ~Assembler();
Steve Block44f0eee2011-05-26 01:26:41 +0100723
Steve Blocka7e24c12009-10-30 11:49:00 +0000724 // GetCode emits any pending (non-emitted) code and fills the descriptor
725 // desc. GetCode() is idempotent; it returns the same result if no other
726 // Assembler functions are invoked in between GetCode() calls.
727 void GetCode(CodeDesc* desc);
728
729 // Label operations & relative jumps (PPUM Appendix D)
730 //
731 // Takes a branch opcode (cc) and a label (L) and generates
732 // either a backward branch or a forward branch and links it
733 // to the label fixup chain. Usage:
734 //
735 // Label L; // unbound label
736 // j(cc, &L); // forward branch to unbound label
737 // bind(&L); // bind label to the current pc
738 // j(cc, &L); // backward branch to bound label
739 // bind(&L); // illegal: a label may be bound only once
740 //
741 // Note: The same Label can be used for forward and backward branches
742 // but it may be bound only once.
743
744 void bind(Label* L); // binds an unbound label L to the current code position
745
746 // Returns the branch offset to the given label from the current code position
747 // Links the label to the current position if it is still unbound
748 // Manages the jump elimination optimization if the second parameter is true.
749 int branch_offset(Label* L, bool jump_elimination_allowed);
750
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000751 // Returns true if the given pc address is the start of a constant pool load
752 // instruction sequence.
753 INLINE(static bool is_constant_pool_load(Address pc));
Steve Blocka7e24c12009-10-30 11:49:00 +0000754
755 // Return the address in the constant pool of the code target address used by
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000756 // the branch/call instruction at pc, or the object in a mov.
757 INLINE(static Address constant_pool_entry_address(
758 Address pc, ConstantPoolArray* constant_pool));
Steve Blocka7e24c12009-10-30 11:49:00 +0000759
760 // Read/Modify the code target address in the branch/call instruction at pc.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000761 INLINE(static Address target_address_at(Address pc,
762 ConstantPoolArray* constant_pool));
763 INLINE(static void set_target_address_at(Address pc,
764 ConstantPoolArray* constant_pool,
765 Address target,
766 ICacheFlushMode icache_flush_mode =
767 FLUSH_ICACHE_IF_NEEDED));
768 INLINE(static Address target_address_at(Address pc, Code* code)) {
769 ConstantPoolArray* constant_pool = code ? code->constant_pool() : NULL;
770 return target_address_at(pc, constant_pool);
771 }
772 INLINE(static void set_target_address_at(Address pc,
773 Code* code,
774 Address target,
775 ICacheFlushMode icache_flush_mode =
776 FLUSH_ICACHE_IF_NEEDED)) {
777 ConstantPoolArray* constant_pool = code ? code->constant_pool() : NULL;
778 set_target_address_at(pc, constant_pool, target, icache_flush_mode);
779 }
780
781 // Return the code target address at a call site from the return address
782 // of that call in the instruction stream.
783 INLINE(static Address target_address_from_return_address(Address pc));
784
785 // Given the address of the beginning of a call, return the address
786 // in the instruction stream that the call will return from.
787 INLINE(static Address return_address_from_call_start(Address pc));
788
789 // Return the code target address of the patch debug break slot
790 INLINE(static Address break_address_from_return_address(Address pc));
Steve Blocka7e24c12009-10-30 11:49:00 +0000791
Steve Blockd0582a62009-12-15 09:54:21 +0000792 // This sets the branch destination (which is in the constant pool on ARM).
793 // This is for calls and branches within generated code.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100794 inline static void deserialization_set_special_target_at(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000795 Address constant_pool_entry, Code* code, Address target);
Steve Blockd0582a62009-12-15 09:54:21 +0000796
797 // Here we are patching the address in the constant pool, not the actual call
798 // instruction. The address in the constant pool is the same size as a
799 // pointer.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100800 static const int kSpecialTargetSize = kPointerSize;
Steve Blockd0582a62009-12-15 09:54:21 +0000801
Steve Blocka7e24c12009-10-30 11:49:00 +0000802 // Size of an instruction.
803 static const int kInstrSize = sizeof(Instr);
804
Steve Blocka7e24c12009-10-30 11:49:00 +0000805 // Distance between start of patched return sequence and the emitted address
806 // to jump to.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100807 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100808 // ldr ip, [pc, #0] @ emited address and start
809 // blx ip
810 static const int kPatchReturnSequenceAddressOffset = 0 * kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +0000811
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100812 // Distance between start of patched debug break slot and the emitted address
813 // to jump to.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100814 // Patched debug break slot code is:
815 // ldr ip, [pc, #0] @ emited address and start
816 // blx ip
817 static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000818
819 static const int kPatchDebugBreakSlotReturnOffset = 2 * kInstrSize;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100820
Steve Blocka7e24c12009-10-30 11:49:00 +0000821 // Difference between address of current opcode and value read from pc
822 // register.
823 static const int kPcLoadDelta = 8;
824
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100825 static const int kJSReturnSequenceInstructions = 4;
826 static const int kDebugBreakSlotInstructions = 3;
827 static const int kDebugBreakSlotLength =
828 kDebugBreakSlotInstructions * kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +0000829
830 // ---------------------------------------------------------------------------
831 // Code generation
832
833 // Insert the smallest number of nop instructions
834 // possible to align the pc offset to a multiple
835 // of m. m must be a power of 2 (>= 4).
836 void Align(int m);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100837 // Aligns code to something that's optimal for a jump target for the platform.
838 void CodeTargetAlign();
Steve Blocka7e24c12009-10-30 11:49:00 +0000839
840 // Branch instructions
841 void b(int branch_offset, Condition cond = al);
842 void bl(int branch_offset, Condition cond = al);
843 void blx(int branch_offset); // v5 and above
844 void blx(Register target, Condition cond = al); // v5 and above
845 void bx(Register target, Condition cond = al); // v5 and above, plus v4t
846
847 // Convenience branch instructions using labels
848 void b(Label* L, Condition cond = al) {
849 b(branch_offset(L, cond == al), cond);
850 }
851 void b(Condition cond, Label* L) { b(branch_offset(L, cond == al), cond); }
852 void bl(Label* L, Condition cond = al) { bl(branch_offset(L, false), cond); }
853 void bl(Condition cond, Label* L) { bl(branch_offset(L, false), cond); }
854 void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above
855
856 // Data-processing instructions
Andrei Popescu31002712010-02-23 13:46:05 +0000857
Steve Blocka7e24c12009-10-30 11:49:00 +0000858 void and_(Register dst, Register src1, const Operand& src2,
859 SBit s = LeaveCC, Condition cond = al);
860
861 void eor(Register dst, Register src1, const Operand& src2,
862 SBit s = LeaveCC, Condition cond = al);
863
864 void sub(Register dst, Register src1, const Operand& src2,
865 SBit s = LeaveCC, Condition cond = al);
866 void sub(Register dst, Register src1, Register src2,
867 SBit s = LeaveCC, Condition cond = al) {
868 sub(dst, src1, Operand(src2), s, cond);
869 }
870
871 void rsb(Register dst, Register src1, const Operand& src2,
872 SBit s = LeaveCC, Condition cond = al);
873
874 void add(Register dst, Register src1, const Operand& src2,
875 SBit s = LeaveCC, Condition cond = al);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100876 void add(Register dst, Register src1, Register src2,
877 SBit s = LeaveCC, Condition cond = al) {
878 add(dst, src1, Operand(src2), s, cond);
879 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000880
881 void adc(Register dst, Register src1, const Operand& src2,
882 SBit s = LeaveCC, Condition cond = al);
883
884 void sbc(Register dst, Register src1, const Operand& src2,
885 SBit s = LeaveCC, Condition cond = al);
886
887 void rsc(Register dst, Register src1, const Operand& src2,
888 SBit s = LeaveCC, Condition cond = al);
889
890 void tst(Register src1, const Operand& src2, Condition cond = al);
891 void tst(Register src1, Register src2, Condition cond = al) {
892 tst(src1, Operand(src2), cond);
893 }
894
895 void teq(Register src1, const Operand& src2, Condition cond = al);
896
897 void cmp(Register src1, const Operand& src2, Condition cond = al);
898 void cmp(Register src1, Register src2, Condition cond = al) {
899 cmp(src1, Operand(src2), cond);
900 }
Steve Block1e0659c2011-05-24 12:43:12 +0100901 void cmp_raw_immediate(Register src1, int raw_immediate, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000902
903 void cmn(Register src1, const Operand& src2, Condition cond = al);
904
905 void orr(Register dst, Register src1, const Operand& src2,
906 SBit s = LeaveCC, Condition cond = al);
907 void orr(Register dst, Register src1, Register src2,
908 SBit s = LeaveCC, Condition cond = al) {
909 orr(dst, src1, Operand(src2), s, cond);
910 }
911
912 void mov(Register dst, const Operand& src,
913 SBit s = LeaveCC, Condition cond = al);
914 void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
915 mov(dst, Operand(src), s, cond);
916 }
917
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000918 // Load the position of the label relative to the generated code object
919 // pointer in a register.
920 void mov_label_offset(Register dst, Label* label);
921
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100922 // ARMv7 instructions for loading a 32 bit immediate in two instructions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000923 // The constant for movw and movt should be in the range 0-0xffff.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100924 void movw(Register reg, uint32_t immediate, Condition cond = al);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100925 void movt(Register reg, uint32_t immediate, Condition cond = al);
926
Steve Blocka7e24c12009-10-30 11:49:00 +0000927 void bic(Register dst, Register src1, const Operand& src2,
928 SBit s = LeaveCC, Condition cond = al);
929
930 void mvn(Register dst, const Operand& src,
931 SBit s = LeaveCC, Condition cond = al);
932
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000933 // Shift instructions
934
935 void asr(Register dst, Register src1, const Operand& src2, SBit s = LeaveCC,
936 Condition cond = al) {
937 if (src2.is_reg()) {
938 mov(dst, Operand(src1, ASR, src2.rm()), s, cond);
939 } else {
940 mov(dst, Operand(src1, ASR, src2.immediate()), s, cond);
941 }
942 }
943
944 void lsl(Register dst, Register src1, const Operand& src2, SBit s = LeaveCC,
945 Condition cond = al) {
946 if (src2.is_reg()) {
947 mov(dst, Operand(src1, LSL, src2.rm()), s, cond);
948 } else {
949 mov(dst, Operand(src1, LSL, src2.immediate()), s, cond);
950 }
951 }
952
953 void lsr(Register dst, Register src1, const Operand& src2, SBit s = LeaveCC,
954 Condition cond = al) {
955 if (src2.is_reg()) {
956 mov(dst, Operand(src1, LSR, src2.rm()), s, cond);
957 } else {
958 mov(dst, Operand(src1, LSR, src2.immediate()), s, cond);
959 }
960 }
961
Steve Blocka7e24c12009-10-30 11:49:00 +0000962 // Multiply instructions
963
964 void mla(Register dst, Register src1, Register src2, Register srcA,
965 SBit s = LeaveCC, Condition cond = al);
966
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000967 void mls(Register dst, Register src1, Register src2, Register srcA,
968 Condition cond = al);
969
970 void sdiv(Register dst, Register src1, Register src2,
971 Condition cond = al);
972
973 void udiv(Register dst, Register src1, Register src2, Condition cond = al);
974
Steve Blocka7e24c12009-10-30 11:49:00 +0000975 void mul(Register dst, Register src1, Register src2,
976 SBit s = LeaveCC, Condition cond = al);
977
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400978 void smmla(Register dst, Register src1, Register src2, Register srcA,
979 Condition cond = al);
980
981 void smmul(Register dst, Register src1, Register src2, Condition cond = al);
982
Steve Blocka7e24c12009-10-30 11:49:00 +0000983 void smlal(Register dstL, Register dstH, Register src1, Register src2,
984 SBit s = LeaveCC, Condition cond = al);
985
986 void smull(Register dstL, Register dstH, Register src1, Register src2,
987 SBit s = LeaveCC, Condition cond = al);
988
989 void umlal(Register dstL, Register dstH, Register src1, Register src2,
990 SBit s = LeaveCC, Condition cond = al);
991
992 void umull(Register dstL, Register dstH, Register src1, Register src2,
993 SBit s = LeaveCC, Condition cond = al);
994
995 // Miscellaneous arithmetic instructions
996
997 void clz(Register dst, Register src, Condition cond = al); // v5 and above
998
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100999 // Saturating instructions. v6 and above.
1000
1001 // Unsigned saturate.
1002 //
1003 // Saturate an optionally shifted signed value to an unsigned range.
1004 //
1005 // usat dst, #satpos, src
1006 // usat dst, #satpos, src, lsl #sh
1007 // usat dst, #satpos, src, asr #sh
1008 //
1009 // Register dst will contain:
1010 //
1011 // 0, if s < 0
1012 // (1 << satpos) - 1, if s > ((1 << satpos) - 1)
1013 // s, otherwise
1014 //
1015 // where s is the contents of src after shifting (if used.)
1016 void usat(Register dst, int satpos, const Operand& src, Condition cond = al);
1017
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001018 // Bitfield manipulation instructions. v7 and above.
1019
1020 void ubfx(Register dst, Register src, int lsb, int width,
1021 Condition cond = al);
1022
1023 void sbfx(Register dst, Register src, int lsb, int width,
1024 Condition cond = al);
1025
1026 void bfc(Register dst, int lsb, int width, Condition cond = al);
1027
1028 void bfi(Register dst, Register src, int lsb, int width,
1029 Condition cond = al);
1030
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001031 void pkhbt(Register dst, Register src1, const Operand& src2,
1032 Condition cond = al);
1033
1034 void pkhtb(Register dst, Register src1, const Operand& src2,
1035 Condition cond = al);
1036
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001037 void sxtb(Register dst, Register src, int rotate = 0, Condition cond = al);
1038 void sxtab(Register dst, Register src1, Register src2, int rotate = 0,
1039 Condition cond = al);
1040 void sxth(Register dst, Register src, int rotate = 0, Condition cond = al);
1041 void sxtah(Register dst, Register src1, Register src2, int rotate = 0,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001042 Condition cond = al);
1043
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001044 void uxtb(Register dst, Register src, int rotate = 0, Condition cond = al);
1045 void uxtab(Register dst, Register src1, Register src2, int rotate = 0,
1046 Condition cond = al);
1047 void uxtb16(Register dst, Register src, int rotate = 0, Condition cond = al);
1048 void uxth(Register dst, Register src, int rotate = 0, Condition cond = al);
1049 void uxtah(Register dst, Register src1, Register src2, int rotate = 0,
1050 Condition cond = al);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001051
Steve Blocka7e24c12009-10-30 11:49:00 +00001052 // Status register access instructions
1053
1054 void mrs(Register dst, SRegister s, Condition cond = al);
1055 void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al);
1056
1057 // Load/Store instructions
1058 void ldr(Register dst, const MemOperand& src, Condition cond = al);
1059 void str(Register src, const MemOperand& dst, Condition cond = al);
1060 void ldrb(Register dst, const MemOperand& src, Condition cond = al);
1061 void strb(Register src, const MemOperand& dst, Condition cond = al);
1062 void ldrh(Register dst, const MemOperand& src, Condition cond = al);
1063 void strh(Register src, const MemOperand& dst, Condition cond = al);
1064 void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
1065 void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
Leon Clarkef7060e22010-06-03 12:02:55 +01001066 void ldrd(Register dst1,
1067 Register dst2,
1068 const MemOperand& src, Condition cond = al);
1069 void strd(Register src1,
1070 Register src2,
1071 const MemOperand& dst, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +00001072
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001073 // Preload instructions
1074 void pld(const MemOperand& address);
1075
Steve Blocka7e24c12009-10-30 11:49:00 +00001076 // Load/Store multiple instructions
1077 void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
1078 void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
1079
Steve Blocka7e24c12009-10-30 11:49:00 +00001080 // Exception-generating instructions and debugging support
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001081 void stop(const char* msg,
1082 Condition cond = al,
1083 int32_t code = kDefaultStopCode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001084
1085 void bkpt(uint32_t imm16); // v5 and above
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001086 void svc(uint32_t imm24, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +00001087
1088 // Coprocessor instructions
1089
1090 void cdp(Coprocessor coproc, int opcode_1,
1091 CRegister crd, CRegister crn, CRegister crm,
1092 int opcode_2, Condition cond = al);
1093
1094 void cdp2(Coprocessor coproc, int opcode_1,
1095 CRegister crd, CRegister crn, CRegister crm,
1096 int opcode_2); // v5 and above
1097
1098 void mcr(Coprocessor coproc, int opcode_1,
1099 Register rd, CRegister crn, CRegister crm,
1100 int opcode_2 = 0, Condition cond = al);
1101
1102 void mcr2(Coprocessor coproc, int opcode_1,
1103 Register rd, CRegister crn, CRegister crm,
1104 int opcode_2 = 0); // v5 and above
1105
1106 void mrc(Coprocessor coproc, int opcode_1,
1107 Register rd, CRegister crn, CRegister crm,
1108 int opcode_2 = 0, Condition cond = al);
1109
1110 void mrc2(Coprocessor coproc, int opcode_1,
1111 Register rd, CRegister crn, CRegister crm,
1112 int opcode_2 = 0); // v5 and above
1113
1114 void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src,
1115 LFlag l = Short, Condition cond = al);
1116 void ldc(Coprocessor coproc, CRegister crd, Register base, int option,
1117 LFlag l = Short, Condition cond = al);
1118
1119 void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
1120 LFlag l = Short); // v5 and above
1121 void ldc2(Coprocessor coproc, CRegister crd, Register base, int option,
1122 LFlag l = Short); // v5 and above
1123
Steve Blockd0582a62009-12-15 09:54:21 +00001124 // Support for VFP.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001125 // All these APIs support S0 to S31 and D0 to D31.
Steve Blockd0582a62009-12-15 09:54:21 +00001126
Leon Clarked91b9f72010-01-27 17:25:45 +00001127 void vldr(const DwVfpRegister dst,
1128 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001129 int offset,
1130 const Condition cond = al);
1131 void vldr(const DwVfpRegister dst,
1132 const MemOperand& src,
Leon Clarked91b9f72010-01-27 17:25:45 +00001133 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +01001134
1135 void vldr(const SwVfpRegister dst,
1136 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001137 int offset,
1138 const Condition cond = al);
1139 void vldr(const SwVfpRegister dst,
1140 const MemOperand& src,
Steve Block6ded16b2010-05-10 14:33:55 +01001141 const Condition cond = al);
1142
Leon Clarked91b9f72010-01-27 17:25:45 +00001143 void vstr(const DwVfpRegister src,
1144 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001145 int offset,
1146 const Condition cond = al);
1147 void vstr(const DwVfpRegister src,
1148 const MemOperand& dst,
Leon Clarked91b9f72010-01-27 17:25:45 +00001149 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +01001150
Iain Merrick75681382010-08-19 15:07:18 +01001151 void vstr(const SwVfpRegister src,
1152 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001153 int offset,
1154 const Condition cond = al);
1155 void vstr(const SwVfpRegister src,
1156 const MemOperand& dst,
Iain Merrick75681382010-08-19 15:07:18 +01001157 const Condition cond = al);
1158
Ben Murdoch8b112d22011-06-08 16:22:53 +01001159 void vldm(BlockAddrMode am,
1160 Register base,
1161 DwVfpRegister first,
1162 DwVfpRegister last,
1163 Condition cond = al);
1164
1165 void vstm(BlockAddrMode am,
1166 Register base,
1167 DwVfpRegister first,
1168 DwVfpRegister last,
1169 Condition cond = al);
1170
1171 void vldm(BlockAddrMode am,
1172 Register base,
1173 SwVfpRegister first,
1174 SwVfpRegister last,
1175 Condition cond = al);
1176
1177 void vstm(BlockAddrMode am,
1178 Register base,
1179 SwVfpRegister first,
1180 SwVfpRegister last,
1181 Condition cond = al);
1182
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001183 void vmov(const SwVfpRegister dst, float imm);
Steve Block8defd9f2010-07-08 12:39:36 +01001184 void vmov(const DwVfpRegister dst,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001185 double imm,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001186 const Register scratch = no_reg);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001187 void vmov(const SwVfpRegister dst,
1188 const SwVfpRegister src,
1189 const Condition cond = al);
1190 void vmov(const DwVfpRegister dst,
Steve Block8defd9f2010-07-08 12:39:36 +01001191 const DwVfpRegister src,
1192 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001193 void vmov(const DwVfpRegister dst,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001194 const VmovIndex index,
1195 const Register src,
1196 const Condition cond = al);
1197 void vmov(const Register dst,
1198 const VmovIndex index,
1199 const DwVfpRegister src,
1200 const Condition cond = al);
1201 void vmov(const DwVfpRegister dst,
Leon Clarkee46be812010-01-19 14:06:41 +00001202 const Register src1,
Steve Blockd0582a62009-12-15 09:54:21 +00001203 const Register src2,
Leon Clarkee46be812010-01-19 14:06:41 +00001204 const Condition cond = al);
1205 void vmov(const Register dst1,
1206 const Register dst2,
1207 const DwVfpRegister src,
1208 const Condition cond = al);
1209 void vmov(const SwVfpRegister dst,
1210 const Register src,
1211 const Condition cond = al);
1212 void vmov(const Register dst,
1213 const SwVfpRegister src,
1214 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +01001215 void vcvt_f64_s32(const DwVfpRegister dst,
1216 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001217 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001218 const Condition cond = al);
1219 void vcvt_f32_s32(const SwVfpRegister dst,
1220 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001221 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001222 const Condition cond = al);
1223 void vcvt_f64_u32(const DwVfpRegister dst,
1224 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001225 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001226 const Condition cond = al);
1227 void vcvt_s32_f64(const SwVfpRegister dst,
1228 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001229 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001230 const Condition cond = al);
1231 void vcvt_u32_f64(const SwVfpRegister dst,
1232 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001233 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001234 const Condition cond = al);
1235 void vcvt_f64_f32(const DwVfpRegister dst,
1236 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001237 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001238 const Condition cond = al);
1239 void vcvt_f32_f64(const SwVfpRegister dst,
1240 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001241 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001242 const Condition cond = al);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001243 void vcvt_f64_s32(const DwVfpRegister dst,
1244 int fraction_bits,
1245 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001246
Steve Block44f0eee2011-05-26 01:26:41 +01001247 void vneg(const DwVfpRegister dst,
1248 const DwVfpRegister src,
1249 const Condition cond = al);
Steve Block1e0659c2011-05-24 12:43:12 +01001250 void vabs(const DwVfpRegister dst,
1251 const DwVfpRegister src,
1252 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001253 void vadd(const DwVfpRegister dst,
1254 const DwVfpRegister src1,
1255 const DwVfpRegister src2,
1256 const Condition cond = al);
1257 void vsub(const DwVfpRegister dst,
1258 const DwVfpRegister src1,
1259 const DwVfpRegister src2,
1260 const Condition cond = al);
1261 void vmul(const DwVfpRegister dst,
1262 const DwVfpRegister src1,
1263 const DwVfpRegister src2,
1264 const Condition cond = al);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001265 void vmla(const DwVfpRegister dst,
1266 const DwVfpRegister src1,
1267 const DwVfpRegister src2,
1268 const Condition cond = al);
1269 void vmls(const DwVfpRegister dst,
1270 const DwVfpRegister src1,
1271 const DwVfpRegister src2,
1272 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001273 void vdiv(const DwVfpRegister dst,
1274 const DwVfpRegister src1,
1275 const DwVfpRegister src2,
1276 const Condition cond = al);
1277 void vcmp(const DwVfpRegister src1,
1278 const DwVfpRegister src2,
Steve Blockd0582a62009-12-15 09:54:21 +00001279 const Condition cond = al);
Iain Merrick75681382010-08-19 15:07:18 +01001280 void vcmp(const DwVfpRegister src1,
1281 const double src2,
Iain Merrick75681382010-08-19 15:07:18 +01001282 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001283 void vmrs(const Register dst,
1284 const Condition cond = al);
Russell Brenner90bac252010-11-18 13:33:46 -08001285 void vmsr(const Register dst,
1286 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +01001287 void vsqrt(const DwVfpRegister dst,
1288 const DwVfpRegister src,
1289 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001290
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001291 // ARMv8 rounding instructions.
1292 void vrinta(const DwVfpRegister dst, const DwVfpRegister src);
1293 void vrintn(const DwVfpRegister dst, const DwVfpRegister src);
1294 void vrintm(const DwVfpRegister dst, const DwVfpRegister src);
1295 void vrintp(const DwVfpRegister dst, const DwVfpRegister src);
1296 void vrintz(const DwVfpRegister dst, const DwVfpRegister src,
1297 const Condition cond = al);
1298
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001299 // Support for NEON.
1300 // All these APIs support D0 to D31 and Q0 to Q15.
1301
1302 void vld1(NeonSize size,
1303 const NeonListOperand& dst,
1304 const NeonMemOperand& src);
1305 void vst1(NeonSize size,
1306 const NeonListOperand& src,
1307 const NeonMemOperand& dst);
1308 void vmovl(NeonDataType dt, QwNeonRegister dst, DwVfpRegister src);
1309
Steve Blocka7e24c12009-10-30 11:49:00 +00001310 // Pseudo instructions
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001311
1312 // Different nop operations are used by the code generator to detect certain
1313 // states of the generated code.
1314 enum NopMarkerTypes {
1315 NON_MARKING_NOP = 0,
1316 DEBUG_BREAK_NOP,
1317 // IC markers.
1318 PROPERTY_ACCESS_INLINED,
1319 PROPERTY_ACCESS_INLINED_CONTEXT,
1320 PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE,
1321 // Helper values.
1322 LAST_CODE_MARKER,
1323 FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED
1324 };
1325
1326 void nop(int type = 0); // 0 is the default non-marking type.
Steve Blocka7e24c12009-10-30 11:49:00 +00001327
1328 void push(Register src, Condition cond = al) {
1329 str(src, MemOperand(sp, 4, NegPreIndex), cond);
1330 }
1331
1332 void pop(Register dst, Condition cond = al) {
1333 ldr(dst, MemOperand(sp, 4, PostIndex), cond);
1334 }
1335
1336 void pop() {
1337 add(sp, sp, Operand(kPointerSize));
1338 }
1339
Steve Blocka7e24c12009-10-30 11:49:00 +00001340 // Jump unconditionally to given label.
1341 void jmp(Label* L) { b(L, al); }
1342
1343 // Check the code size generated from label to here.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001344 int SizeOfCodeGeneratedSince(Label* label) {
1345 return pc_offset() - label->pos();
1346 }
1347
1348 // Check the number of instructions generated from label to here.
1349 int InstructionsGeneratedSince(Label* label) {
1350 return SizeOfCodeGeneratedSince(label) / kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +00001351 }
1352
Steve Blockd0582a62009-12-15 09:54:21 +00001353 // Check whether an immediate fits an addressing mode 1 instruction.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001354 static bool ImmediateFitsAddrMode1Instruction(int32_t imm32);
1355
1356 // Check whether an immediate fits an addressing mode 2 instruction.
1357 bool ImmediateFitsAddrMode2Instruction(int32_t imm32);
Steve Blockd0582a62009-12-15 09:54:21 +00001358
Steve Block6ded16b2010-05-10 14:33:55 +01001359 // Class for scoping postponing the constant pool generation.
1360 class BlockConstPoolScope {
1361 public:
1362 explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) {
1363 assem_->StartBlockConstPool();
1364 }
1365 ~BlockConstPoolScope() {
1366 assem_->EndBlockConstPool();
1367 }
1368
1369 private:
1370 Assembler* assem_;
1371
1372 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstPoolScope);
1373 };
1374
Steve Blocka7e24c12009-10-30 11:49:00 +00001375 // Debugging
1376
1377 // Mark address of the ExitJSFrame code.
1378 void RecordJSReturn();
1379
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001380 // Mark address of a debug break slot.
1381 void RecordDebugBreakSlot();
1382
Ben Murdoch257744e2011-11-30 15:57:28 +00001383 // Record the AST id of the CallIC being compiled, so that it can be placed
1384 // in the relocation information.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001385 void SetRecordedAstId(TypeFeedbackId ast_id) {
1386 DCHECK(recorded_ast_id_.IsNone());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001387 recorded_ast_id_ = ast_id;
1388 }
1389
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001390 TypeFeedbackId RecordedAstId() {
1391 DCHECK(!recorded_ast_id_.IsNone());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001392 return recorded_ast_id_;
1393 }
1394
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001395 void ClearRecordedAstId() { recorded_ast_id_ = TypeFeedbackId::None(); }
Ben Murdoch257744e2011-11-30 15:57:28 +00001396
Steve Blocka7e24c12009-10-30 11:49:00 +00001397 // Record a comment relocation entry that can be used by a disassembler.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001398 // Use --code-comments to enable.
Steve Blocka7e24c12009-10-30 11:49:00 +00001399 void RecordComment(const char* msg);
1400
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001401 // Record the emission of a constant pool.
1402 //
1403 // The emission of constant pool depends on the size of the code generated and
1404 // the number of RelocInfo recorded.
1405 // The Debug mechanism needs to map code offsets between two versions of a
1406 // function, compiled with and without debugger support (see for example
1407 // Debug::PrepareForBreakPoints()).
1408 // Compiling functions with debugger support generates additional code
1409 // (DebugCodegen::GenerateSlot()). This may affect the emission of the
1410 // constant pools and cause the version of the code with debugger support to
1411 // have constant pools generated in different places.
1412 // Recording the position and size of emitted constant pools allows to
1413 // correctly compute the offset mappings between the different versions of a
1414 // function in all situations.
1415 //
1416 // The parameter indicates the size of the constant pool (in bytes), including
1417 // the marker and branch over the data.
1418 void RecordConstPool(int size);
1419
Ben Murdochb8e0da22011-05-16 14:20:40 +01001420 // Writes a single byte or word of data in the code stream. Used
1421 // for inline tables, e.g., jump-tables. The constant pool should be
1422 // emitted before any use of db and dd to ensure that constant pools
1423 // are not emitted as part of the tables generated.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001424 void db(uint8_t data);
1425 void dd(uint32_t data);
1426
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001427 // Emits the address of the code stub's first instruction.
1428 void emit_code_stub_address(Code* stub);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001429
1430 PositionsRecorder* positions_recorder() { return &positions_recorder_; }
Steve Block6ded16b2010-05-10 14:33:55 +01001431
1432 // Read/patch instructions
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001433 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
1434 void instr_at_put(int pos, Instr instr) {
1435 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
1436 }
Steve Block6ded16b2010-05-10 14:33:55 +01001437 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
1438 static void instr_at_put(byte* pc, Instr instr) {
1439 *reinterpret_cast<Instr*>(pc) = instr;
1440 }
Steve Block1e0659c2011-05-24 12:43:12 +01001441 static Condition GetCondition(Instr instr);
Steve Block6ded16b2010-05-10 14:33:55 +01001442 static bool IsBranch(Instr instr);
1443 static int GetBranchOffset(Instr instr);
1444 static bool IsLdrRegisterImmediate(Instr instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001445 static bool IsVldrDRegisterImmediate(Instr instr);
1446 static Instr GetConsantPoolLoadPattern();
1447 static Instr GetConsantPoolLoadMask();
1448 static bool IsLdrPpRegOffset(Instr instr);
1449 static Instr GetLdrPpRegOffsetPattern();
1450 static bool IsLdrPpImmediateOffset(Instr instr);
1451 static bool IsVldrDPpImmediateOffset(Instr instr);
Steve Block6ded16b2010-05-10 14:33:55 +01001452 static int GetLdrRegisterImmediateOffset(Instr instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001453 static int GetVldrDRegisterImmediateOffset(Instr instr);
Steve Block6ded16b2010-05-10 14:33:55 +01001454 static Instr SetLdrRegisterImmediateOffset(Instr instr, int offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001455 static Instr SetVldrDRegisterImmediateOffset(Instr instr, int offset);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001456 static bool IsStrRegisterImmediate(Instr instr);
1457 static Instr SetStrRegisterImmediateOffset(Instr instr, int offset);
1458 static bool IsAddRegisterImmediate(Instr instr);
1459 static Instr SetAddRegisterImmediateOffset(Instr instr, int offset);
Leon Clarkef7060e22010-06-03 12:02:55 +01001460 static Register GetRd(Instr instr);
Steve Block1e0659c2011-05-24 12:43:12 +01001461 static Register GetRn(Instr instr);
1462 static Register GetRm(Instr instr);
Leon Clarkef7060e22010-06-03 12:02:55 +01001463 static bool IsPush(Instr instr);
1464 static bool IsPop(Instr instr);
1465 static bool IsStrRegFpOffset(Instr instr);
1466 static bool IsLdrRegFpOffset(Instr instr);
1467 static bool IsStrRegFpNegOffset(Instr instr);
1468 static bool IsLdrRegFpNegOffset(Instr instr);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001469 static bool IsLdrPcImmediateOffset(Instr instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001470 static bool IsVldrDPcImmediateOffset(Instr instr);
1471 static bool IsBlxReg(Instr instr);
1472 static bool IsBlxIp(Instr instr);
Steve Block1e0659c2011-05-24 12:43:12 +01001473 static bool IsTstImmediate(Instr instr);
1474 static bool IsCmpRegister(Instr instr);
1475 static bool IsCmpImmediate(Instr instr);
1476 static Register GetCmpImmediateRegister(Instr instr);
1477 static int GetCmpImmediateRawImmediate(Instr instr);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001478 static bool IsNop(Instr instr, int type = NON_MARKING_NOP);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001479 static bool IsMovImmed(Instr instr);
1480 static bool IsOrrImmed(Instr instr);
1481 static bool IsMovT(Instr instr);
1482 static Instr GetMovTPattern();
1483 static bool IsMovW(Instr instr);
1484 static Instr GetMovWPattern();
1485 static Instr EncodeMovwImmediate(uint32_t immediate);
1486 static Instr PatchMovwImmediate(Instr instruction, uint32_t immediate);
1487 static int DecodeShiftImm(Instr instr);
1488 static Instr PatchShiftImm(Instr instr, int immed);
Steve Block6ded16b2010-05-10 14:33:55 +01001489
Ben Murdoch257744e2011-11-30 15:57:28 +00001490 // Constants in pools are accessed via pc relative addressing, which can
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001491 // reach +/-4KB for integer PC-relative loads and +/-1KB for floating-point
1492 // PC-relative loads, thereby defining a maximum distance between the
1493 // instruction and the accessed constant.
1494 static const int kMaxDistToIntPool = 4*KB;
1495 static const int kMaxDistToFPPool = 1*KB;
1496 // All relocations could be integer, it therefore acts as the limit.
1497 static const int kMaxNumPending32RelocInfo = kMaxDistToIntPool/kInstrSize;
1498 static const int kMaxNumPending64RelocInfo = kMaxDistToFPPool/kInstrSize;
Ben Murdoch257744e2011-11-30 15:57:28 +00001499
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001500 // Postpone the generation of the constant pool for the specified number of
1501 // instructions.
1502 void BlockConstPoolFor(int instructions);
1503
1504 // Check if is time to emit a constant pool.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001505 void CheckConstPool(bool force_emit, bool require_jump);
Steve Blocka7e24c12009-10-30 11:49:00 +00001506
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001507 // Allocate a constant pool of the correct size for the generated code.
1508 Handle<ConstantPoolArray> NewConstantPool(Isolate* isolate);
1509
1510 // Generate the constant pool for the generated code.
1511 void PopulateConstantPool(ConstantPoolArray* constant_pool);
1512
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001513 bool use_extended_constant_pool() const {
1514 return constant_pool_builder_.current_section() ==
1515 ConstantPoolArray::EXTENDED_SECTION;
1516 }
1517
1518
Steve Blocka7e24c12009-10-30 11:49:00 +00001519 protected:
Ben Murdoch257744e2011-11-30 15:57:28 +00001520 // Relocation for a type-recording IC has the AST id added to it. This
1521 // member variable is a way to pass the information from the call site to
1522 // the relocation info.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001523 TypeFeedbackId recorded_ast_id_;
Steve Block44f0eee2011-05-26 01:26:41 +01001524
Steve Blocka7e24c12009-10-30 11:49:00 +00001525 int buffer_space() const { return reloc_info_writer.pos() - pc_; }
1526
Steve Blocka7e24c12009-10-30 11:49:00 +00001527 // Decode branch instruction at pos and return branch target pos
1528 int target_at(int pos);
1529
1530 // Patch branch instruction at pos to branch to given branch target pos
1531 void target_at_put(int pos, int target_pos);
1532
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001533 // Prevent contant pool emission until EndBlockConstPool is called.
1534 // Call to this function can be nested but must be followed by an equal
1535 // number of call to EndBlockConstpool.
1536 void StartBlockConstPool() {
1537 if (const_pool_blocked_nesting_++ == 0) {
1538 // Prevent constant pool checks happening by setting the next check to
1539 // the biggest possible offset.
1540 next_buffer_check_ = kMaxInt;
1541 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001542 }
1543
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001544 // Resume constant pool emission. Need to be called as many time as
1545 // StartBlockConstPool to have an effect.
Steve Block6ded16b2010-05-10 14:33:55 +01001546 void EndBlockConstPool() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001547 if (--const_pool_blocked_nesting_ == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001548#ifdef DEBUG
1549 // Max pool start (if we need a jump and an alignment).
1550 int start = pc_offset() + kInstrSize + 2 * kPointerSize;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001551 // Check the constant pool hasn't been blocked for too long.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001552 DCHECK((num_pending_32_bit_reloc_info_ == 0) ||
1553 (start + num_pending_64_bit_reloc_info_ * kDoubleSize <
1554 (first_const_pool_32_use_ + kMaxDistToIntPool)));
1555 DCHECK((num_pending_64_bit_reloc_info_ == 0) ||
1556 (start < (first_const_pool_64_use_ + kMaxDistToFPPool)));
1557#endif
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001558 // Two cases:
1559 // * no_const_pool_before_ >= next_buffer_check_ and the emission is
1560 // still blocked
1561 // * no_const_pool_before_ < next_buffer_check_ and the next emit will
1562 // trigger a check.
1563 next_buffer_check_ = no_const_pool_before_;
1564 }
Steve Block6ded16b2010-05-10 14:33:55 +01001565 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001566
1567 bool is_const_pool_blocked() const {
1568 return (const_pool_blocked_nesting_ > 0) ||
1569 (pc_offset() < no_const_pool_before_);
1570 }
Steve Block6ded16b2010-05-10 14:33:55 +01001571
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001572 private:
Steve Blocka7e24c12009-10-30 11:49:00 +00001573 int next_buffer_check_; // pc offset of next buffer check
1574
1575 // Code generation
1576 // The relocation writer's position is at least kGap bytes below the end of
1577 // the generated instructions. This is so that multi-instruction sequences do
1578 // not have to check for overflow. The same is true for writes of large
1579 // relocation info entries.
1580 static const int kGap = 32;
Steve Blocka7e24c12009-10-30 11:49:00 +00001581
1582 // Constant pool generation
1583 // Pools are emitted in the instruction stream, preferably after unconditional
1584 // jumps or after returns from functions (in dead code locations).
1585 // If a long code sequence does not contain unconditional jumps, it is
1586 // necessary to emit the constant pool before the pool gets too far from the
1587 // location it is accessed from. In this case, we emit a jump over the emitted
1588 // constant pool.
1589 // Constants in the pool may be addresses of functions that gets relocated;
1590 // if so, a relocation info entry is associated to the constant pool entry.
1591
1592 // Repeated checking whether the constant pool should be emitted is rather
1593 // expensive. By default we only check again once a number of instructions
1594 // has been generated. That also means that the sizing of the buffers is not
1595 // an exact science, and that we rely on some slop to not overrun buffers.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001596 static const int kCheckPoolIntervalInst = 32;
1597 static const int kCheckPoolInterval = kCheckPoolIntervalInst * kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +00001598
1599
Steve Block6ded16b2010-05-10 14:33:55 +01001600 // Emission of the constant pool may be blocked in some code sequences.
1601 int const_pool_blocked_nesting_; // Block emission if this is not zero.
1602 int no_const_pool_before_; // Block emission before this pc offset.
Steve Blocka7e24c12009-10-30 11:49:00 +00001603
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001604 // Keep track of the first instruction requiring a constant pool entry
1605 // since the previous constant pool was emitted.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001606 int first_const_pool_32_use_;
1607 int first_const_pool_64_use_;
Steve Blocka7e24c12009-10-30 11:49:00 +00001608
1609 // Relocation info generation
1610 // Each relocation is encoded as a variable size value
1611 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1612 RelocInfoWriter reloc_info_writer;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001613
Steve Blocka7e24c12009-10-30 11:49:00 +00001614 // Relocation info records are also used during code generation as temporary
1615 // containers for constants and code target addresses until they are emitted
1616 // to the constant pool. These pending relocation info records are temporarily
1617 // stored in a separate buffer until a constant pool is emitted.
1618 // If every instruction in a long sequence is accessing the pool, we need one
1619 // pending relocation entry per instruction.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001620
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001621 // The buffers of pending relocation info.
1622 RelocInfo pending_32_bit_reloc_info_[kMaxNumPending32RelocInfo];
1623 RelocInfo pending_64_bit_reloc_info_[kMaxNumPending64RelocInfo];
1624 // Number of pending reloc info entries in the 32 bits buffer.
1625 int num_pending_32_bit_reloc_info_;
1626 // Number of pending reloc info entries in the 64 bits buffer.
1627 int num_pending_64_bit_reloc_info_;
1628
1629 ConstantPoolBuilder constant_pool_builder_;
Steve Blocka7e24c12009-10-30 11:49:00 +00001630
1631 // The bound position, before this we cannot do instruction elimination.
1632 int last_bound_pos_;
1633
Steve Blocka7e24c12009-10-30 11:49:00 +00001634 // Code emission
1635 inline void CheckBuffer();
1636 void GrowBuffer();
1637 inline void emit(Instr x);
1638
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001639 // 32-bit immediate values
1640 void move_32_bit_immediate(Register rd,
1641 const Operand& x,
1642 Condition cond = al);
1643
Steve Blocka7e24c12009-10-30 11:49:00 +00001644 // Instruction generation
1645 void addrmod1(Instr instr, Register rn, Register rd, const Operand& x);
1646 void addrmod2(Instr instr, Register rd, const MemOperand& x);
1647 void addrmod3(Instr instr, Register rd, const MemOperand& x);
1648 void addrmod4(Instr instr, Register rn, RegList rl);
1649 void addrmod5(Instr instr, CRegister crd, const MemOperand& x);
1650
1651 // Labels
1652 void print(Label* L);
1653 void bind_to(Label* L, int pos);
Steve Blocka7e24c12009-10-30 11:49:00 +00001654 void next(Label* L);
1655
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001656 enum UseConstantPoolMode {
1657 USE_CONSTANT_POOL,
1658 DONT_USE_CONSTANT_POOL
1659 };
1660
Steve Blocka7e24c12009-10-30 11:49:00 +00001661 // Record reloc info for current pc_
1662 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001663 void RecordRelocInfo(const RelocInfo& rinfo);
1664 ConstantPoolArray::LayoutSection ConstantPoolAddEntry(const RelocInfo& rinfo);
Steve Blocka7e24c12009-10-30 11:49:00 +00001665
Steve Blocka7e24c12009-10-30 11:49:00 +00001666 friend class RelocInfo;
1667 friend class CodePatcher;
Steve Block6ded16b2010-05-10 14:33:55 +01001668 friend class BlockConstPoolScope;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001669 PositionsRecorder positions_recorder_;
1670 friend class PositionsRecorder;
1671 friend class EnsureSpace;
Steve Blocka7e24c12009-10-30 11:49:00 +00001672};
1673
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001674
1675class EnsureSpace BASE_EMBEDDED {
1676 public:
1677 explicit EnsureSpace(Assembler* assembler) {
1678 assembler->CheckBuffer();
1679 }
1680};
1681
1682
Steve Blocka7e24c12009-10-30 11:49:00 +00001683} } // namespace v8::internal
1684
1685#endif // V8_ARM_ASSEMBLER_ARM_H_