blob: 9a586936fe0c8d14f5d86341b9da833fb0841c23 [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 Murdoch8b112d22011-06-08 16:22:53 +010035// Copyright 2011 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
179 static int ToAllocationIndex(DwVfpRegister reg) {
180 ASSERT(reg.code() != 0);
181 return reg.code() - 1;
182 }
183
184 static DwVfpRegister FromAllocationIndex(int index) {
185 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
186 return from_code(index + 1);
187 }
188
189 static const char* AllocationIndexToString(int index) {
190 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
191 const char* const names[] = {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000192 "d0",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100193 "d1",
194 "d2",
195 "d3",
196 "d4",
197 "d5",
198 "d6",
199 "d7",
200 "d8",
201 "d9",
202 "d10",
203 "d11",
204 "d12",
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000205 "d13"
Ben Murdochb0fe1622011-05-05 13:52:32 +0100206 };
207 return names[index];
208 }
209
210 static DwVfpRegister from_code(int code) {
211 DwVfpRegister r = { code };
212 return r;
213 }
214
Leon Clarkee46be812010-01-19 14:06:41 +0000215 // Supporting d0 to d15, can be later extended to d31.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100216 bool is_valid() const { return 0 <= code_ && code_ < 16; }
217 bool is(DwVfpRegister reg) const { return code_ == reg.code_; }
218 SwVfpRegister low() const {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100219 SwVfpRegister reg;
220 reg.code_ = code_ * 2;
221
222 ASSERT(reg.is_valid());
223 return reg;
224 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100225 SwVfpRegister high() const {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100226 SwVfpRegister reg;
227 reg.code_ = (code_ * 2) + 1;
228
229 ASSERT(reg.is_valid());
230 return reg;
231 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100232 int code() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000233 ASSERT(is_valid());
234 return code_;
235 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100236 int bit() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000237 ASSERT(is_valid());
238 return 1 << code_;
239 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100240 void split_code(int* vm, int* m) const {
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100241 ASSERT(is_valid());
242 *m = (code_ & 0x10) >> 4;
243 *vm = code_ & 0x0F;
244 }
Leon Clarkee46be812010-01-19 14:06:41 +0000245
246 int code_;
247};
248
249
Ben Murdochb0fe1622011-05-05 13:52:32 +0100250typedef DwVfpRegister DoubleRegister;
251
252
Steve Block6ded16b2010-05-10 14:33:55 +0100253// Support for the VFP registers s0 to s31 (d0 to d15).
Leon Clarkee46be812010-01-19 14:06:41 +0000254// Note that "s(N):s(N+1)" is the same as "d(N/2)".
Steve Block6ded16b2010-05-10 14:33:55 +0100255const SwVfpRegister s0 = { 0 };
256const SwVfpRegister s1 = { 1 };
257const SwVfpRegister s2 = { 2 };
258const SwVfpRegister s3 = { 3 };
259const SwVfpRegister s4 = { 4 };
260const SwVfpRegister s5 = { 5 };
261const SwVfpRegister s6 = { 6 };
262const SwVfpRegister s7 = { 7 };
263const SwVfpRegister s8 = { 8 };
264const SwVfpRegister s9 = { 9 };
265const SwVfpRegister s10 = { 10 };
266const SwVfpRegister s11 = { 11 };
267const SwVfpRegister s12 = { 12 };
268const SwVfpRegister s13 = { 13 };
269const SwVfpRegister s14 = { 14 };
270const SwVfpRegister s15 = { 15 };
271const SwVfpRegister s16 = { 16 };
272const SwVfpRegister s17 = { 17 };
273const SwVfpRegister s18 = { 18 };
274const SwVfpRegister s19 = { 19 };
275const SwVfpRegister s20 = { 20 };
276const SwVfpRegister s21 = { 21 };
277const SwVfpRegister s22 = { 22 };
278const SwVfpRegister s23 = { 23 };
279const SwVfpRegister s24 = { 24 };
280const SwVfpRegister s25 = { 25 };
281const SwVfpRegister s26 = { 26 };
282const SwVfpRegister s27 = { 27 };
283const SwVfpRegister s28 = { 28 };
284const SwVfpRegister s29 = { 29 };
285const SwVfpRegister s30 = { 30 };
286const SwVfpRegister s31 = { 31 };
Leon Clarkee46be812010-01-19 14:06:41 +0000287
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100288const DwVfpRegister no_dreg = { -1 };
Steve Block6ded16b2010-05-10 14:33:55 +0100289const DwVfpRegister d0 = { 0 };
290const DwVfpRegister d1 = { 1 };
291const DwVfpRegister d2 = { 2 };
292const DwVfpRegister d3 = { 3 };
293const DwVfpRegister d4 = { 4 };
294const DwVfpRegister d5 = { 5 };
295const DwVfpRegister d6 = { 6 };
296const DwVfpRegister d7 = { 7 };
297const DwVfpRegister d8 = { 8 };
298const DwVfpRegister d9 = { 9 };
299const DwVfpRegister d10 = { 10 };
300const DwVfpRegister d11 = { 11 };
301const DwVfpRegister d12 = { 12 };
302const DwVfpRegister d13 = { 13 };
303const DwVfpRegister d14 = { 14 };
304const DwVfpRegister d15 = { 15 };
Leon Clarkee46be812010-01-19 14:06:41 +0000305
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +0100306// Aliases for double registers.
307const DwVfpRegister kFirstCalleeSavedDoubleReg = d8;
308const DwVfpRegister kLastCalleeSavedDoubleReg = d15;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000309const DwVfpRegister kDoubleRegZero = d14;
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +0100310
Steve Blocka7e24c12009-10-30 11:49:00 +0000311
312// Coprocessor register
313struct CRegister {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100314 bool is_valid() const { return 0 <= code_ && code_ < 16; }
315 bool is(CRegister creg) const { return code_ == creg.code_; }
316 int code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000317 ASSERT(is_valid());
318 return code_;
319 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100320 int bit() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000321 ASSERT(is_valid());
322 return 1 << code_;
323 }
324
Andrei Popescu31002712010-02-23 13:46:05 +0000325 // Unfortunately we can't make this private in a struct.
Steve Blocka7e24c12009-10-30 11:49:00 +0000326 int code_;
327};
328
329
Steve Block6ded16b2010-05-10 14:33:55 +0100330const CRegister no_creg = { -1 };
331
332const CRegister cr0 = { 0 };
333const CRegister cr1 = { 1 };
334const CRegister cr2 = { 2 };
335const CRegister cr3 = { 3 };
336const CRegister cr4 = { 4 };
337const CRegister cr5 = { 5 };
338const CRegister cr6 = { 6 };
339const CRegister cr7 = { 7 };
340const CRegister cr8 = { 8 };
341const CRegister cr9 = { 9 };
342const CRegister cr10 = { 10 };
343const CRegister cr11 = { 11 };
344const CRegister cr12 = { 12 };
345const CRegister cr13 = { 13 };
346const CRegister cr14 = { 14 };
347const CRegister cr15 = { 15 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000348
349
350// Coprocessor number
351enum Coprocessor {
352 p0 = 0,
353 p1 = 1,
354 p2 = 2,
355 p3 = 3,
356 p4 = 4,
357 p5 = 5,
358 p6 = 6,
359 p7 = 7,
360 p8 = 8,
361 p9 = 9,
362 p10 = 10,
363 p11 = 11,
364 p12 = 12,
365 p13 = 13,
366 p14 = 14,
367 p15 = 15
368};
369
370
Steve Blocka7e24c12009-10-30 11:49:00 +0000371// -----------------------------------------------------------------------------
372// Machine instruction Operands
373
374// Class Operand represents a shifter operand in data processing instructions
375class Operand BASE_EMBEDDED {
376 public:
377 // immediate
378 INLINE(explicit Operand(int32_t immediate,
379 RelocInfo::Mode rmode = RelocInfo::NONE));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000380 INLINE(static Operand Zero()) {
381 return Operand(static_cast<int32_t>(0));
382 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000383 INLINE(explicit Operand(const ExternalReference& f));
Steve Blocka7e24c12009-10-30 11:49:00 +0000384 explicit Operand(Handle<Object> handle);
385 INLINE(explicit Operand(Smi* value));
386
387 // rm
388 INLINE(explicit Operand(Register rm));
389
390 // rm <shift_op> shift_imm
391 explicit Operand(Register rm, ShiftOp shift_op, int shift_imm);
392
393 // rm <shift_op> rs
394 explicit Operand(Register rm, ShiftOp shift_op, Register rs);
395
396 // Return true if this is a register operand.
397 INLINE(bool is_reg() const);
398
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100399 // Return true if this operand fits in one instruction so that no
Steve Block44f0eee2011-05-26 01:26:41 +0100400 // 2-instruction solution with a load into the ip register is necessary. If
401 // the instruction this operand is used for is a MOV or MVN instruction the
402 // actual instruction to use is required for this calculation. For other
403 // instructions instr is ignored.
404 bool is_single_instruction(Instr instr = 0) const;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800405 bool must_use_constant_pool() const;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100406
407 inline int32_t immediate() const {
408 ASSERT(!rm_.is_valid());
409 return imm32_;
410 }
411
Steve Blocka7e24c12009-10-30 11:49:00 +0000412 Register rm() const { return rm_; }
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100413 Register rs() const { return rs_; }
414 ShiftOp shift_op() const { return shift_op_; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000415
416 private:
417 Register rm_;
418 Register rs_;
419 ShiftOp shift_op_;
420 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
421 int32_t imm32_; // valid if rm_ == no_reg
422 RelocInfo::Mode rmode_;
423
424 friend class Assembler;
425};
426
427
428// Class MemOperand represents a memory operand in load and store instructions
429class MemOperand BASE_EMBEDDED {
430 public:
431 // [rn +/- offset] Offset/NegOffset
432 // [rn +/- offset]! PreIndex/NegPreIndex
433 // [rn], +/- offset PostIndex/NegPostIndex
434 // offset is any signed 32-bit value; offset is first loaded to register ip if
435 // it does not fit the addressing mode (12-bit unsigned and sign bit)
436 explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset);
437
438 // [rn +/- rm] Offset/NegOffset
439 // [rn +/- rm]! PreIndex/NegPreIndex
440 // [rn], +/- rm PostIndex/NegPostIndex
441 explicit MemOperand(Register rn, Register rm, AddrMode am = Offset);
442
443 // [rn +/- rm <shift_op> shift_imm] Offset/NegOffset
444 // [rn +/- rm <shift_op> shift_imm]! PreIndex/NegPreIndex
445 // [rn], +/- rm <shift_op> shift_imm PostIndex/NegPostIndex
446 explicit MemOperand(Register rn, Register rm,
447 ShiftOp shift_op, int shift_imm, AddrMode am = Offset);
448
Kristian Monsen25f61362010-05-21 11:50:48 +0100449 void set_offset(int32_t offset) {
450 ASSERT(rm_.is(no_reg));
451 offset_ = offset;
452 }
453
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100454 uint32_t offset() const {
Kristian Monsen25f61362010-05-21 11:50:48 +0100455 ASSERT(rm_.is(no_reg));
456 return offset_;
457 }
458
Leon Clarkef7060e22010-06-03 12:02:55 +0100459 Register rn() const { return rn_; }
460 Register rm() const { return rm_; }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000461 AddrMode am() const { return am_; }
Kristian Monsen25f61362010-05-21 11:50:48 +0100462
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100463 bool OffsetIsUint12Encodable() const {
464 return offset_ >= 0 ? is_uint12(offset_) : is_uint12(-offset_);
465 }
466
Steve Blocka7e24c12009-10-30 11:49:00 +0000467 private:
468 Register rn_; // base
469 Register rm_; // register offset
470 int32_t offset_; // valid if rm_ == no_reg
471 ShiftOp shift_op_;
472 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
473 AddrMode am_; // bits P, U, and W
474
475 friend class Assembler;
476};
477
Steve Blockd0582a62009-12-15 09:54:21 +0000478// CpuFeatures keeps track of which features are supported by the target CPU.
479// Supported features must be enabled by a Scope before use.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100480class CpuFeatures : public AllStatic {
Steve Blockd0582a62009-12-15 09:54:21 +0000481 public:
482 // Detect features of the target CPU. Set safe defaults if the serializer
483 // is enabled (snapshots must be portable).
Ben Murdoch8b112d22011-06-08 16:22:53 +0100484 static void Probe();
Steve Blockd0582a62009-12-15 09:54:21 +0000485
486 // Check whether a feature is supported by the target CPU.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100487 static bool IsSupported(CpuFeature f) {
488 ASSERT(initialized_);
Steve Blockd0582a62009-12-15 09:54:21 +0000489 if (f == VFP3 && !FLAG_enable_vfp3) return false;
490 return (supported_ & (1u << f)) != 0;
491 }
492
Ben Murdoch8b112d22011-06-08 16:22:53 +0100493#ifdef DEBUG
Steve Blockd0582a62009-12-15 09:54:21 +0000494 // Check whether a feature is currently enabled.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100495 static bool IsEnabled(CpuFeature f) {
496 ASSERT(initialized_);
497 Isolate* isolate = Isolate::UncheckedCurrent();
498 if (isolate == NULL) {
499 // When no isolate is available, work as if we're running in
500 // release mode.
501 return IsSupported(f);
502 }
503 unsigned enabled = static_cast<unsigned>(isolate->enabled_cpu_features());
504 return (enabled & (1u << f)) != 0;
Steve Blockd0582a62009-12-15 09:54:21 +0000505 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100506#endif
Steve Blockd0582a62009-12-15 09:54:21 +0000507
508 // Enable a specified feature within a scope.
509 class Scope BASE_EMBEDDED {
510#ifdef DEBUG
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000511
Steve Blockd0582a62009-12-15 09:54:21 +0000512 public:
Ben Murdoch8b112d22011-06-08 16:22:53 +0100513 explicit Scope(CpuFeature f) {
514 unsigned mask = 1u << f;
515 ASSERT(CpuFeatures::IsSupported(f));
Steve Blockd0582a62009-12-15 09:54:21 +0000516 ASSERT(!Serializer::enabled() ||
Ben Murdoch8b112d22011-06-08 16:22:53 +0100517 (CpuFeatures::found_by_runtime_probing_ & mask) == 0);
518 isolate_ = Isolate::UncheckedCurrent();
519 old_enabled_ = 0;
520 if (isolate_ != NULL) {
521 old_enabled_ = static_cast<unsigned>(isolate_->enabled_cpu_features());
522 isolate_->set_enabled_cpu_features(old_enabled_ | mask);
523 }
Steve Blockd0582a62009-12-15 09:54:21 +0000524 }
Steve Block44f0eee2011-05-26 01:26:41 +0100525 ~Scope() {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100526 ASSERT_EQ(Isolate::UncheckedCurrent(), isolate_);
527 if (isolate_ != NULL) {
528 isolate_->set_enabled_cpu_features(old_enabled_);
529 }
Steve Block44f0eee2011-05-26 01:26:41 +0100530 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000531
Steve Blockd0582a62009-12-15 09:54:21 +0000532 private:
Steve Block44f0eee2011-05-26 01:26:41 +0100533 Isolate* isolate_;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100534 unsigned old_enabled_;
Steve Blockd0582a62009-12-15 09:54:21 +0000535#else
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000536
Steve Blockd0582a62009-12-15 09:54:21 +0000537 public:
538 explicit Scope(CpuFeature f) {}
539#endif
540 };
541
Ben Murdoch8b112d22011-06-08 16:22:53 +0100542 class TryForceFeatureScope BASE_EMBEDDED {
543 public:
544 explicit TryForceFeatureScope(CpuFeature f)
545 : old_supported_(CpuFeatures::supported_) {
546 if (CanForce()) {
547 CpuFeatures::supported_ |= (1u << f);
548 }
549 }
550
551 ~TryForceFeatureScope() {
552 if (CanForce()) {
553 CpuFeatures::supported_ = old_supported_;
554 }
555 }
556
557 private:
558 static bool CanForce() {
559 // It's only safe to temporarily force support of CPU features
560 // when there's only a single isolate, which is guaranteed when
561 // the serializer is enabled.
562 return Serializer::enabled();
563 }
564
565 const unsigned old_supported_;
566 };
567
Steve Blockd0582a62009-12-15 09:54:21 +0000568 private:
Ben Murdoch8b112d22011-06-08 16:22:53 +0100569#ifdef DEBUG
570 static bool initialized_;
571#endif
572 static unsigned supported_;
573 static unsigned found_by_runtime_probing_;
Steve Block44f0eee2011-05-26 01:26:41 +0100574
575 DISALLOW_COPY_AND_ASSIGN(CpuFeatures);
Steve Blockd0582a62009-12-15 09:54:21 +0000576};
577
Steve Blocka7e24c12009-10-30 11:49:00 +0000578
Steve Blocka7e24c12009-10-30 11:49:00 +0000579extern const Instr kMovLrPc;
Steve Block6ded16b2010-05-10 14:33:55 +0100580extern const Instr kLdrPCMask;
Steve Blocka7e24c12009-10-30 11:49:00 +0000581extern const Instr kLdrPCPattern;
Steve Block6ded16b2010-05-10 14:33:55 +0100582extern const Instr kBlxRegMask;
583extern const Instr kBlxRegPattern;
Steve Blocka7e24c12009-10-30 11:49:00 +0000584
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100585extern const Instr kMovMvnMask;
586extern const Instr kMovMvnPattern;
587extern const Instr kMovMvnFlip;
588
589extern const Instr kMovLeaveCCMask;
590extern const Instr kMovLeaveCCPattern;
591extern const Instr kMovwMask;
592extern const Instr kMovwPattern;
593extern const Instr kMovwLeaveCCFlip;
594
595extern const Instr kCmpCmnMask;
596extern const Instr kCmpCmnPattern;
597extern const Instr kCmpCmnFlip;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100598extern const Instr kAddSubFlip;
599extern const Instr kAndBicFlip;
Steve Blocka7e24c12009-10-30 11:49:00 +0000600
Steve Block1e0659c2011-05-24 12:43:12 +0100601
602
Steve Block44f0eee2011-05-26 01:26:41 +0100603class Assembler : public AssemblerBase {
Steve Blocka7e24c12009-10-30 11:49:00 +0000604 public:
605 // Create an assembler. Instructions and relocation information are emitted
606 // into a buffer, with the instructions starting from the beginning and the
607 // relocation information starting from the end of the buffer. See CodeDesc
608 // for a detailed comment on the layout (globals.h).
609 //
610 // If the provided buffer is NULL, the assembler allocates and grows its own
611 // buffer, and buffer_size determines the initial buffer size. The buffer is
612 // owned by the assembler and deallocated upon destruction of the assembler.
613 //
614 // If the provided buffer is not NULL, the assembler uses the provided buffer
615 // for code generation and assumes its size to be buffer_size. If the buffer
616 // is too small, a fatal error occurs. No deallocation of the buffer is done
617 // upon destruction of the assembler.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100618 Assembler(Isolate* isolate, void* buffer, int buffer_size);
Steve Blocka7e24c12009-10-30 11:49:00 +0000619 ~Assembler();
620
Steve Block44f0eee2011-05-26 01:26:41 +0100621 // Overrides the default provided by FLAG_debug_code.
622 void set_emit_debug_code(bool value) { emit_debug_code_ = value; }
623
Steve Blocka7e24c12009-10-30 11:49:00 +0000624 // GetCode emits any pending (non-emitted) code and fills the descriptor
625 // desc. GetCode() is idempotent; it returns the same result if no other
626 // Assembler functions are invoked in between GetCode() calls.
627 void GetCode(CodeDesc* desc);
628
629 // Label operations & relative jumps (PPUM Appendix D)
630 //
631 // Takes a branch opcode (cc) and a label (L) and generates
632 // either a backward branch or a forward branch and links it
633 // to the label fixup chain. Usage:
634 //
635 // Label L; // unbound label
636 // j(cc, &L); // forward branch to unbound label
637 // bind(&L); // bind label to the current pc
638 // j(cc, &L); // backward branch to bound label
639 // bind(&L); // illegal: a label may be bound only once
640 //
641 // Note: The same Label can be used for forward and backward branches
642 // but it may be bound only once.
643
644 void bind(Label* L); // binds an unbound label L to the current code position
645
646 // Returns the branch offset to the given label from the current code position
647 // Links the label to the current position if it is still unbound
648 // Manages the jump elimination optimization if the second parameter is true.
649 int branch_offset(Label* L, bool jump_elimination_allowed);
650
651 // Puts a labels target address at the given position.
652 // The high 8 bits are set to zero.
653 void label_at_put(Label* L, int at_offset);
654
655 // Return the address in the constant pool of the code target address used by
656 // the branch/call instruction at pc.
657 INLINE(static Address target_address_address_at(Address pc));
658
659 // Read/Modify the code target address in the branch/call instruction at pc.
660 INLINE(static Address target_address_at(Address pc));
661 INLINE(static void set_target_address_at(Address pc, Address target));
662
Steve Blockd0582a62009-12-15 09:54:21 +0000663 // This sets the branch destination (which is in the constant pool on ARM).
664 // This is for calls and branches within generated code.
665 inline static void set_target_at(Address constant_pool_entry, Address target);
666
667 // This sets the branch destination (which is in the constant pool on ARM).
668 // This is for calls and branches to runtime code.
669 inline static void set_external_target_at(Address constant_pool_entry,
670 Address target) {
671 set_target_at(constant_pool_entry, target);
672 }
673
674 // Here we are patching the address in the constant pool, not the actual call
675 // instruction. The address in the constant pool is the same size as a
676 // pointer.
677 static const int kCallTargetSize = kPointerSize;
678 static const int kExternalTargetSize = kPointerSize;
679
Steve Blocka7e24c12009-10-30 11:49:00 +0000680 // Size of an instruction.
681 static const int kInstrSize = sizeof(Instr);
682
683 // Distance between the instruction referring to the address of the call
Steve Block6ded16b2010-05-10 14:33:55 +0100684 // target and the return address.
685#ifdef USE_BLX
686 // Call sequence is:
687 // ldr ip, [pc, #...] @ call address
688 // blx ip
689 // @ return address
690 static const int kCallTargetAddressOffset = 2 * kInstrSize;
691#else
692 // Call sequence is:
693 // mov lr, pc
694 // ldr pc, [pc, #...] @ call address
695 // @ return address
Steve Blocka7e24c12009-10-30 11:49:00 +0000696 static const int kCallTargetAddressOffset = kInstrSize;
Steve Block6ded16b2010-05-10 14:33:55 +0100697#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000698
699 // Distance between start of patched return sequence and the emitted address
700 // to jump to.
Steve Block6ded16b2010-05-10 14:33:55 +0100701#ifdef USE_BLX
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100702 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100703 // ldr ip, [pc, #0] @ emited address and start
704 // blx ip
705 static const int kPatchReturnSequenceAddressOffset = 0 * kInstrSize;
706#else
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100707 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100708 // mov lr, pc @ start of sequence
709 // ldr pc, [pc, #-4] @ emited address
710 static const int kPatchReturnSequenceAddressOffset = kInstrSize;
711#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000712
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100713 // Distance between start of patched debug break slot and the emitted address
714 // to jump to.
715#ifdef USE_BLX
716 // Patched debug break slot code is:
717 // ldr ip, [pc, #0] @ emited address and start
718 // blx ip
719 static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
720#else
721 // Patched debug break slot code is:
722 // mov lr, pc @ start of sequence
723 // ldr pc, [pc, #-4] @ emited address
724 static const int kPatchDebugBreakSlotAddressOffset = kInstrSize;
725#endif
726
Steve Blocka7e24c12009-10-30 11:49:00 +0000727 // Difference between address of current opcode and value read from pc
728 // register.
729 static const int kPcLoadDelta = 8;
730
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100731 static const int kJSReturnSequenceInstructions = 4;
732 static const int kDebugBreakSlotInstructions = 3;
733 static const int kDebugBreakSlotLength =
734 kDebugBreakSlotInstructions * kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +0000735
736 // ---------------------------------------------------------------------------
737 // Code generation
738
739 // Insert the smallest number of nop instructions
740 // possible to align the pc offset to a multiple
741 // of m. m must be a power of 2 (>= 4).
742 void Align(int m);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100743 // Aligns code to something that's optimal for a jump target for the platform.
744 void CodeTargetAlign();
Steve Blocka7e24c12009-10-30 11:49:00 +0000745
746 // Branch instructions
747 void b(int branch_offset, Condition cond = al);
748 void bl(int branch_offset, Condition cond = al);
749 void blx(int branch_offset); // v5 and above
750 void blx(Register target, Condition cond = al); // v5 and above
751 void bx(Register target, Condition cond = al); // v5 and above, plus v4t
752
753 // Convenience branch instructions using labels
754 void b(Label* L, Condition cond = al) {
755 b(branch_offset(L, cond == al), cond);
756 }
757 void b(Condition cond, Label* L) { b(branch_offset(L, cond == al), cond); }
758 void bl(Label* L, Condition cond = al) { bl(branch_offset(L, false), cond); }
759 void bl(Condition cond, Label* L) { bl(branch_offset(L, false), cond); }
760 void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above
761
762 // Data-processing instructions
Andrei Popescu31002712010-02-23 13:46:05 +0000763
Steve Blocka7e24c12009-10-30 11:49:00 +0000764 void and_(Register dst, Register src1, const Operand& src2,
765 SBit s = LeaveCC, Condition cond = al);
766
767 void eor(Register dst, Register src1, const Operand& src2,
768 SBit s = LeaveCC, Condition cond = al);
769
770 void sub(Register dst, Register src1, const Operand& src2,
771 SBit s = LeaveCC, Condition cond = al);
772 void sub(Register dst, Register src1, Register src2,
773 SBit s = LeaveCC, Condition cond = al) {
774 sub(dst, src1, Operand(src2), s, cond);
775 }
776
777 void rsb(Register dst, Register src1, const Operand& src2,
778 SBit s = LeaveCC, Condition cond = al);
779
780 void add(Register dst, Register src1, const Operand& src2,
781 SBit s = LeaveCC, Condition cond = al);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100782 void add(Register dst, Register src1, Register src2,
783 SBit s = LeaveCC, Condition cond = al) {
784 add(dst, src1, Operand(src2), s, cond);
785 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000786
787 void adc(Register dst, Register src1, const Operand& src2,
788 SBit s = LeaveCC, Condition cond = al);
789
790 void sbc(Register dst, Register src1, const Operand& src2,
791 SBit s = LeaveCC, Condition cond = al);
792
793 void rsc(Register dst, Register src1, const Operand& src2,
794 SBit s = LeaveCC, Condition cond = al);
795
796 void tst(Register src1, const Operand& src2, Condition cond = al);
797 void tst(Register src1, Register src2, Condition cond = al) {
798 tst(src1, Operand(src2), cond);
799 }
800
801 void teq(Register src1, const Operand& src2, Condition cond = al);
802
803 void cmp(Register src1, const Operand& src2, Condition cond = al);
804 void cmp(Register src1, Register src2, Condition cond = al) {
805 cmp(src1, Operand(src2), cond);
806 }
Steve Block1e0659c2011-05-24 12:43:12 +0100807 void cmp_raw_immediate(Register src1, int raw_immediate, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000808
809 void cmn(Register src1, const Operand& src2, Condition cond = al);
810
811 void orr(Register dst, Register src1, const Operand& src2,
812 SBit s = LeaveCC, Condition cond = al);
813 void orr(Register dst, Register src1, Register src2,
814 SBit s = LeaveCC, Condition cond = al) {
815 orr(dst, src1, Operand(src2), s, cond);
816 }
817
818 void mov(Register dst, const Operand& src,
819 SBit s = LeaveCC, Condition cond = al);
820 void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
821 mov(dst, Operand(src), s, cond);
822 }
823
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100824 // ARMv7 instructions for loading a 32 bit immediate in two instructions.
825 // This may actually emit a different mov instruction, but on an ARMv7 it
826 // is guaranteed to only emit one instruction.
827 void movw(Register reg, uint32_t immediate, Condition cond = al);
828 // The constant for movt should be in the range 0-0xffff.
829 void movt(Register reg, uint32_t immediate, Condition cond = al);
830
Steve Blocka7e24c12009-10-30 11:49:00 +0000831 void bic(Register dst, Register src1, const Operand& src2,
832 SBit s = LeaveCC, Condition cond = al);
833
834 void mvn(Register dst, const Operand& src,
835 SBit s = LeaveCC, Condition cond = al);
836
837 // Multiply instructions
838
839 void mla(Register dst, Register src1, Register src2, Register srcA,
840 SBit s = LeaveCC, Condition cond = al);
841
842 void mul(Register dst, Register src1, Register src2,
843 SBit s = LeaveCC, Condition cond = al);
844
845 void smlal(Register dstL, Register dstH, Register src1, Register src2,
846 SBit s = LeaveCC, Condition cond = al);
847
848 void smull(Register dstL, Register dstH, Register src1, Register src2,
849 SBit s = LeaveCC, Condition cond = al);
850
851 void umlal(Register dstL, Register dstH, Register src1, Register src2,
852 SBit s = LeaveCC, Condition cond = al);
853
854 void umull(Register dstL, Register dstH, Register src1, Register src2,
855 SBit s = LeaveCC, Condition cond = al);
856
857 // Miscellaneous arithmetic instructions
858
859 void clz(Register dst, Register src, Condition cond = al); // v5 and above
860
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100861 // Saturating instructions. v6 and above.
862
863 // Unsigned saturate.
864 //
865 // Saturate an optionally shifted signed value to an unsigned range.
866 //
867 // usat dst, #satpos, src
868 // usat dst, #satpos, src, lsl #sh
869 // usat dst, #satpos, src, asr #sh
870 //
871 // Register dst will contain:
872 //
873 // 0, if s < 0
874 // (1 << satpos) - 1, if s > ((1 << satpos) - 1)
875 // s, otherwise
876 //
877 // where s is the contents of src after shifting (if used.)
878 void usat(Register dst, int satpos, const Operand& src, Condition cond = al);
879
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100880 // Bitfield manipulation instructions. v7 and above.
881
882 void ubfx(Register dst, Register src, int lsb, int width,
883 Condition cond = al);
884
885 void sbfx(Register dst, Register src, int lsb, int width,
886 Condition cond = al);
887
888 void bfc(Register dst, int lsb, int width, Condition cond = al);
889
890 void bfi(Register dst, Register src, int lsb, int width,
891 Condition cond = al);
892
Steve Blocka7e24c12009-10-30 11:49:00 +0000893 // Status register access instructions
894
895 void mrs(Register dst, SRegister s, Condition cond = al);
896 void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al);
897
898 // Load/Store instructions
899 void ldr(Register dst, const MemOperand& src, Condition cond = al);
900 void str(Register src, const MemOperand& dst, Condition cond = al);
901 void ldrb(Register dst, const MemOperand& src, Condition cond = al);
902 void strb(Register src, const MemOperand& dst, Condition cond = al);
903 void ldrh(Register dst, const MemOperand& src, Condition cond = al);
904 void strh(Register src, const MemOperand& dst, Condition cond = al);
905 void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
906 void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
Leon Clarkef7060e22010-06-03 12:02:55 +0100907 void ldrd(Register dst1,
908 Register dst2,
909 const MemOperand& src, Condition cond = al);
910 void strd(Register src1,
911 Register src2,
912 const MemOperand& dst, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000913
914 // Load/Store multiple instructions
915 void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
916 void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
917
Steve Blocka7e24c12009-10-30 11:49:00 +0000918 // Exception-generating instructions and debugging support
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800919 void stop(const char* msg,
920 Condition cond = al,
921 int32_t code = kDefaultStopCode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000922
923 void bkpt(uint32_t imm16); // v5 and above
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800924 void svc(uint32_t imm24, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000925
926 // Coprocessor instructions
927
928 void cdp(Coprocessor coproc, int opcode_1,
929 CRegister crd, CRegister crn, CRegister crm,
930 int opcode_2, Condition cond = al);
931
932 void cdp2(Coprocessor coproc, int opcode_1,
933 CRegister crd, CRegister crn, CRegister crm,
934 int opcode_2); // v5 and above
935
936 void mcr(Coprocessor coproc, int opcode_1,
937 Register rd, CRegister crn, CRegister crm,
938 int opcode_2 = 0, Condition cond = al);
939
940 void mcr2(Coprocessor coproc, int opcode_1,
941 Register rd, CRegister crn, CRegister crm,
942 int opcode_2 = 0); // v5 and above
943
944 void mrc(Coprocessor coproc, int opcode_1,
945 Register rd, CRegister crn, CRegister crm,
946 int opcode_2 = 0, Condition cond = al);
947
948 void mrc2(Coprocessor coproc, int opcode_1,
949 Register rd, CRegister crn, CRegister crm,
950 int opcode_2 = 0); // v5 and above
951
952 void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src,
953 LFlag l = Short, Condition cond = al);
954 void ldc(Coprocessor coproc, CRegister crd, Register base, int option,
955 LFlag l = Short, Condition cond = al);
956
957 void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
958 LFlag l = Short); // v5 and above
959 void ldc2(Coprocessor coproc, CRegister crd, Register base, int option,
960 LFlag l = Short); // v5 and above
961
Steve Blockd0582a62009-12-15 09:54:21 +0000962 // Support for VFP.
963 // All these APIs support S0 to S31 and D0 to D15.
964 // Currently these APIs do not support extended D registers, i.e, D16 to D31.
965 // However, some simple modifications can allow
966 // these APIs to support D16 to D31.
967
Leon Clarked91b9f72010-01-27 17:25:45 +0000968 void vldr(const DwVfpRegister dst,
969 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100970 int offset,
971 const Condition cond = al);
972 void vldr(const DwVfpRegister dst,
973 const MemOperand& src,
Leon Clarked91b9f72010-01-27 17:25:45 +0000974 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +0100975
976 void vldr(const SwVfpRegister dst,
977 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100978 int offset,
979 const Condition cond = al);
980 void vldr(const SwVfpRegister dst,
981 const MemOperand& src,
Steve Block6ded16b2010-05-10 14:33:55 +0100982 const Condition cond = al);
983
Leon Clarked91b9f72010-01-27 17:25:45 +0000984 void vstr(const DwVfpRegister src,
985 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100986 int offset,
987 const Condition cond = al);
988 void vstr(const DwVfpRegister src,
989 const MemOperand& dst,
Leon Clarked91b9f72010-01-27 17:25:45 +0000990 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +0100991
Iain Merrick75681382010-08-19 15:07:18 +0100992 void vstr(const SwVfpRegister src,
993 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100994 int offset,
995 const Condition cond = al);
996 void vstr(const SwVfpRegister src,
997 const MemOperand& dst,
Iain Merrick75681382010-08-19 15:07:18 +0100998 const Condition cond = al);
999
Ben Murdoch8b112d22011-06-08 16:22:53 +01001000 void vldm(BlockAddrMode am,
1001 Register base,
1002 DwVfpRegister first,
1003 DwVfpRegister last,
1004 Condition cond = al);
1005
1006 void vstm(BlockAddrMode am,
1007 Register base,
1008 DwVfpRegister first,
1009 DwVfpRegister last,
1010 Condition cond = al);
1011
1012 void vldm(BlockAddrMode am,
1013 Register base,
1014 SwVfpRegister first,
1015 SwVfpRegister last,
1016 Condition cond = al);
1017
1018 void vstm(BlockAddrMode am,
1019 Register base,
1020 SwVfpRegister first,
1021 SwVfpRegister last,
1022 Condition cond = al);
1023
Steve Block8defd9f2010-07-08 12:39:36 +01001024 void vmov(const DwVfpRegister dst,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001025 double imm,
1026 const Condition cond = al);
1027 void vmov(const SwVfpRegister dst,
1028 const SwVfpRegister src,
1029 const Condition cond = al);
1030 void vmov(const DwVfpRegister dst,
Steve Block8defd9f2010-07-08 12:39:36 +01001031 const DwVfpRegister src,
1032 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001033 void vmov(const DwVfpRegister dst,
1034 const Register src1,
Steve Blockd0582a62009-12-15 09:54:21 +00001035 const Register src2,
Leon Clarkee46be812010-01-19 14:06:41 +00001036 const Condition cond = al);
1037 void vmov(const Register dst1,
1038 const Register dst2,
1039 const DwVfpRegister src,
1040 const Condition cond = al);
1041 void vmov(const SwVfpRegister dst,
1042 const Register src,
1043 const Condition cond = al);
1044 void vmov(const Register dst,
1045 const SwVfpRegister src,
1046 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +01001047 void vcvt_f64_s32(const DwVfpRegister dst,
1048 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001049 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001050 const Condition cond = al);
1051 void vcvt_f32_s32(const SwVfpRegister dst,
1052 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001053 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001054 const Condition cond = al);
1055 void vcvt_f64_u32(const DwVfpRegister dst,
1056 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001057 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001058 const Condition cond = al);
1059 void vcvt_s32_f64(const SwVfpRegister dst,
1060 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001061 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001062 const Condition cond = al);
1063 void vcvt_u32_f64(const SwVfpRegister dst,
1064 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001065 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001066 const Condition cond = al);
1067 void vcvt_f64_f32(const DwVfpRegister dst,
1068 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001069 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001070 const Condition cond = al);
1071 void vcvt_f32_f64(const SwVfpRegister dst,
1072 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001073 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001074 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001075
Steve Block44f0eee2011-05-26 01:26:41 +01001076 void vneg(const DwVfpRegister dst,
1077 const DwVfpRegister src,
1078 const Condition cond = al);
Steve Block1e0659c2011-05-24 12:43:12 +01001079 void vabs(const DwVfpRegister dst,
1080 const DwVfpRegister src,
1081 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001082 void vadd(const DwVfpRegister dst,
1083 const DwVfpRegister src1,
1084 const DwVfpRegister src2,
1085 const Condition cond = al);
1086 void vsub(const DwVfpRegister dst,
1087 const DwVfpRegister src1,
1088 const DwVfpRegister src2,
1089 const Condition cond = al);
1090 void vmul(const DwVfpRegister dst,
1091 const DwVfpRegister src1,
1092 const DwVfpRegister src2,
1093 const Condition cond = al);
1094 void vdiv(const DwVfpRegister dst,
1095 const DwVfpRegister src1,
1096 const DwVfpRegister src2,
1097 const Condition cond = al);
1098 void vcmp(const DwVfpRegister src1,
1099 const DwVfpRegister src2,
Steve Blockd0582a62009-12-15 09:54:21 +00001100 const Condition cond = al);
Iain Merrick75681382010-08-19 15:07:18 +01001101 void vcmp(const DwVfpRegister src1,
1102 const double src2,
Iain Merrick75681382010-08-19 15:07:18 +01001103 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001104 void vmrs(const Register dst,
1105 const Condition cond = al);
Russell Brenner90bac252010-11-18 13:33:46 -08001106 void vmsr(const Register dst,
1107 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +01001108 void vsqrt(const DwVfpRegister dst,
1109 const DwVfpRegister src,
1110 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001111
Steve Blocka7e24c12009-10-30 11:49:00 +00001112 // Pseudo instructions
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001113
1114 // Different nop operations are used by the code generator to detect certain
1115 // states of the generated code.
1116 enum NopMarkerTypes {
1117 NON_MARKING_NOP = 0,
1118 DEBUG_BREAK_NOP,
1119 // IC markers.
1120 PROPERTY_ACCESS_INLINED,
1121 PROPERTY_ACCESS_INLINED_CONTEXT,
1122 PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE,
1123 // Helper values.
1124 LAST_CODE_MARKER,
1125 FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED
1126 };
1127
1128 void nop(int type = 0); // 0 is the default non-marking type.
Steve Blocka7e24c12009-10-30 11:49:00 +00001129
1130 void push(Register src, Condition cond = al) {
1131 str(src, MemOperand(sp, 4, NegPreIndex), cond);
1132 }
1133
1134 void pop(Register dst, Condition cond = al) {
1135 ldr(dst, MemOperand(sp, 4, PostIndex), cond);
1136 }
1137
1138 void pop() {
1139 add(sp, sp, Operand(kPointerSize));
1140 }
1141
Steve Blocka7e24c12009-10-30 11:49:00 +00001142 // Jump unconditionally to given label.
1143 void jmp(Label* L) { b(L, al); }
1144
1145 // Check the code size generated from label to here.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001146 int SizeOfCodeGeneratedSince(Label* label) {
1147 return pc_offset() - label->pos();
1148 }
1149
1150 // Check the number of instructions generated from label to here.
1151 int InstructionsGeneratedSince(Label* label) {
1152 return SizeOfCodeGeneratedSince(label) / kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +00001153 }
1154
Steve Blockd0582a62009-12-15 09:54:21 +00001155 // Check whether an immediate fits an addressing mode 1 instruction.
1156 bool ImmediateFitsAddrMode1Instruction(int32_t imm32);
1157
Steve Block6ded16b2010-05-10 14:33:55 +01001158 // Class for scoping postponing the constant pool generation.
1159 class BlockConstPoolScope {
1160 public:
1161 explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) {
1162 assem_->StartBlockConstPool();
1163 }
1164 ~BlockConstPoolScope() {
1165 assem_->EndBlockConstPool();
1166 }
1167
1168 private:
1169 Assembler* assem_;
1170
1171 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstPoolScope);
1172 };
1173
Steve Blocka7e24c12009-10-30 11:49:00 +00001174 // Debugging
1175
1176 // Mark address of the ExitJSFrame code.
1177 void RecordJSReturn();
1178
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001179 // Mark address of a debug break slot.
1180 void RecordDebugBreakSlot();
1181
Ben Murdoch257744e2011-11-30 15:57:28 +00001182 // Record the AST id of the CallIC being compiled, so that it can be placed
1183 // in the relocation information.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001184 void SetRecordedAstId(unsigned ast_id) {
1185 ASSERT(recorded_ast_id_ == kNoASTId);
1186 recorded_ast_id_ = ast_id;
1187 }
1188
1189 unsigned RecordedAstId() {
1190 ASSERT(recorded_ast_id_ != kNoASTId);
1191 return recorded_ast_id_;
1192 }
1193
1194 void ClearRecordedAstId() { recorded_ast_id_ = kNoASTId; }
Ben Murdoch257744e2011-11-30 15:57:28 +00001195
Steve Blocka7e24c12009-10-30 11:49:00 +00001196 // Record a comment relocation entry that can be used by a disassembler.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001197 // Use --code-comments to enable.
Steve Blocka7e24c12009-10-30 11:49:00 +00001198 void RecordComment(const char* msg);
1199
Ben Murdochb8e0da22011-05-16 14:20:40 +01001200 // Writes a single byte or word of data in the code stream. Used
1201 // for inline tables, e.g., jump-tables. The constant pool should be
1202 // emitted before any use of db and dd to ensure that constant pools
1203 // are not emitted as part of the tables generated.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001204 void db(uint8_t data);
1205 void dd(uint32_t data);
1206
Steve Blocka7e24c12009-10-30 11:49:00 +00001207 int pc_offset() const { return pc_ - buffer_; }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001208
1209 PositionsRecorder* positions_recorder() { return &positions_recorder_; }
Steve Block6ded16b2010-05-10 14:33:55 +01001210
1211 // Read/patch instructions
1212 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
1213 static void instr_at_put(byte* pc, Instr instr) {
1214 *reinterpret_cast<Instr*>(pc) = instr;
1215 }
Steve Block1e0659c2011-05-24 12:43:12 +01001216 static Condition GetCondition(Instr instr);
Steve Block6ded16b2010-05-10 14:33:55 +01001217 static bool IsBranch(Instr instr);
1218 static int GetBranchOffset(Instr instr);
1219 static bool IsLdrRegisterImmediate(Instr instr);
1220 static int GetLdrRegisterImmediateOffset(Instr instr);
1221 static Instr SetLdrRegisterImmediateOffset(Instr instr, int offset);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001222 static bool IsStrRegisterImmediate(Instr instr);
1223 static Instr SetStrRegisterImmediateOffset(Instr instr, int offset);
1224 static bool IsAddRegisterImmediate(Instr instr);
1225 static Instr SetAddRegisterImmediateOffset(Instr instr, int offset);
Leon Clarkef7060e22010-06-03 12:02:55 +01001226 static Register GetRd(Instr instr);
Steve Block1e0659c2011-05-24 12:43:12 +01001227 static Register GetRn(Instr instr);
1228 static Register GetRm(Instr instr);
Leon Clarkef7060e22010-06-03 12:02:55 +01001229 static bool IsPush(Instr instr);
1230 static bool IsPop(Instr instr);
1231 static bool IsStrRegFpOffset(Instr instr);
1232 static bool IsLdrRegFpOffset(Instr instr);
1233 static bool IsStrRegFpNegOffset(Instr instr);
1234 static bool IsLdrRegFpNegOffset(Instr instr);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001235 static bool IsLdrPcImmediateOffset(Instr instr);
Steve Block1e0659c2011-05-24 12:43:12 +01001236 static bool IsTstImmediate(Instr instr);
1237 static bool IsCmpRegister(Instr instr);
1238 static bool IsCmpImmediate(Instr instr);
1239 static Register GetCmpImmediateRegister(Instr instr);
1240 static int GetCmpImmediateRawImmediate(Instr instr);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001241 static bool IsNop(Instr instr, int type = NON_MARKING_NOP);
Steve Block6ded16b2010-05-10 14:33:55 +01001242
Ben Murdoch257744e2011-11-30 15:57:28 +00001243 // Constants in pools are accessed via pc relative addressing, which can
1244 // reach +/-4KB thereby defining a maximum distance between the instruction
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001245 // and the accessed constant.
1246 static const int kMaxDistToPool = 4*KB;
1247 static const int kMaxNumPendingRelocInfo = kMaxDistToPool/kInstrSize;
Ben Murdoch257744e2011-11-30 15:57:28 +00001248
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001249 // Postpone the generation of the constant pool for the specified number of
1250 // instructions.
1251 void BlockConstPoolFor(int instructions);
1252
1253 // Check if is time to emit a constant pool.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001254 void CheckConstPool(bool force_emit, bool require_jump);
Steve Blocka7e24c12009-10-30 11:49:00 +00001255
1256 protected:
Ben Murdoch257744e2011-11-30 15:57:28 +00001257 // Relocation for a type-recording IC has the AST id added to it. This
1258 // member variable is a way to pass the information from the call site to
1259 // the relocation info.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001260 unsigned recorded_ast_id_;
Ben Murdoch257744e2011-11-30 15:57:28 +00001261
Steve Block44f0eee2011-05-26 01:26:41 +01001262 bool emit_debug_code() const { return emit_debug_code_; }
1263
Steve Blocka7e24c12009-10-30 11:49:00 +00001264 int buffer_space() const { return reloc_info_writer.pos() - pc_; }
1265
1266 // Read/patch instructions
Steve Blocka7e24c12009-10-30 11:49:00 +00001267 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
1268 void instr_at_put(int pos, Instr instr) {
1269 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
1270 }
1271
1272 // Decode branch instruction at pos and return branch target pos
1273 int target_at(int pos);
1274
1275 // Patch branch instruction at pos to branch to given branch target pos
1276 void target_at_put(int pos, int target_pos);
1277
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001278 // Prevent contant pool emission until EndBlockConstPool is called.
1279 // Call to this function can be nested but must be followed by an equal
1280 // number of call to EndBlockConstpool.
1281 void StartBlockConstPool() {
1282 if (const_pool_blocked_nesting_++ == 0) {
1283 // Prevent constant pool checks happening by setting the next check to
1284 // the biggest possible offset.
1285 next_buffer_check_ = kMaxInt;
1286 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001287 }
1288
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001289 // Resume constant pool emission. Need to be called as many time as
1290 // StartBlockConstPool to have an effect.
Steve Block6ded16b2010-05-10 14:33:55 +01001291 void EndBlockConstPool() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001292 if (--const_pool_blocked_nesting_ == 0) {
1293 // Check the constant pool hasn't been blocked for too long.
1294 ASSERT((num_pending_reloc_info_ == 0) ||
1295 (pc_offset() < (first_const_pool_use_ + kMaxDistToPool)));
1296 // Two cases:
1297 // * no_const_pool_before_ >= next_buffer_check_ and the emission is
1298 // still blocked
1299 // * no_const_pool_before_ < next_buffer_check_ and the next emit will
1300 // trigger a check.
1301 next_buffer_check_ = no_const_pool_before_;
1302 }
Steve Block6ded16b2010-05-10 14:33:55 +01001303 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001304
1305 bool is_const_pool_blocked() const {
1306 return (const_pool_blocked_nesting_ > 0) ||
1307 (pc_offset() < no_const_pool_before_);
1308 }
Steve Block6ded16b2010-05-10 14:33:55 +01001309
Steve Blocka7e24c12009-10-30 11:49:00 +00001310 private:
1311 // Code buffer:
1312 // The buffer into which code and relocation info are generated.
1313 byte* buffer_;
1314 int buffer_size_;
1315 // True if the assembler owns the buffer, false if buffer is external.
1316 bool own_buffer_;
1317
Steve Blocka7e24c12009-10-30 11:49:00 +00001318 int next_buffer_check_; // pc offset of next buffer check
1319
1320 // Code generation
1321 // The relocation writer's position is at least kGap bytes below the end of
1322 // the generated instructions. This is so that multi-instruction sequences do
1323 // not have to check for overflow. The same is true for writes of large
1324 // relocation info entries.
1325 static const int kGap = 32;
1326 byte* pc_; // the program counter; moves forward
1327
1328 // Constant pool generation
1329 // Pools are emitted in the instruction stream, preferably after unconditional
1330 // jumps or after returns from functions (in dead code locations).
1331 // If a long code sequence does not contain unconditional jumps, it is
1332 // necessary to emit the constant pool before the pool gets too far from the
1333 // location it is accessed from. In this case, we emit a jump over the emitted
1334 // constant pool.
1335 // Constants in the pool may be addresses of functions that gets relocated;
1336 // if so, a relocation info entry is associated to the constant pool entry.
1337
1338 // Repeated checking whether the constant pool should be emitted is rather
1339 // expensive. By default we only check again once a number of instructions
1340 // has been generated. That also means that the sizing of the buffers is not
1341 // an exact science, and that we rely on some slop to not overrun buffers.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001342 static const int kCheckPoolIntervalInst = 32;
1343 static const int kCheckPoolInterval = kCheckPoolIntervalInst * kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +00001344
1345
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001346 // Average distance beetween a constant pool and the first instruction
1347 // accessing the constant pool. Longer distance should result in less I-cache
1348 // pollution.
1349 // In practice the distance will be smaller since constant pool emission is
1350 // forced after function return and sometimes after unconditional branches.
1351 static const int kAvgDistToPool = kMaxDistToPool - kCheckPoolInterval;
Steve Blocka7e24c12009-10-30 11:49:00 +00001352
Steve Block6ded16b2010-05-10 14:33:55 +01001353 // Emission of the constant pool may be blocked in some code sequences.
1354 int const_pool_blocked_nesting_; // Block emission if this is not zero.
1355 int no_const_pool_before_; // Block emission before this pc offset.
Steve Blocka7e24c12009-10-30 11:49:00 +00001356
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001357 // Keep track of the first instruction requiring a constant pool entry
1358 // since the previous constant pool was emitted.
1359 int first_const_pool_use_;
Steve Blocka7e24c12009-10-30 11:49:00 +00001360
1361 // Relocation info generation
1362 // Each relocation is encoded as a variable size value
1363 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1364 RelocInfoWriter reloc_info_writer;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001365
Steve Blocka7e24c12009-10-30 11:49:00 +00001366 // Relocation info records are also used during code generation as temporary
1367 // containers for constants and code target addresses until they are emitted
1368 // to the constant pool. These pending relocation info records are temporarily
1369 // stored in a separate buffer until a constant pool is emitted.
1370 // If every instruction in a long sequence is accessing the pool, we need one
1371 // pending relocation entry per instruction.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001372
1373 // the buffer of pending relocation info
1374 RelocInfo pending_reloc_info_[kMaxNumPendingRelocInfo];
1375 // number of pending reloc info entries in the buffer
1376 int num_pending_reloc_info_;
Steve Blocka7e24c12009-10-30 11:49:00 +00001377
1378 // The bound position, before this we cannot do instruction elimination.
1379 int last_bound_pos_;
1380
Steve Blocka7e24c12009-10-30 11:49:00 +00001381 // Code emission
1382 inline void CheckBuffer();
1383 void GrowBuffer();
1384 inline void emit(Instr x);
1385
1386 // Instruction generation
1387 void addrmod1(Instr instr, Register rn, Register rd, const Operand& x);
1388 void addrmod2(Instr instr, Register rd, const MemOperand& x);
1389 void addrmod3(Instr instr, Register rd, const MemOperand& x);
1390 void addrmod4(Instr instr, Register rn, RegList rl);
1391 void addrmod5(Instr instr, CRegister crd, const MemOperand& x);
1392
1393 // Labels
1394 void print(Label* L);
1395 void bind_to(Label* L, int pos);
1396 void link_to(Label* L, Label* appendix);
1397 void next(Label* L);
1398
1399 // Record reloc info for current pc_
1400 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
1401
1402 friend class RegExpMacroAssemblerARM;
1403 friend class RelocInfo;
1404 friend class CodePatcher;
Steve Block6ded16b2010-05-10 14:33:55 +01001405 friend class BlockConstPoolScope;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001406
1407 PositionsRecorder positions_recorder_;
Steve Block44f0eee2011-05-26 01:26:41 +01001408 bool emit_debug_code_;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001409 friend class PositionsRecorder;
1410 friend class EnsureSpace;
Steve Blocka7e24c12009-10-30 11:49:00 +00001411};
1412
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001413
1414class EnsureSpace BASE_EMBEDDED {
1415 public:
1416 explicit EnsureSpace(Assembler* assembler) {
1417 assembler->CheckBuffer();
1418 }
1419};
1420
1421
Steve Blocka7e24c12009-10-30 11:49:00 +00001422} } // namespace v8::internal
1423
1424#endif // V8_ARM_ASSEMBLER_ARM_H_