blob: eeadaca8a821fdc0f93cd9755653ddb27f31312c [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_
42#include <stdio.h>
43#include "assembler.h"
Steve Block1e0659c2011-05-24 12:43:12 +010044#include "constants-arm.h"
Steve Blockd0582a62009-12-15 09:54:21 +000045#include "serialize.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000046
47namespace v8 {
48namespace internal {
49
50// CPU Registers.
51//
52// 1) We would prefer to use an enum, but enum values are assignment-
53// compatible with int, which has caused code-generation bugs.
54//
55// 2) We would prefer to use a class instead of a struct but we don't like
56// the register initialization to depend on the particular initialization
57// order (which appears to be different on OS X, Linux, and Windows for the
58// installed versions of C++ we tried). Using a struct permits C-style
59// "initialization". Also, the Register objects cannot be const as this
60// forces initialization stubs in MSVC, making us dependent on initialization
61// order.
62//
63// 3) By not using an enum, we are possibly preventing the compiler from
64// doing certain constant folds, which may significantly reduce the
65// code generated for some assembly instructions (because they boil down
66// to a few constants). If this is a problem, we could change the code
67// such that we use an enum in optimized mode, and the struct in debug
68// mode. This way we get the compile-time error checking in debug mode
69// and best performance in optimized code.
Steve Block9fac8402011-05-12 15:51:54 +010070
Steve Blocka7e24c12009-10-30 11:49:00 +000071// Core register
72struct Register {
Ben Murdochb0fe1622011-05-05 13:52:32 +010073 static const int kNumRegisters = 16;
74 static const int kNumAllocatableRegisters = 8;
Ben Murdoch257744e2011-11-30 15:57:28 +000075 static const int kSizeInBytes = 4;
Ben Murdochb0fe1622011-05-05 13:52:32 +010076
77 static int ToAllocationIndex(Register reg) {
Steve Block9fac8402011-05-12 15:51:54 +010078 ASSERT(reg.code() < kNumAllocatableRegisters);
Ben Murdochb0fe1622011-05-05 13:52:32 +010079 return reg.code();
80 }
81
82 static Register FromAllocationIndex(int index) {
83 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
84 return from_code(index);
85 }
86
87 static const char* AllocationIndexToString(int index) {
88 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
89 const char* const names[] = {
90 "r0",
91 "r1",
92 "r2",
93 "r3",
94 "r4",
95 "r5",
96 "r6",
97 "r7",
98 };
99 return names[index];
100 }
101
102 static Register from_code(int code) {
103 Register r = { code };
104 return r;
105 }
106
107 bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100108 bool is(Register reg) const { return code_ == reg.code_; }
109 int code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000110 ASSERT(is_valid());
111 return code_;
112 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100113 int bit() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000114 ASSERT(is_valid());
115 return 1 << code_;
116 }
117
Leon Clarkef7060e22010-06-03 12:02:55 +0100118 void set_code(int code) {
119 code_ = code;
120 ASSERT(is_valid());
121 }
122
Andrei Popescu31002712010-02-23 13:46:05 +0000123 // Unfortunately we can't make this private in a struct.
Steve Blocka7e24c12009-10-30 11:49:00 +0000124 int code_;
125};
126
Steve Block6ded16b2010-05-10 14:33:55 +0100127const Register no_reg = { -1 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000128
Steve Block6ded16b2010-05-10 14:33:55 +0100129const Register r0 = { 0 };
130const Register r1 = { 1 };
131const Register r2 = { 2 };
132const Register r3 = { 3 };
133const Register r4 = { 4 };
134const Register r5 = { 5 };
135const Register r6 = { 6 };
136const Register r7 = { 7 };
137const Register r8 = { 8 }; // Used as context register.
Steve Block9fac8402011-05-12 15:51:54 +0100138const Register r9 = { 9 }; // Used as lithium codegen scratch register.
Steve Block6ded16b2010-05-10 14:33:55 +0100139const Register r10 = { 10 }; // Used as roots register.
140const Register fp = { 11 };
141const Register ip = { 12 };
142const Register sp = { 13 };
143const Register lr = { 14 };
144const Register pc = { 15 };
Steve Blockd0582a62009-12-15 09:54:21 +0000145
Leon Clarkee46be812010-01-19 14:06:41 +0000146// Single word VFP register.
147struct SwVfpRegister {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100148 bool is_valid() const { return 0 <= code_ && code_ < 32; }
149 bool is(SwVfpRegister reg) const { return code_ == reg.code_; }
150 int code() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000151 ASSERT(is_valid());
152 return code_;
153 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100154 int bit() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000155 ASSERT(is_valid());
156 return 1 << code_;
157 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100158 void split_code(int* vm, int* m) const {
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100159 ASSERT(is_valid());
160 *m = code_ & 0x1;
161 *vm = code_ >> 1;
162 }
Leon Clarkee46be812010-01-19 14:06:41 +0000163
164 int code_;
165};
166
167
168// Double word VFP register.
169struct DwVfpRegister {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100170 static const int kNumRegisters = 16;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000171 // A few double registers are reserved: one as a scratch register and one to
172 // hold 0.0, that does not fit in the immediate field of vmov instructions.
173 // d14: 0.0
174 // d15: scratch register.
175 static const int kNumReservedRegisters = 2;
176 static const int kNumAllocatableRegisters = kNumRegisters -
177 kNumReservedRegisters;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100178
Ben Murdoch692be652012-01-10 18:47:50 +0000179 inline static int ToAllocationIndex(DwVfpRegister reg);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100180
181 static DwVfpRegister FromAllocationIndex(int index) {
182 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
Ben Murdoch692be652012-01-10 18:47:50 +0000183 return from_code(index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100184 }
185
186 static const char* AllocationIndexToString(int index) {
187 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
188 const char* const names[] = {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000189 "d0",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100190 "d1",
191 "d2",
192 "d3",
193 "d4",
194 "d5",
195 "d6",
196 "d7",
197 "d8",
198 "d9",
199 "d10",
200 "d11",
201 "d12",
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000202 "d13"
Ben Murdochb0fe1622011-05-05 13:52:32 +0100203 };
204 return names[index];
205 }
206
207 static DwVfpRegister from_code(int code) {
208 DwVfpRegister r = { code };
209 return r;
210 }
211
Leon Clarkee46be812010-01-19 14:06:41 +0000212 // Supporting d0 to d15, can be later extended to d31.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100213 bool is_valid() const { return 0 <= code_ && code_ < 16; }
214 bool is(DwVfpRegister reg) const { return code_ == reg.code_; }
215 SwVfpRegister low() const {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100216 SwVfpRegister reg;
217 reg.code_ = code_ * 2;
218
219 ASSERT(reg.is_valid());
220 return reg;
221 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100222 SwVfpRegister high() const {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100223 SwVfpRegister reg;
224 reg.code_ = (code_ * 2) + 1;
225
226 ASSERT(reg.is_valid());
227 return reg;
228 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100229 int code() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000230 ASSERT(is_valid());
231 return code_;
232 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100233 int bit() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000234 ASSERT(is_valid());
235 return 1 << code_;
236 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100237 void split_code(int* vm, int* m) const {
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100238 ASSERT(is_valid());
239 *m = (code_ & 0x10) >> 4;
240 *vm = code_ & 0x0F;
241 }
Leon Clarkee46be812010-01-19 14:06:41 +0000242
243 int code_;
244};
245
246
Ben Murdochb0fe1622011-05-05 13:52:32 +0100247typedef DwVfpRegister DoubleRegister;
248
249
Steve Block6ded16b2010-05-10 14:33:55 +0100250// Support for the VFP registers s0 to s31 (d0 to d15).
Leon Clarkee46be812010-01-19 14:06:41 +0000251// Note that "s(N):s(N+1)" is the same as "d(N/2)".
Steve Block6ded16b2010-05-10 14:33:55 +0100252const SwVfpRegister s0 = { 0 };
253const SwVfpRegister s1 = { 1 };
254const SwVfpRegister s2 = { 2 };
255const SwVfpRegister s3 = { 3 };
256const SwVfpRegister s4 = { 4 };
257const SwVfpRegister s5 = { 5 };
258const SwVfpRegister s6 = { 6 };
259const SwVfpRegister s7 = { 7 };
260const SwVfpRegister s8 = { 8 };
261const SwVfpRegister s9 = { 9 };
262const SwVfpRegister s10 = { 10 };
263const SwVfpRegister s11 = { 11 };
264const SwVfpRegister s12 = { 12 };
265const SwVfpRegister s13 = { 13 };
266const SwVfpRegister s14 = { 14 };
267const SwVfpRegister s15 = { 15 };
268const SwVfpRegister s16 = { 16 };
269const SwVfpRegister s17 = { 17 };
270const SwVfpRegister s18 = { 18 };
271const SwVfpRegister s19 = { 19 };
272const SwVfpRegister s20 = { 20 };
273const SwVfpRegister s21 = { 21 };
274const SwVfpRegister s22 = { 22 };
275const SwVfpRegister s23 = { 23 };
276const SwVfpRegister s24 = { 24 };
277const SwVfpRegister s25 = { 25 };
278const SwVfpRegister s26 = { 26 };
279const SwVfpRegister s27 = { 27 };
280const SwVfpRegister s28 = { 28 };
281const SwVfpRegister s29 = { 29 };
282const SwVfpRegister s30 = { 30 };
283const SwVfpRegister s31 = { 31 };
Leon Clarkee46be812010-01-19 14:06:41 +0000284
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100285const DwVfpRegister no_dreg = { -1 };
Steve Block6ded16b2010-05-10 14:33:55 +0100286const DwVfpRegister d0 = { 0 };
287const DwVfpRegister d1 = { 1 };
288const DwVfpRegister d2 = { 2 };
289const DwVfpRegister d3 = { 3 };
290const DwVfpRegister d4 = { 4 };
291const DwVfpRegister d5 = { 5 };
292const DwVfpRegister d6 = { 6 };
293const DwVfpRegister d7 = { 7 };
294const DwVfpRegister d8 = { 8 };
295const DwVfpRegister d9 = { 9 };
296const DwVfpRegister d10 = { 10 };
297const DwVfpRegister d11 = { 11 };
298const DwVfpRegister d12 = { 12 };
299const DwVfpRegister d13 = { 13 };
300const DwVfpRegister d14 = { 14 };
301const DwVfpRegister d15 = { 15 };
Leon Clarkee46be812010-01-19 14:06:41 +0000302
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +0100303// Aliases for double registers.
304const DwVfpRegister kFirstCalleeSavedDoubleReg = d8;
305const DwVfpRegister kLastCalleeSavedDoubleReg = d15;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000306const DwVfpRegister kDoubleRegZero = d14;
Ben Murdoch692be652012-01-10 18:47:50 +0000307const DwVfpRegister kScratchDoubleReg = d15;
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +0100308
Steve Blocka7e24c12009-10-30 11:49:00 +0000309
310// Coprocessor register
311struct CRegister {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100312 bool is_valid() const { return 0 <= code_ && code_ < 16; }
313 bool is(CRegister creg) const { return code_ == creg.code_; }
314 int code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000315 ASSERT(is_valid());
316 return code_;
317 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100318 int bit() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000319 ASSERT(is_valid());
320 return 1 << code_;
321 }
322
Andrei Popescu31002712010-02-23 13:46:05 +0000323 // Unfortunately we can't make this private in a struct.
Steve Blocka7e24c12009-10-30 11:49:00 +0000324 int code_;
325};
326
327
Steve Block6ded16b2010-05-10 14:33:55 +0100328const CRegister no_creg = { -1 };
329
330const CRegister cr0 = { 0 };
331const CRegister cr1 = { 1 };
332const CRegister cr2 = { 2 };
333const CRegister cr3 = { 3 };
334const CRegister cr4 = { 4 };
335const CRegister cr5 = { 5 };
336const CRegister cr6 = { 6 };
337const CRegister cr7 = { 7 };
338const CRegister cr8 = { 8 };
339const CRegister cr9 = { 9 };
340const CRegister cr10 = { 10 };
341const CRegister cr11 = { 11 };
342const CRegister cr12 = { 12 };
343const CRegister cr13 = { 13 };
344const CRegister cr14 = { 14 };
345const CRegister cr15 = { 15 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000346
347
348// Coprocessor number
349enum Coprocessor {
350 p0 = 0,
351 p1 = 1,
352 p2 = 2,
353 p3 = 3,
354 p4 = 4,
355 p5 = 5,
356 p6 = 6,
357 p7 = 7,
358 p8 = 8,
359 p9 = 9,
360 p10 = 10,
361 p11 = 11,
362 p12 = 12,
363 p13 = 13,
364 p14 = 14,
365 p15 = 15
366};
367
368
Steve Blocka7e24c12009-10-30 11:49:00 +0000369// -----------------------------------------------------------------------------
370// Machine instruction Operands
371
372// Class Operand represents a shifter operand in data processing instructions
373class Operand BASE_EMBEDDED {
374 public:
375 // immediate
376 INLINE(explicit Operand(int32_t immediate,
377 RelocInfo::Mode rmode = RelocInfo::NONE));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000378 INLINE(static Operand Zero()) {
379 return Operand(static_cast<int32_t>(0));
380 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000381 INLINE(explicit Operand(const ExternalReference& f));
Steve Blocka7e24c12009-10-30 11:49:00 +0000382 explicit Operand(Handle<Object> handle);
383 INLINE(explicit Operand(Smi* value));
384
385 // rm
386 INLINE(explicit Operand(Register rm));
387
388 // rm <shift_op> shift_imm
389 explicit Operand(Register rm, ShiftOp shift_op, int shift_imm);
390
391 // rm <shift_op> rs
392 explicit Operand(Register rm, ShiftOp shift_op, Register rs);
393
394 // Return true if this is a register operand.
395 INLINE(bool is_reg() const);
396
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100397 // Return true if this operand fits in one instruction so that no
Steve Block44f0eee2011-05-26 01:26:41 +0100398 // 2-instruction solution with a load into the ip register is necessary. If
399 // the instruction this operand is used for is a MOV or MVN instruction the
400 // actual instruction to use is required for this calculation. For other
401 // instructions instr is ignored.
402 bool is_single_instruction(Instr instr = 0) const;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800403 bool must_use_constant_pool() const;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100404
405 inline int32_t immediate() const {
406 ASSERT(!rm_.is_valid());
407 return imm32_;
408 }
409
Steve Blocka7e24c12009-10-30 11:49:00 +0000410 Register rm() const { return rm_; }
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100411 Register rs() const { return rs_; }
412 ShiftOp shift_op() const { return shift_op_; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000413
414 private:
415 Register rm_;
416 Register rs_;
417 ShiftOp shift_op_;
418 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
419 int32_t imm32_; // valid if rm_ == no_reg
420 RelocInfo::Mode rmode_;
421
422 friend class Assembler;
423};
424
425
426// Class MemOperand represents a memory operand in load and store instructions
427class MemOperand BASE_EMBEDDED {
428 public:
429 // [rn +/- offset] Offset/NegOffset
430 // [rn +/- offset]! PreIndex/NegPreIndex
431 // [rn], +/- offset PostIndex/NegPostIndex
432 // offset is any signed 32-bit value; offset is first loaded to register ip if
433 // it does not fit the addressing mode (12-bit unsigned and sign bit)
434 explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset);
435
436 // [rn +/- rm] Offset/NegOffset
437 // [rn +/- rm]! PreIndex/NegPreIndex
438 // [rn], +/- rm PostIndex/NegPostIndex
439 explicit MemOperand(Register rn, Register rm, AddrMode am = Offset);
440
441 // [rn +/- rm <shift_op> shift_imm] Offset/NegOffset
442 // [rn +/- rm <shift_op> shift_imm]! PreIndex/NegPreIndex
443 // [rn], +/- rm <shift_op> shift_imm PostIndex/NegPostIndex
444 explicit MemOperand(Register rn, Register rm,
445 ShiftOp shift_op, int shift_imm, AddrMode am = Offset);
446
Kristian Monsen25f61362010-05-21 11:50:48 +0100447 void set_offset(int32_t offset) {
448 ASSERT(rm_.is(no_reg));
449 offset_ = offset;
450 }
451
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100452 uint32_t offset() const {
Kristian Monsen25f61362010-05-21 11:50:48 +0100453 ASSERT(rm_.is(no_reg));
454 return offset_;
455 }
456
Leon Clarkef7060e22010-06-03 12:02:55 +0100457 Register rn() const { return rn_; }
458 Register rm() const { return rm_; }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000459 AddrMode am() const { return am_; }
Kristian Monsen25f61362010-05-21 11:50:48 +0100460
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100461 bool OffsetIsUint12Encodable() const {
462 return offset_ >= 0 ? is_uint12(offset_) : is_uint12(-offset_);
463 }
464
Steve Blocka7e24c12009-10-30 11:49:00 +0000465 private:
466 Register rn_; // base
467 Register rm_; // register offset
468 int32_t offset_; // valid if rm_ == no_reg
469 ShiftOp shift_op_;
470 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
471 AddrMode am_; // bits P, U, and W
472
473 friend class Assembler;
474};
475
Steve Blockd0582a62009-12-15 09:54:21 +0000476// CpuFeatures keeps track of which features are supported by the target CPU.
477// Supported features must be enabled by a Scope before use.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100478class CpuFeatures : public AllStatic {
Steve Blockd0582a62009-12-15 09:54:21 +0000479 public:
480 // Detect features of the target CPU. Set safe defaults if the serializer
481 // is enabled (snapshots must be portable).
Ben Murdoch8b112d22011-06-08 16:22:53 +0100482 static void Probe();
Steve Blockd0582a62009-12-15 09:54:21 +0000483
484 // Check whether a feature is supported by the target CPU.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100485 static bool IsSupported(CpuFeature f) {
486 ASSERT(initialized_);
Steve Blockd0582a62009-12-15 09:54:21 +0000487 if (f == VFP3 && !FLAG_enable_vfp3) return false;
488 return (supported_ & (1u << f)) != 0;
489 }
490
Ben Murdoch8b112d22011-06-08 16:22:53 +0100491#ifdef DEBUG
Steve Blockd0582a62009-12-15 09:54:21 +0000492 // Check whether a feature is currently enabled.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100493 static bool IsEnabled(CpuFeature f) {
494 ASSERT(initialized_);
495 Isolate* isolate = Isolate::UncheckedCurrent();
496 if (isolate == NULL) {
497 // When no isolate is available, work as if we're running in
498 // release mode.
499 return IsSupported(f);
500 }
501 unsigned enabled = static_cast<unsigned>(isolate->enabled_cpu_features());
502 return (enabled & (1u << f)) != 0;
Steve Blockd0582a62009-12-15 09:54:21 +0000503 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100504#endif
Steve Blockd0582a62009-12-15 09:54:21 +0000505
506 // Enable a specified feature within a scope.
507 class Scope BASE_EMBEDDED {
508#ifdef DEBUG
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000509
Steve Blockd0582a62009-12-15 09:54:21 +0000510 public:
Ben Murdoch8b112d22011-06-08 16:22:53 +0100511 explicit Scope(CpuFeature f) {
512 unsigned mask = 1u << f;
513 ASSERT(CpuFeatures::IsSupported(f));
Steve Blockd0582a62009-12-15 09:54:21 +0000514 ASSERT(!Serializer::enabled() ||
Ben Murdoch8b112d22011-06-08 16:22:53 +0100515 (CpuFeatures::found_by_runtime_probing_ & mask) == 0);
516 isolate_ = Isolate::UncheckedCurrent();
517 old_enabled_ = 0;
518 if (isolate_ != NULL) {
519 old_enabled_ = static_cast<unsigned>(isolate_->enabled_cpu_features());
520 isolate_->set_enabled_cpu_features(old_enabled_ | mask);
521 }
Steve Blockd0582a62009-12-15 09:54:21 +0000522 }
Steve Block44f0eee2011-05-26 01:26:41 +0100523 ~Scope() {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100524 ASSERT_EQ(Isolate::UncheckedCurrent(), isolate_);
525 if (isolate_ != NULL) {
526 isolate_->set_enabled_cpu_features(old_enabled_);
527 }
Steve Block44f0eee2011-05-26 01:26:41 +0100528 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000529
Steve Blockd0582a62009-12-15 09:54:21 +0000530 private:
Steve Block44f0eee2011-05-26 01:26:41 +0100531 Isolate* isolate_;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100532 unsigned old_enabled_;
Steve Blockd0582a62009-12-15 09:54:21 +0000533#else
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000534
Steve Blockd0582a62009-12-15 09:54:21 +0000535 public:
536 explicit Scope(CpuFeature f) {}
537#endif
538 };
539
Ben Murdoch8b112d22011-06-08 16:22:53 +0100540 class TryForceFeatureScope BASE_EMBEDDED {
541 public:
542 explicit TryForceFeatureScope(CpuFeature f)
543 : old_supported_(CpuFeatures::supported_) {
544 if (CanForce()) {
545 CpuFeatures::supported_ |= (1u << f);
546 }
547 }
548
549 ~TryForceFeatureScope() {
550 if (CanForce()) {
551 CpuFeatures::supported_ = old_supported_;
552 }
553 }
554
555 private:
556 static bool CanForce() {
557 // It's only safe to temporarily force support of CPU features
558 // when there's only a single isolate, which is guaranteed when
559 // the serializer is enabled.
560 return Serializer::enabled();
561 }
562
563 const unsigned old_supported_;
564 };
565
Steve Blockd0582a62009-12-15 09:54:21 +0000566 private:
Ben Murdoch8b112d22011-06-08 16:22:53 +0100567#ifdef DEBUG
568 static bool initialized_;
569#endif
570 static unsigned supported_;
571 static unsigned found_by_runtime_probing_;
Steve Block44f0eee2011-05-26 01:26:41 +0100572
573 DISALLOW_COPY_AND_ASSIGN(CpuFeatures);
Steve Blockd0582a62009-12-15 09:54:21 +0000574};
575
Steve Blocka7e24c12009-10-30 11:49:00 +0000576
Steve Blocka7e24c12009-10-30 11:49:00 +0000577extern const Instr kMovLrPc;
Steve Block6ded16b2010-05-10 14:33:55 +0100578extern const Instr kLdrPCMask;
Steve Blocka7e24c12009-10-30 11:49:00 +0000579extern const Instr kLdrPCPattern;
Steve Block6ded16b2010-05-10 14:33:55 +0100580extern const Instr kBlxRegMask;
581extern const Instr kBlxRegPattern;
Steve Blocka7e24c12009-10-30 11:49:00 +0000582
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100583extern const Instr kMovMvnMask;
584extern const Instr kMovMvnPattern;
585extern const Instr kMovMvnFlip;
586
587extern const Instr kMovLeaveCCMask;
588extern const Instr kMovLeaveCCPattern;
589extern const Instr kMovwMask;
590extern const Instr kMovwPattern;
591extern const Instr kMovwLeaveCCFlip;
592
593extern const Instr kCmpCmnMask;
594extern const Instr kCmpCmnPattern;
595extern const Instr kCmpCmnFlip;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100596extern const Instr kAddSubFlip;
597extern const Instr kAndBicFlip;
Steve Blocka7e24c12009-10-30 11:49:00 +0000598
Steve Block1e0659c2011-05-24 12:43:12 +0100599
600
Steve Block44f0eee2011-05-26 01:26:41 +0100601class Assembler : public AssemblerBase {
Steve Blocka7e24c12009-10-30 11:49:00 +0000602 public:
603 // Create an assembler. Instructions and relocation information are emitted
604 // into a buffer, with the instructions starting from the beginning and the
605 // relocation information starting from the end of the buffer. See CodeDesc
606 // for a detailed comment on the layout (globals.h).
607 //
608 // If the provided buffer is NULL, the assembler allocates and grows its own
609 // buffer, and buffer_size determines the initial buffer size. The buffer is
610 // owned by the assembler and deallocated upon destruction of the assembler.
611 //
612 // If the provided buffer is not NULL, the assembler uses the provided buffer
613 // for code generation and assumes its size to be buffer_size. If the buffer
614 // is too small, a fatal error occurs. No deallocation of the buffer is done
615 // upon destruction of the assembler.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100616 Assembler(Isolate* isolate, void* buffer, int buffer_size);
Steve Blocka7e24c12009-10-30 11:49:00 +0000617 ~Assembler();
618
Steve Block44f0eee2011-05-26 01:26:41 +0100619 // Overrides the default provided by FLAG_debug_code.
620 void set_emit_debug_code(bool value) { emit_debug_code_ = value; }
621
Steve Blocka7e24c12009-10-30 11:49:00 +0000622 // GetCode emits any pending (non-emitted) code and fills the descriptor
623 // desc. GetCode() is idempotent; it returns the same result if no other
624 // Assembler functions are invoked in between GetCode() calls.
625 void GetCode(CodeDesc* desc);
626
627 // Label operations & relative jumps (PPUM Appendix D)
628 //
629 // Takes a branch opcode (cc) and a label (L) and generates
630 // either a backward branch or a forward branch and links it
631 // to the label fixup chain. Usage:
632 //
633 // Label L; // unbound label
634 // j(cc, &L); // forward branch to unbound label
635 // bind(&L); // bind label to the current pc
636 // j(cc, &L); // backward branch to bound label
637 // bind(&L); // illegal: a label may be bound only once
638 //
639 // Note: The same Label can be used for forward and backward branches
640 // but it may be bound only once.
641
642 void bind(Label* L); // binds an unbound label L to the current code position
643
644 // Returns the branch offset to the given label from the current code position
645 // Links the label to the current position if it is still unbound
646 // Manages the jump elimination optimization if the second parameter is true.
647 int branch_offset(Label* L, bool jump_elimination_allowed);
648
649 // Puts a labels target address at the given position.
650 // The high 8 bits are set to zero.
651 void label_at_put(Label* L, int at_offset);
652
653 // Return the address in the constant pool of the code target address used by
654 // the branch/call instruction at pc.
655 INLINE(static Address target_address_address_at(Address pc));
656
657 // Read/Modify the code target address in the branch/call instruction at pc.
658 INLINE(static Address target_address_at(Address pc));
659 INLINE(static void set_target_address_at(Address pc, Address target));
660
Steve Blockd0582a62009-12-15 09:54:21 +0000661 // This sets the branch destination (which is in the constant pool on ARM).
662 // This is for calls and branches within generated code.
663 inline static void set_target_at(Address constant_pool_entry, Address target);
664
665 // This sets the branch destination (which is in the constant pool on ARM).
666 // This is for calls and branches to runtime code.
667 inline static void set_external_target_at(Address constant_pool_entry,
668 Address target) {
669 set_target_at(constant_pool_entry, target);
670 }
671
672 // Here we are patching the address in the constant pool, not the actual call
673 // instruction. The address in the constant pool is the same size as a
674 // pointer.
675 static const int kCallTargetSize = kPointerSize;
676 static const int kExternalTargetSize = kPointerSize;
677
Steve Blocka7e24c12009-10-30 11:49:00 +0000678 // Size of an instruction.
679 static const int kInstrSize = sizeof(Instr);
680
681 // Distance between the instruction referring to the address of the call
Steve Block6ded16b2010-05-10 14:33:55 +0100682 // target and the return address.
683#ifdef USE_BLX
684 // Call sequence is:
685 // ldr ip, [pc, #...] @ call address
686 // blx ip
687 // @ return address
688 static const int kCallTargetAddressOffset = 2 * kInstrSize;
689#else
690 // Call sequence is:
691 // mov lr, pc
692 // ldr pc, [pc, #...] @ call address
693 // @ return address
Steve Blocka7e24c12009-10-30 11:49:00 +0000694 static const int kCallTargetAddressOffset = kInstrSize;
Steve Block6ded16b2010-05-10 14:33:55 +0100695#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000696
697 // Distance between start of patched return sequence and the emitted address
698 // to jump to.
Steve Block6ded16b2010-05-10 14:33:55 +0100699#ifdef USE_BLX
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100700 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100701 // ldr ip, [pc, #0] @ emited address and start
702 // blx ip
703 static const int kPatchReturnSequenceAddressOffset = 0 * kInstrSize;
704#else
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100705 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100706 // mov lr, pc @ start of sequence
707 // ldr pc, [pc, #-4] @ emited address
708 static const int kPatchReturnSequenceAddressOffset = kInstrSize;
709#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000710
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100711 // Distance between start of patched debug break slot and the emitted address
712 // to jump to.
713#ifdef USE_BLX
714 // Patched debug break slot code is:
715 // ldr ip, [pc, #0] @ emited address and start
716 // blx ip
717 static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
718#else
719 // Patched debug break slot code is:
720 // mov lr, pc @ start of sequence
721 // ldr pc, [pc, #-4] @ emited address
722 static const int kPatchDebugBreakSlotAddressOffset = kInstrSize;
723#endif
724
Steve Blocka7e24c12009-10-30 11:49:00 +0000725 // Difference between address of current opcode and value read from pc
726 // register.
727 static const int kPcLoadDelta = 8;
728
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100729 static const int kJSReturnSequenceInstructions = 4;
730 static const int kDebugBreakSlotInstructions = 3;
731 static const int kDebugBreakSlotLength =
732 kDebugBreakSlotInstructions * kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +0000733
734 // ---------------------------------------------------------------------------
735 // Code generation
736
737 // Insert the smallest number of nop instructions
738 // possible to align the pc offset to a multiple
739 // of m. m must be a power of 2 (>= 4).
740 void Align(int m);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100741 // Aligns code to something that's optimal for a jump target for the platform.
742 void CodeTargetAlign();
Steve Blocka7e24c12009-10-30 11:49:00 +0000743
744 // Branch instructions
745 void b(int branch_offset, Condition cond = al);
746 void bl(int branch_offset, Condition cond = al);
747 void blx(int branch_offset); // v5 and above
748 void blx(Register target, Condition cond = al); // v5 and above
749 void bx(Register target, Condition cond = al); // v5 and above, plus v4t
750
751 // Convenience branch instructions using labels
752 void b(Label* L, Condition cond = al) {
753 b(branch_offset(L, cond == al), cond);
754 }
755 void b(Condition cond, Label* L) { b(branch_offset(L, cond == al), cond); }
756 void bl(Label* L, Condition cond = al) { bl(branch_offset(L, false), cond); }
757 void bl(Condition cond, Label* L) { bl(branch_offset(L, false), cond); }
758 void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above
759
760 // Data-processing instructions
Andrei Popescu31002712010-02-23 13:46:05 +0000761
Steve Blocka7e24c12009-10-30 11:49:00 +0000762 void and_(Register dst, Register src1, const Operand& src2,
763 SBit s = LeaveCC, Condition cond = al);
764
765 void eor(Register dst, Register src1, const Operand& src2,
766 SBit s = LeaveCC, Condition cond = al);
767
768 void sub(Register dst, Register src1, const Operand& src2,
769 SBit s = LeaveCC, Condition cond = al);
770 void sub(Register dst, Register src1, Register src2,
771 SBit s = LeaveCC, Condition cond = al) {
772 sub(dst, src1, Operand(src2), s, cond);
773 }
774
775 void rsb(Register dst, Register src1, const Operand& src2,
776 SBit s = LeaveCC, Condition cond = al);
777
778 void add(Register dst, Register src1, const Operand& src2,
779 SBit s = LeaveCC, Condition cond = al);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100780 void add(Register dst, Register src1, Register src2,
781 SBit s = LeaveCC, Condition cond = al) {
782 add(dst, src1, Operand(src2), s, cond);
783 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000784
785 void adc(Register dst, Register src1, const Operand& src2,
786 SBit s = LeaveCC, Condition cond = al);
787
788 void sbc(Register dst, Register src1, const Operand& src2,
789 SBit s = LeaveCC, Condition cond = al);
790
791 void rsc(Register dst, Register src1, const Operand& src2,
792 SBit s = LeaveCC, Condition cond = al);
793
794 void tst(Register src1, const Operand& src2, Condition cond = al);
795 void tst(Register src1, Register src2, Condition cond = al) {
796 tst(src1, Operand(src2), cond);
797 }
798
799 void teq(Register src1, const Operand& src2, Condition cond = al);
800
801 void cmp(Register src1, const Operand& src2, Condition cond = al);
802 void cmp(Register src1, Register src2, Condition cond = al) {
803 cmp(src1, Operand(src2), cond);
804 }
Steve Block1e0659c2011-05-24 12:43:12 +0100805 void cmp_raw_immediate(Register src1, int raw_immediate, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000806
807 void cmn(Register src1, const Operand& src2, Condition cond = al);
808
809 void orr(Register dst, Register src1, const Operand& src2,
810 SBit s = LeaveCC, Condition cond = al);
811 void orr(Register dst, Register src1, Register src2,
812 SBit s = LeaveCC, Condition cond = al) {
813 orr(dst, src1, Operand(src2), s, cond);
814 }
815
816 void mov(Register dst, const Operand& src,
817 SBit s = LeaveCC, Condition cond = al);
818 void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
819 mov(dst, Operand(src), s, cond);
820 }
821
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100822 // ARMv7 instructions for loading a 32 bit immediate in two instructions.
823 // This may actually emit a different mov instruction, but on an ARMv7 it
824 // is guaranteed to only emit one instruction.
825 void movw(Register reg, uint32_t immediate, Condition cond = al);
826 // The constant for movt should be in the range 0-0xffff.
827 void movt(Register reg, uint32_t immediate, Condition cond = al);
828
Steve Blocka7e24c12009-10-30 11:49:00 +0000829 void bic(Register dst, Register src1, const Operand& src2,
830 SBit s = LeaveCC, Condition cond = al);
831
832 void mvn(Register dst, const Operand& src,
833 SBit s = LeaveCC, Condition cond = al);
834
835 // Multiply instructions
836
837 void mla(Register dst, Register src1, Register src2, Register srcA,
838 SBit s = LeaveCC, Condition cond = al);
839
840 void mul(Register dst, Register src1, Register src2,
841 SBit s = LeaveCC, Condition cond = al);
842
843 void smlal(Register dstL, Register dstH, Register src1, Register src2,
844 SBit s = LeaveCC, Condition cond = al);
845
846 void smull(Register dstL, Register dstH, Register src1, Register src2,
847 SBit s = LeaveCC, Condition cond = al);
848
849 void umlal(Register dstL, Register dstH, Register src1, Register src2,
850 SBit s = LeaveCC, Condition cond = al);
851
852 void umull(Register dstL, Register dstH, Register src1, Register src2,
853 SBit s = LeaveCC, Condition cond = al);
854
855 // Miscellaneous arithmetic instructions
856
857 void clz(Register dst, Register src, Condition cond = al); // v5 and above
858
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100859 // Saturating instructions. v6 and above.
860
861 // Unsigned saturate.
862 //
863 // Saturate an optionally shifted signed value to an unsigned range.
864 //
865 // usat dst, #satpos, src
866 // usat dst, #satpos, src, lsl #sh
867 // usat dst, #satpos, src, asr #sh
868 //
869 // Register dst will contain:
870 //
871 // 0, if s < 0
872 // (1 << satpos) - 1, if s > ((1 << satpos) - 1)
873 // s, otherwise
874 //
875 // where s is the contents of src after shifting (if used.)
876 void usat(Register dst, int satpos, const Operand& src, Condition cond = al);
877
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100878 // Bitfield manipulation instructions. v7 and above.
879
880 void ubfx(Register dst, Register src, int lsb, int width,
881 Condition cond = al);
882
883 void sbfx(Register dst, Register src, int lsb, int width,
884 Condition cond = al);
885
886 void bfc(Register dst, int lsb, int width, Condition cond = al);
887
888 void bfi(Register dst, Register src, int lsb, int width,
889 Condition cond = al);
890
Steve Blocka7e24c12009-10-30 11:49:00 +0000891 // Status register access instructions
892
893 void mrs(Register dst, SRegister s, Condition cond = al);
894 void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al);
895
896 // Load/Store instructions
897 void ldr(Register dst, const MemOperand& src, Condition cond = al);
898 void str(Register src, const MemOperand& dst, Condition cond = al);
899 void ldrb(Register dst, const MemOperand& src, Condition cond = al);
900 void strb(Register src, const MemOperand& dst, Condition cond = al);
901 void ldrh(Register dst, const MemOperand& src, Condition cond = al);
902 void strh(Register src, const MemOperand& dst, Condition cond = al);
903 void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
904 void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
Leon Clarkef7060e22010-06-03 12:02:55 +0100905 void ldrd(Register dst1,
906 Register dst2,
907 const MemOperand& src, Condition cond = al);
908 void strd(Register src1,
909 Register src2,
910 const MemOperand& dst, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000911
912 // Load/Store multiple instructions
913 void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
914 void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
915
Steve Blocka7e24c12009-10-30 11:49:00 +0000916 // Exception-generating instructions and debugging support
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800917 void stop(const char* msg,
918 Condition cond = al,
919 int32_t code = kDefaultStopCode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000920
921 void bkpt(uint32_t imm16); // v5 and above
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800922 void svc(uint32_t imm24, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000923
924 // Coprocessor instructions
925
926 void cdp(Coprocessor coproc, int opcode_1,
927 CRegister crd, CRegister crn, CRegister crm,
928 int opcode_2, Condition cond = al);
929
930 void cdp2(Coprocessor coproc, int opcode_1,
931 CRegister crd, CRegister crn, CRegister crm,
932 int opcode_2); // v5 and above
933
934 void mcr(Coprocessor coproc, int opcode_1,
935 Register rd, CRegister crn, CRegister crm,
936 int opcode_2 = 0, Condition cond = al);
937
938 void mcr2(Coprocessor coproc, int opcode_1,
939 Register rd, CRegister crn, CRegister crm,
940 int opcode_2 = 0); // v5 and above
941
942 void mrc(Coprocessor coproc, int opcode_1,
943 Register rd, CRegister crn, CRegister crm,
944 int opcode_2 = 0, Condition cond = al);
945
946 void mrc2(Coprocessor coproc, int opcode_1,
947 Register rd, CRegister crn, CRegister crm,
948 int opcode_2 = 0); // v5 and above
949
950 void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src,
951 LFlag l = Short, Condition cond = al);
952 void ldc(Coprocessor coproc, CRegister crd, Register base, int option,
953 LFlag l = Short, Condition cond = al);
954
955 void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
956 LFlag l = Short); // v5 and above
957 void ldc2(Coprocessor coproc, CRegister crd, Register base, int option,
958 LFlag l = Short); // v5 and above
959
Steve Blockd0582a62009-12-15 09:54:21 +0000960 // Support for VFP.
961 // All these APIs support S0 to S31 and D0 to D15.
962 // Currently these APIs do not support extended D registers, i.e, D16 to D31.
963 // However, some simple modifications can allow
964 // these APIs to support D16 to D31.
965
Leon Clarked91b9f72010-01-27 17:25:45 +0000966 void vldr(const DwVfpRegister dst,
967 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100968 int offset,
969 const Condition cond = al);
970 void vldr(const DwVfpRegister dst,
971 const MemOperand& src,
Leon Clarked91b9f72010-01-27 17:25:45 +0000972 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +0100973
974 void vldr(const SwVfpRegister dst,
975 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100976 int offset,
977 const Condition cond = al);
978 void vldr(const SwVfpRegister dst,
979 const MemOperand& src,
Steve Block6ded16b2010-05-10 14:33:55 +0100980 const Condition cond = al);
981
Leon Clarked91b9f72010-01-27 17:25:45 +0000982 void vstr(const DwVfpRegister src,
983 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100984 int offset,
985 const Condition cond = al);
986 void vstr(const DwVfpRegister src,
987 const MemOperand& dst,
Leon Clarked91b9f72010-01-27 17:25:45 +0000988 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +0100989
Iain Merrick75681382010-08-19 15:07:18 +0100990 void vstr(const SwVfpRegister src,
991 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100992 int offset,
993 const Condition cond = al);
994 void vstr(const SwVfpRegister src,
995 const MemOperand& dst,
Iain Merrick75681382010-08-19 15:07:18 +0100996 const Condition cond = al);
997
Ben Murdoch8b112d22011-06-08 16:22:53 +0100998 void vldm(BlockAddrMode am,
999 Register base,
1000 DwVfpRegister first,
1001 DwVfpRegister last,
1002 Condition cond = al);
1003
1004 void vstm(BlockAddrMode am,
1005 Register base,
1006 DwVfpRegister first,
1007 DwVfpRegister last,
1008 Condition cond = al);
1009
1010 void vldm(BlockAddrMode am,
1011 Register base,
1012 SwVfpRegister first,
1013 SwVfpRegister last,
1014 Condition cond = al);
1015
1016 void vstm(BlockAddrMode am,
1017 Register base,
1018 SwVfpRegister first,
1019 SwVfpRegister last,
1020 Condition cond = al);
1021
Steve Block8defd9f2010-07-08 12:39:36 +01001022 void vmov(const DwVfpRegister dst,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001023 double imm,
1024 const Condition cond = al);
1025 void vmov(const SwVfpRegister dst,
1026 const SwVfpRegister src,
1027 const Condition cond = al);
1028 void vmov(const DwVfpRegister dst,
Steve Block8defd9f2010-07-08 12:39:36 +01001029 const DwVfpRegister src,
1030 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001031 void vmov(const DwVfpRegister dst,
1032 const Register src1,
Steve Blockd0582a62009-12-15 09:54:21 +00001033 const Register src2,
Leon Clarkee46be812010-01-19 14:06:41 +00001034 const Condition cond = al);
1035 void vmov(const Register dst1,
1036 const Register dst2,
1037 const DwVfpRegister src,
1038 const Condition cond = al);
1039 void vmov(const SwVfpRegister dst,
1040 const Register src,
1041 const Condition cond = al);
1042 void vmov(const Register dst,
1043 const SwVfpRegister src,
1044 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +01001045 void vcvt_f64_s32(const DwVfpRegister dst,
1046 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001047 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001048 const Condition cond = al);
1049 void vcvt_f32_s32(const SwVfpRegister dst,
1050 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001051 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001052 const Condition cond = al);
1053 void vcvt_f64_u32(const DwVfpRegister dst,
1054 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001055 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001056 const Condition cond = al);
1057 void vcvt_s32_f64(const SwVfpRegister dst,
1058 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001059 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001060 const Condition cond = al);
1061 void vcvt_u32_f64(const SwVfpRegister dst,
1062 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001063 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001064 const Condition cond = al);
1065 void vcvt_f64_f32(const DwVfpRegister dst,
1066 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001067 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001068 const Condition cond = al);
1069 void vcvt_f32_f64(const SwVfpRegister dst,
1070 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001071 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001072 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001073
Steve Block44f0eee2011-05-26 01:26:41 +01001074 void vneg(const DwVfpRegister dst,
1075 const DwVfpRegister src,
1076 const Condition cond = al);
Steve Block1e0659c2011-05-24 12:43:12 +01001077 void vabs(const DwVfpRegister dst,
1078 const DwVfpRegister src,
1079 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001080 void vadd(const DwVfpRegister dst,
1081 const DwVfpRegister src1,
1082 const DwVfpRegister src2,
1083 const Condition cond = al);
1084 void vsub(const DwVfpRegister dst,
1085 const DwVfpRegister src1,
1086 const DwVfpRegister src2,
1087 const Condition cond = al);
1088 void vmul(const DwVfpRegister dst,
1089 const DwVfpRegister src1,
1090 const DwVfpRegister src2,
1091 const Condition cond = al);
1092 void vdiv(const DwVfpRegister dst,
1093 const DwVfpRegister src1,
1094 const DwVfpRegister src2,
1095 const Condition cond = al);
1096 void vcmp(const DwVfpRegister src1,
1097 const DwVfpRegister src2,
Steve Blockd0582a62009-12-15 09:54:21 +00001098 const Condition cond = al);
Iain Merrick75681382010-08-19 15:07:18 +01001099 void vcmp(const DwVfpRegister src1,
1100 const double src2,
Iain Merrick75681382010-08-19 15:07:18 +01001101 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001102 void vmrs(const Register dst,
1103 const Condition cond = al);
Russell Brenner90bac252010-11-18 13:33:46 -08001104 void vmsr(const Register dst,
1105 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +01001106 void vsqrt(const DwVfpRegister dst,
1107 const DwVfpRegister src,
1108 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001109
Steve Blocka7e24c12009-10-30 11:49:00 +00001110 // Pseudo instructions
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001111
1112 // Different nop operations are used by the code generator to detect certain
1113 // states of the generated code.
1114 enum NopMarkerTypes {
1115 NON_MARKING_NOP = 0,
1116 DEBUG_BREAK_NOP,
1117 // IC markers.
1118 PROPERTY_ACCESS_INLINED,
1119 PROPERTY_ACCESS_INLINED_CONTEXT,
1120 PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE,
1121 // Helper values.
1122 LAST_CODE_MARKER,
1123 FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED
1124 };
1125
1126 void nop(int type = 0); // 0 is the default non-marking type.
Steve Blocka7e24c12009-10-30 11:49:00 +00001127
1128 void push(Register src, Condition cond = al) {
1129 str(src, MemOperand(sp, 4, NegPreIndex), cond);
1130 }
1131
1132 void pop(Register dst, Condition cond = al) {
1133 ldr(dst, MemOperand(sp, 4, PostIndex), cond);
1134 }
1135
1136 void pop() {
1137 add(sp, sp, Operand(kPointerSize));
1138 }
1139
Steve Blocka7e24c12009-10-30 11:49:00 +00001140 // Jump unconditionally to given label.
1141 void jmp(Label* L) { b(L, al); }
1142
1143 // Check the code size generated from label to here.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001144 int SizeOfCodeGeneratedSince(Label* label) {
1145 return pc_offset() - label->pos();
1146 }
1147
1148 // Check the number of instructions generated from label to here.
1149 int InstructionsGeneratedSince(Label* label) {
1150 return SizeOfCodeGeneratedSince(label) / kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +00001151 }
1152
Steve Blockd0582a62009-12-15 09:54:21 +00001153 // Check whether an immediate fits an addressing mode 1 instruction.
1154 bool ImmediateFitsAddrMode1Instruction(int32_t imm32);
1155
Steve Block6ded16b2010-05-10 14:33:55 +01001156 // Class for scoping postponing the constant pool generation.
1157 class BlockConstPoolScope {
1158 public:
1159 explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) {
1160 assem_->StartBlockConstPool();
1161 }
1162 ~BlockConstPoolScope() {
1163 assem_->EndBlockConstPool();
1164 }
1165
1166 private:
1167 Assembler* assem_;
1168
1169 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstPoolScope);
1170 };
1171
Steve Blocka7e24c12009-10-30 11:49:00 +00001172 // Debugging
1173
1174 // Mark address of the ExitJSFrame code.
1175 void RecordJSReturn();
1176
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001177 // Mark address of a debug break slot.
1178 void RecordDebugBreakSlot();
1179
Ben Murdoch257744e2011-11-30 15:57:28 +00001180 // Record the AST id of the CallIC being compiled, so that it can be placed
1181 // in the relocation information.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001182 void SetRecordedAstId(unsigned ast_id) {
1183 ASSERT(recorded_ast_id_ == kNoASTId);
1184 recorded_ast_id_ = ast_id;
1185 }
1186
1187 unsigned RecordedAstId() {
1188 ASSERT(recorded_ast_id_ != kNoASTId);
1189 return recorded_ast_id_;
1190 }
1191
1192 void ClearRecordedAstId() { recorded_ast_id_ = kNoASTId; }
Ben Murdoch257744e2011-11-30 15:57:28 +00001193
Steve Blocka7e24c12009-10-30 11:49:00 +00001194 // Record a comment relocation entry that can be used by a disassembler.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001195 // Use --code-comments to enable.
Steve Blocka7e24c12009-10-30 11:49:00 +00001196 void RecordComment(const char* msg);
1197
Ben Murdochb8e0da22011-05-16 14:20:40 +01001198 // Writes a single byte or word of data in the code stream. Used
1199 // for inline tables, e.g., jump-tables. The constant pool should be
1200 // emitted before any use of db and dd to ensure that constant pools
1201 // are not emitted as part of the tables generated.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001202 void db(uint8_t data);
1203 void dd(uint32_t data);
1204
Steve Blocka7e24c12009-10-30 11:49:00 +00001205 int pc_offset() const { return pc_ - buffer_; }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001206
1207 PositionsRecorder* positions_recorder() { return &positions_recorder_; }
Steve Block6ded16b2010-05-10 14:33:55 +01001208
1209 // Read/patch instructions
1210 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
1211 static void instr_at_put(byte* pc, Instr instr) {
1212 *reinterpret_cast<Instr*>(pc) = instr;
1213 }
Steve Block1e0659c2011-05-24 12:43:12 +01001214 static Condition GetCondition(Instr instr);
Steve Block6ded16b2010-05-10 14:33:55 +01001215 static bool IsBranch(Instr instr);
1216 static int GetBranchOffset(Instr instr);
1217 static bool IsLdrRegisterImmediate(Instr instr);
1218 static int GetLdrRegisterImmediateOffset(Instr instr);
1219 static Instr SetLdrRegisterImmediateOffset(Instr instr, int offset);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001220 static bool IsStrRegisterImmediate(Instr instr);
1221 static Instr SetStrRegisterImmediateOffset(Instr instr, int offset);
1222 static bool IsAddRegisterImmediate(Instr instr);
1223 static Instr SetAddRegisterImmediateOffset(Instr instr, int offset);
Leon Clarkef7060e22010-06-03 12:02:55 +01001224 static Register GetRd(Instr instr);
Steve Block1e0659c2011-05-24 12:43:12 +01001225 static Register GetRn(Instr instr);
1226 static Register GetRm(Instr instr);
Leon Clarkef7060e22010-06-03 12:02:55 +01001227 static bool IsPush(Instr instr);
1228 static bool IsPop(Instr instr);
1229 static bool IsStrRegFpOffset(Instr instr);
1230 static bool IsLdrRegFpOffset(Instr instr);
1231 static bool IsStrRegFpNegOffset(Instr instr);
1232 static bool IsLdrRegFpNegOffset(Instr instr);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001233 static bool IsLdrPcImmediateOffset(Instr instr);
Steve Block1e0659c2011-05-24 12:43:12 +01001234 static bool IsTstImmediate(Instr instr);
1235 static bool IsCmpRegister(Instr instr);
1236 static bool IsCmpImmediate(Instr instr);
1237 static Register GetCmpImmediateRegister(Instr instr);
1238 static int GetCmpImmediateRawImmediate(Instr instr);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001239 static bool IsNop(Instr instr, int type = NON_MARKING_NOP);
Steve Block6ded16b2010-05-10 14:33:55 +01001240
Ben Murdoch257744e2011-11-30 15:57:28 +00001241 // Constants in pools are accessed via pc relative addressing, which can
1242 // reach +/-4KB thereby defining a maximum distance between the instruction
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001243 // and the accessed constant.
1244 static const int kMaxDistToPool = 4*KB;
1245 static const int kMaxNumPendingRelocInfo = kMaxDistToPool/kInstrSize;
Ben Murdoch257744e2011-11-30 15:57:28 +00001246
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001247 // Postpone the generation of the constant pool for the specified number of
1248 // instructions.
1249 void BlockConstPoolFor(int instructions);
1250
1251 // Check if is time to emit a constant pool.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001252 void CheckConstPool(bool force_emit, bool require_jump);
Steve Blocka7e24c12009-10-30 11:49:00 +00001253
1254 protected:
Ben Murdoch257744e2011-11-30 15:57:28 +00001255 // Relocation for a type-recording IC has the AST id added to it. This
1256 // member variable is a way to pass the information from the call site to
1257 // the relocation info.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001258 unsigned recorded_ast_id_;
Ben Murdoch257744e2011-11-30 15:57:28 +00001259
Steve Block44f0eee2011-05-26 01:26:41 +01001260 bool emit_debug_code() const { return emit_debug_code_; }
1261
Steve Blocka7e24c12009-10-30 11:49:00 +00001262 int buffer_space() const { return reloc_info_writer.pos() - pc_; }
1263
1264 // Read/patch instructions
Steve Blocka7e24c12009-10-30 11:49:00 +00001265 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
1266 void instr_at_put(int pos, Instr instr) {
1267 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
1268 }
1269
1270 // Decode branch instruction at pos and return branch target pos
1271 int target_at(int pos);
1272
1273 // Patch branch instruction at pos to branch to given branch target pos
1274 void target_at_put(int pos, int target_pos);
1275
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001276 // Prevent contant pool emission until EndBlockConstPool is called.
1277 // Call to this function can be nested but must be followed by an equal
1278 // number of call to EndBlockConstpool.
1279 void StartBlockConstPool() {
1280 if (const_pool_blocked_nesting_++ == 0) {
1281 // Prevent constant pool checks happening by setting the next check to
1282 // the biggest possible offset.
1283 next_buffer_check_ = kMaxInt;
1284 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001285 }
1286
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001287 // Resume constant pool emission. Need to be called as many time as
1288 // StartBlockConstPool to have an effect.
Steve Block6ded16b2010-05-10 14:33:55 +01001289 void EndBlockConstPool() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001290 if (--const_pool_blocked_nesting_ == 0) {
1291 // Check the constant pool hasn't been blocked for too long.
1292 ASSERT((num_pending_reloc_info_ == 0) ||
1293 (pc_offset() < (first_const_pool_use_ + kMaxDistToPool)));
1294 // Two cases:
1295 // * no_const_pool_before_ >= next_buffer_check_ and the emission is
1296 // still blocked
1297 // * no_const_pool_before_ < next_buffer_check_ and the next emit will
1298 // trigger a check.
1299 next_buffer_check_ = no_const_pool_before_;
1300 }
Steve Block6ded16b2010-05-10 14:33:55 +01001301 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001302
1303 bool is_const_pool_blocked() const {
1304 return (const_pool_blocked_nesting_ > 0) ||
1305 (pc_offset() < no_const_pool_before_);
1306 }
Steve Block6ded16b2010-05-10 14:33:55 +01001307
Steve Blocka7e24c12009-10-30 11:49:00 +00001308 private:
1309 // Code buffer:
1310 // The buffer into which code and relocation info are generated.
1311 byte* buffer_;
1312 int buffer_size_;
1313 // True if the assembler owns the buffer, false if buffer is external.
1314 bool own_buffer_;
1315
Steve Blocka7e24c12009-10-30 11:49:00 +00001316 int next_buffer_check_; // pc offset of next buffer check
1317
1318 // Code generation
1319 // The relocation writer's position is at least kGap bytes below the end of
1320 // the generated instructions. This is so that multi-instruction sequences do
1321 // not have to check for overflow. The same is true for writes of large
1322 // relocation info entries.
1323 static const int kGap = 32;
1324 byte* pc_; // the program counter; moves forward
1325
1326 // Constant pool generation
1327 // Pools are emitted in the instruction stream, preferably after unconditional
1328 // jumps or after returns from functions (in dead code locations).
1329 // If a long code sequence does not contain unconditional jumps, it is
1330 // necessary to emit the constant pool before the pool gets too far from the
1331 // location it is accessed from. In this case, we emit a jump over the emitted
1332 // constant pool.
1333 // Constants in the pool may be addresses of functions that gets relocated;
1334 // if so, a relocation info entry is associated to the constant pool entry.
1335
1336 // Repeated checking whether the constant pool should be emitted is rather
1337 // expensive. By default we only check again once a number of instructions
1338 // has been generated. That also means that the sizing of the buffers is not
1339 // an exact science, and that we rely on some slop to not overrun buffers.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001340 static const int kCheckPoolIntervalInst = 32;
1341 static const int kCheckPoolInterval = kCheckPoolIntervalInst * kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +00001342
1343
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001344 // Average distance beetween a constant pool and the first instruction
1345 // accessing the constant pool. Longer distance should result in less I-cache
1346 // pollution.
1347 // In practice the distance will be smaller since constant pool emission is
1348 // forced after function return and sometimes after unconditional branches.
1349 static const int kAvgDistToPool = kMaxDistToPool - kCheckPoolInterval;
Steve Blocka7e24c12009-10-30 11:49:00 +00001350
Steve Block6ded16b2010-05-10 14:33:55 +01001351 // Emission of the constant pool may be blocked in some code sequences.
1352 int const_pool_blocked_nesting_; // Block emission if this is not zero.
1353 int no_const_pool_before_; // Block emission before this pc offset.
Steve Blocka7e24c12009-10-30 11:49:00 +00001354
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001355 // Keep track of the first instruction requiring a constant pool entry
1356 // since the previous constant pool was emitted.
1357 int first_const_pool_use_;
Steve Blocka7e24c12009-10-30 11:49:00 +00001358
1359 // Relocation info generation
1360 // Each relocation is encoded as a variable size value
1361 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1362 RelocInfoWriter reloc_info_writer;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001363
Steve Blocka7e24c12009-10-30 11:49:00 +00001364 // Relocation info records are also used during code generation as temporary
1365 // containers for constants and code target addresses until they are emitted
1366 // to the constant pool. These pending relocation info records are temporarily
1367 // stored in a separate buffer until a constant pool is emitted.
1368 // If every instruction in a long sequence is accessing the pool, we need one
1369 // pending relocation entry per instruction.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001370
1371 // the buffer of pending relocation info
1372 RelocInfo pending_reloc_info_[kMaxNumPendingRelocInfo];
1373 // number of pending reloc info entries in the buffer
1374 int num_pending_reloc_info_;
Steve Blocka7e24c12009-10-30 11:49:00 +00001375
1376 // The bound position, before this we cannot do instruction elimination.
1377 int last_bound_pos_;
1378
Steve Blocka7e24c12009-10-30 11:49:00 +00001379 // Code emission
1380 inline void CheckBuffer();
1381 void GrowBuffer();
1382 inline void emit(Instr x);
1383
1384 // Instruction generation
1385 void addrmod1(Instr instr, Register rn, Register rd, const Operand& x);
1386 void addrmod2(Instr instr, Register rd, const MemOperand& x);
1387 void addrmod3(Instr instr, Register rd, const MemOperand& x);
1388 void addrmod4(Instr instr, Register rn, RegList rl);
1389 void addrmod5(Instr instr, CRegister crd, const MemOperand& x);
1390
1391 // Labels
1392 void print(Label* L);
1393 void bind_to(Label* L, int pos);
1394 void link_to(Label* L, Label* appendix);
1395 void next(Label* L);
1396
1397 // Record reloc info for current pc_
1398 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
1399
1400 friend class RegExpMacroAssemblerARM;
1401 friend class RelocInfo;
1402 friend class CodePatcher;
Steve Block6ded16b2010-05-10 14:33:55 +01001403 friend class BlockConstPoolScope;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001404
1405 PositionsRecorder positions_recorder_;
Steve Block44f0eee2011-05-26 01:26:41 +01001406 bool emit_debug_code_;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001407 friend class PositionsRecorder;
1408 friend class EnsureSpace;
Steve Blocka7e24c12009-10-30 11:49:00 +00001409};
1410
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001411
1412class EnsureSpace BASE_EMBEDDED {
1413 public:
1414 explicit EnsureSpace(Assembler* assembler) {
1415 assembler->CheckBuffer();
1416 }
1417};
1418
1419
Steve Blocka7e24c12009-10-30 11:49:00 +00001420} } // namespace v8::internal
1421
1422#endif // V8_ARM_ASSEMBLER_ARM_H_