blob: 97d4226503b21e56e8881632ed8736a900ac1166 [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));
380 INLINE(explicit Operand(const ExternalReference& f));
Steve Blocka7e24c12009-10-30 11:49:00 +0000381 explicit Operand(Handle<Object> handle);
382 INLINE(explicit Operand(Smi* value));
383
384 // rm
385 INLINE(explicit Operand(Register rm));
386
387 // rm <shift_op> shift_imm
388 explicit Operand(Register rm, ShiftOp shift_op, int shift_imm);
389
390 // rm <shift_op> rs
391 explicit Operand(Register rm, ShiftOp shift_op, Register rs);
392
393 // Return true if this is a register operand.
394 INLINE(bool is_reg() const);
395
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100396 // Return true if this operand fits in one instruction so that no
Steve Block44f0eee2011-05-26 01:26:41 +0100397 // 2-instruction solution with a load into the ip register is necessary. If
398 // the instruction this operand is used for is a MOV or MVN instruction the
399 // actual instruction to use is required for this calculation. For other
400 // instructions instr is ignored.
401 bool is_single_instruction(Instr instr = 0) const;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800402 bool must_use_constant_pool() const;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100403
404 inline int32_t immediate() const {
405 ASSERT(!rm_.is_valid());
406 return imm32_;
407 }
408
Steve Blocka7e24c12009-10-30 11:49:00 +0000409 Register rm() const { return rm_; }
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100410 Register rs() const { return rs_; }
411 ShiftOp shift_op() const { return shift_op_; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000412
413 private:
414 Register rm_;
415 Register rs_;
416 ShiftOp shift_op_;
417 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
418 int32_t imm32_; // valid if rm_ == no_reg
419 RelocInfo::Mode rmode_;
420
421 friend class Assembler;
422};
423
424
425// Class MemOperand represents a memory operand in load and store instructions
426class MemOperand BASE_EMBEDDED {
427 public:
428 // [rn +/- offset] Offset/NegOffset
429 // [rn +/- offset]! PreIndex/NegPreIndex
430 // [rn], +/- offset PostIndex/NegPostIndex
431 // offset is any signed 32-bit value; offset is first loaded to register ip if
432 // it does not fit the addressing mode (12-bit unsigned and sign bit)
433 explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset);
434
435 // [rn +/- rm] Offset/NegOffset
436 // [rn +/- rm]! PreIndex/NegPreIndex
437 // [rn], +/- rm PostIndex/NegPostIndex
438 explicit MemOperand(Register rn, Register rm, AddrMode am = Offset);
439
440 // [rn +/- rm <shift_op> shift_imm] Offset/NegOffset
441 // [rn +/- rm <shift_op> shift_imm]! PreIndex/NegPreIndex
442 // [rn], +/- rm <shift_op> shift_imm PostIndex/NegPostIndex
443 explicit MemOperand(Register rn, Register rm,
444 ShiftOp shift_op, int shift_imm, AddrMode am = Offset);
445
Kristian Monsen25f61362010-05-21 11:50:48 +0100446 void set_offset(int32_t offset) {
447 ASSERT(rm_.is(no_reg));
448 offset_ = offset;
449 }
450
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100451 uint32_t offset() const {
Kristian Monsen25f61362010-05-21 11:50:48 +0100452 ASSERT(rm_.is(no_reg));
453 return offset_;
454 }
455
Leon Clarkef7060e22010-06-03 12:02:55 +0100456 Register rn() const { return rn_; }
457 Register rm() const { return rm_; }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000458 AddrMode am() const { return am_; }
Kristian Monsen25f61362010-05-21 11:50:48 +0100459
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100460 bool OffsetIsUint12Encodable() const {
461 return offset_ >= 0 ? is_uint12(offset_) : is_uint12(-offset_);
462 }
463
Steve Blocka7e24c12009-10-30 11:49:00 +0000464 private:
465 Register rn_; // base
466 Register rm_; // register offset
467 int32_t offset_; // valid if rm_ == no_reg
468 ShiftOp shift_op_;
469 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
470 AddrMode am_; // bits P, U, and W
471
472 friend class Assembler;
473};
474
Steve Blockd0582a62009-12-15 09:54:21 +0000475// CpuFeatures keeps track of which features are supported by the target CPU.
476// Supported features must be enabled by a Scope before use.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100477class CpuFeatures : public AllStatic {
Steve Blockd0582a62009-12-15 09:54:21 +0000478 public:
479 // Detect features of the target CPU. Set safe defaults if the serializer
480 // is enabled (snapshots must be portable).
Ben Murdoch8b112d22011-06-08 16:22:53 +0100481 static void Probe();
Steve Blockd0582a62009-12-15 09:54:21 +0000482
483 // Check whether a feature is supported by the target CPU.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100484 static bool IsSupported(CpuFeature f) {
485 ASSERT(initialized_);
Steve Blockd0582a62009-12-15 09:54:21 +0000486 if (f == VFP3 && !FLAG_enable_vfp3) return false;
487 return (supported_ & (1u << f)) != 0;
488 }
489
Ben Murdoch8b112d22011-06-08 16:22:53 +0100490#ifdef DEBUG
Steve Blockd0582a62009-12-15 09:54:21 +0000491 // Check whether a feature is currently enabled.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100492 static bool IsEnabled(CpuFeature f) {
493 ASSERT(initialized_);
494 Isolate* isolate = Isolate::UncheckedCurrent();
495 if (isolate == NULL) {
496 // When no isolate is available, work as if we're running in
497 // release mode.
498 return IsSupported(f);
499 }
500 unsigned enabled = static_cast<unsigned>(isolate->enabled_cpu_features());
501 return (enabled & (1u << f)) != 0;
Steve Blockd0582a62009-12-15 09:54:21 +0000502 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100503#endif
Steve Blockd0582a62009-12-15 09:54:21 +0000504
505 // Enable a specified feature within a scope.
506 class Scope BASE_EMBEDDED {
507#ifdef DEBUG
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000508
Steve Blockd0582a62009-12-15 09:54:21 +0000509 public:
Ben Murdoch8b112d22011-06-08 16:22:53 +0100510 explicit Scope(CpuFeature f) {
511 unsigned mask = 1u << f;
512 ASSERT(CpuFeatures::IsSupported(f));
Steve Blockd0582a62009-12-15 09:54:21 +0000513 ASSERT(!Serializer::enabled() ||
Ben Murdoch8b112d22011-06-08 16:22:53 +0100514 (CpuFeatures::found_by_runtime_probing_ & mask) == 0);
515 isolate_ = Isolate::UncheckedCurrent();
516 old_enabled_ = 0;
517 if (isolate_ != NULL) {
518 old_enabled_ = static_cast<unsigned>(isolate_->enabled_cpu_features());
519 isolate_->set_enabled_cpu_features(old_enabled_ | mask);
520 }
Steve Blockd0582a62009-12-15 09:54:21 +0000521 }
Steve Block44f0eee2011-05-26 01:26:41 +0100522 ~Scope() {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100523 ASSERT_EQ(Isolate::UncheckedCurrent(), isolate_);
524 if (isolate_ != NULL) {
525 isolate_->set_enabled_cpu_features(old_enabled_);
526 }
Steve Block44f0eee2011-05-26 01:26:41 +0100527 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000528
Steve Blockd0582a62009-12-15 09:54:21 +0000529 private:
Steve Block44f0eee2011-05-26 01:26:41 +0100530 Isolate* isolate_;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100531 unsigned old_enabled_;
Steve Blockd0582a62009-12-15 09:54:21 +0000532#else
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000533
Steve Blockd0582a62009-12-15 09:54:21 +0000534 public:
535 explicit Scope(CpuFeature f) {}
536#endif
537 };
538
Ben Murdoch8b112d22011-06-08 16:22:53 +0100539 class TryForceFeatureScope BASE_EMBEDDED {
540 public:
541 explicit TryForceFeatureScope(CpuFeature f)
542 : old_supported_(CpuFeatures::supported_) {
543 if (CanForce()) {
544 CpuFeatures::supported_ |= (1u << f);
545 }
546 }
547
548 ~TryForceFeatureScope() {
549 if (CanForce()) {
550 CpuFeatures::supported_ = old_supported_;
551 }
552 }
553
554 private:
555 static bool CanForce() {
556 // It's only safe to temporarily force support of CPU features
557 // when there's only a single isolate, which is guaranteed when
558 // the serializer is enabled.
559 return Serializer::enabled();
560 }
561
562 const unsigned old_supported_;
563 };
564
Steve Blockd0582a62009-12-15 09:54:21 +0000565 private:
Ben Murdoch8b112d22011-06-08 16:22:53 +0100566#ifdef DEBUG
567 static bool initialized_;
568#endif
569 static unsigned supported_;
570 static unsigned found_by_runtime_probing_;
Steve Block44f0eee2011-05-26 01:26:41 +0100571
572 DISALLOW_COPY_AND_ASSIGN(CpuFeatures);
Steve Blockd0582a62009-12-15 09:54:21 +0000573};
574
Steve Blocka7e24c12009-10-30 11:49:00 +0000575
Steve Blocka7e24c12009-10-30 11:49:00 +0000576extern const Instr kMovLrPc;
Steve Block6ded16b2010-05-10 14:33:55 +0100577extern const Instr kLdrPCMask;
Steve Blocka7e24c12009-10-30 11:49:00 +0000578extern const Instr kLdrPCPattern;
Steve Block6ded16b2010-05-10 14:33:55 +0100579extern const Instr kBlxRegMask;
580extern const Instr kBlxRegPattern;
Steve Blocka7e24c12009-10-30 11:49:00 +0000581
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100582extern const Instr kMovMvnMask;
583extern const Instr kMovMvnPattern;
584extern const Instr kMovMvnFlip;
585
586extern const Instr kMovLeaveCCMask;
587extern const Instr kMovLeaveCCPattern;
588extern const Instr kMovwMask;
589extern const Instr kMovwPattern;
590extern const Instr kMovwLeaveCCFlip;
591
592extern const Instr kCmpCmnMask;
593extern const Instr kCmpCmnPattern;
594extern const Instr kCmpCmnFlip;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100595extern const Instr kAddSubFlip;
596extern const Instr kAndBicFlip;
Steve Blocka7e24c12009-10-30 11:49:00 +0000597
Steve Block1e0659c2011-05-24 12:43:12 +0100598
599
Steve Block44f0eee2011-05-26 01:26:41 +0100600class Assembler : public AssemblerBase {
Steve Blocka7e24c12009-10-30 11:49:00 +0000601 public:
602 // Create an assembler. Instructions and relocation information are emitted
603 // into a buffer, with the instructions starting from the beginning and the
604 // relocation information starting from the end of the buffer. See CodeDesc
605 // for a detailed comment on the layout (globals.h).
606 //
607 // If the provided buffer is NULL, the assembler allocates and grows its own
608 // buffer, and buffer_size determines the initial buffer size. The buffer is
609 // owned by the assembler and deallocated upon destruction of the assembler.
610 //
611 // If the provided buffer is not NULL, the assembler uses the provided buffer
612 // for code generation and assumes its size to be buffer_size. If the buffer
613 // is too small, a fatal error occurs. No deallocation of the buffer is done
614 // upon destruction of the assembler.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100615 Assembler(Isolate* isolate, void* buffer, int buffer_size);
Steve Blocka7e24c12009-10-30 11:49:00 +0000616 ~Assembler();
617
Steve Block44f0eee2011-05-26 01:26:41 +0100618 // Overrides the default provided by FLAG_debug_code.
619 void set_emit_debug_code(bool value) { emit_debug_code_ = value; }
620
Steve Blocka7e24c12009-10-30 11:49:00 +0000621 // GetCode emits any pending (non-emitted) code and fills the descriptor
622 // desc. GetCode() is idempotent; it returns the same result if no other
623 // Assembler functions are invoked in between GetCode() calls.
624 void GetCode(CodeDesc* desc);
625
626 // Label operations & relative jumps (PPUM Appendix D)
627 //
628 // Takes a branch opcode (cc) and a label (L) and generates
629 // either a backward branch or a forward branch and links it
630 // to the label fixup chain. Usage:
631 //
632 // Label L; // unbound label
633 // j(cc, &L); // forward branch to unbound label
634 // bind(&L); // bind label to the current pc
635 // j(cc, &L); // backward branch to bound label
636 // bind(&L); // illegal: a label may be bound only once
637 //
638 // Note: The same Label can be used for forward and backward branches
639 // but it may be bound only once.
640
641 void bind(Label* L); // binds an unbound label L to the current code position
642
643 // Returns the branch offset to the given label from the current code position
644 // Links the label to the current position if it is still unbound
645 // Manages the jump elimination optimization if the second parameter is true.
646 int branch_offset(Label* L, bool jump_elimination_allowed);
647
648 // Puts a labels target address at the given position.
649 // The high 8 bits are set to zero.
650 void label_at_put(Label* L, int at_offset);
651
652 // Return the address in the constant pool of the code target address used by
653 // the branch/call instruction at pc.
654 INLINE(static Address target_address_address_at(Address pc));
655
656 // Read/Modify the code target address in the branch/call instruction at pc.
657 INLINE(static Address target_address_at(Address pc));
658 INLINE(static void set_target_address_at(Address pc, Address target));
659
Steve Blockd0582a62009-12-15 09:54:21 +0000660 // This sets the branch destination (which is in the constant pool on ARM).
661 // This is for calls and branches within generated code.
662 inline static void set_target_at(Address constant_pool_entry, Address target);
663
664 // This sets the branch destination (which is in the constant pool on ARM).
665 // This is for calls and branches to runtime code.
666 inline static void set_external_target_at(Address constant_pool_entry,
667 Address target) {
668 set_target_at(constant_pool_entry, target);
669 }
670
671 // Here we are patching the address in the constant pool, not the actual call
672 // instruction. The address in the constant pool is the same size as a
673 // pointer.
674 static const int kCallTargetSize = kPointerSize;
675 static const int kExternalTargetSize = kPointerSize;
676
Steve Blocka7e24c12009-10-30 11:49:00 +0000677 // Size of an instruction.
678 static const int kInstrSize = sizeof(Instr);
679
680 // Distance between the instruction referring to the address of the call
Steve Block6ded16b2010-05-10 14:33:55 +0100681 // target and the return address.
682#ifdef USE_BLX
683 // Call sequence is:
684 // ldr ip, [pc, #...] @ call address
685 // blx ip
686 // @ return address
687 static const int kCallTargetAddressOffset = 2 * kInstrSize;
688#else
689 // Call sequence is:
690 // mov lr, pc
691 // ldr pc, [pc, #...] @ call address
692 // @ return address
Steve Blocka7e24c12009-10-30 11:49:00 +0000693 static const int kCallTargetAddressOffset = kInstrSize;
Steve Block6ded16b2010-05-10 14:33:55 +0100694#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000695
696 // Distance between start of patched return sequence and the emitted address
697 // to jump to.
Steve Block6ded16b2010-05-10 14:33:55 +0100698#ifdef USE_BLX
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100699 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100700 // ldr ip, [pc, #0] @ emited address and start
701 // blx ip
702 static const int kPatchReturnSequenceAddressOffset = 0 * kInstrSize;
703#else
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100704 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100705 // mov lr, pc @ start of sequence
706 // ldr pc, [pc, #-4] @ emited address
707 static const int kPatchReturnSequenceAddressOffset = kInstrSize;
708#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000709
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100710 // Distance between start of patched debug break slot and the emitted address
711 // to jump to.
712#ifdef USE_BLX
713 // Patched debug break slot code is:
714 // ldr ip, [pc, #0] @ emited address and start
715 // blx ip
716 static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
717#else
718 // Patched debug break slot code is:
719 // mov lr, pc @ start of sequence
720 // ldr pc, [pc, #-4] @ emited address
721 static const int kPatchDebugBreakSlotAddressOffset = kInstrSize;
722#endif
723
Steve Blocka7e24c12009-10-30 11:49:00 +0000724 // Difference between address of current opcode and value read from pc
725 // register.
726 static const int kPcLoadDelta = 8;
727
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100728 static const int kJSReturnSequenceInstructions = 4;
729 static const int kDebugBreakSlotInstructions = 3;
730 static const int kDebugBreakSlotLength =
731 kDebugBreakSlotInstructions * kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +0000732
733 // ---------------------------------------------------------------------------
734 // Code generation
735
736 // Insert the smallest number of nop instructions
737 // possible to align the pc offset to a multiple
738 // of m. m must be a power of 2 (>= 4).
739 void Align(int m);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100740 // Aligns code to something that's optimal for a jump target for the platform.
741 void CodeTargetAlign();
Steve Blocka7e24c12009-10-30 11:49:00 +0000742
743 // Branch instructions
744 void b(int branch_offset, Condition cond = al);
745 void bl(int branch_offset, Condition cond = al);
746 void blx(int branch_offset); // v5 and above
747 void blx(Register target, Condition cond = al); // v5 and above
748 void bx(Register target, Condition cond = al); // v5 and above, plus v4t
749
750 // Convenience branch instructions using labels
751 void b(Label* L, Condition cond = al) {
752 b(branch_offset(L, cond == al), cond);
753 }
754 void b(Condition cond, Label* L) { b(branch_offset(L, cond == al), cond); }
755 void bl(Label* L, Condition cond = al) { bl(branch_offset(L, false), cond); }
756 void bl(Condition cond, Label* L) { bl(branch_offset(L, false), cond); }
757 void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above
758
759 // Data-processing instructions
Andrei Popescu31002712010-02-23 13:46:05 +0000760
Steve Blocka7e24c12009-10-30 11:49:00 +0000761 void and_(Register dst, Register src1, const Operand& src2,
762 SBit s = LeaveCC, Condition cond = al);
763
764 void eor(Register dst, Register src1, const Operand& src2,
765 SBit s = LeaveCC, Condition cond = al);
766
767 void sub(Register dst, Register src1, const Operand& src2,
768 SBit s = LeaveCC, Condition cond = al);
769 void sub(Register dst, Register src1, Register src2,
770 SBit s = LeaveCC, Condition cond = al) {
771 sub(dst, src1, Operand(src2), s, cond);
772 }
773
774 void rsb(Register dst, Register src1, const Operand& src2,
775 SBit s = LeaveCC, Condition cond = al);
776
777 void add(Register dst, Register src1, const Operand& src2,
778 SBit s = LeaveCC, Condition cond = al);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100779 void add(Register dst, Register src1, Register src2,
780 SBit s = LeaveCC, Condition cond = al) {
781 add(dst, src1, Operand(src2), s, cond);
782 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000783
784 void adc(Register dst, Register src1, const Operand& src2,
785 SBit s = LeaveCC, Condition cond = al);
786
787 void sbc(Register dst, Register src1, const Operand& src2,
788 SBit s = LeaveCC, Condition cond = al);
789
790 void rsc(Register dst, Register src1, const Operand& src2,
791 SBit s = LeaveCC, Condition cond = al);
792
793 void tst(Register src1, const Operand& src2, Condition cond = al);
794 void tst(Register src1, Register src2, Condition cond = al) {
795 tst(src1, Operand(src2), cond);
796 }
797
798 void teq(Register src1, const Operand& src2, Condition cond = al);
799
800 void cmp(Register src1, const Operand& src2, Condition cond = al);
801 void cmp(Register src1, Register src2, Condition cond = al) {
802 cmp(src1, Operand(src2), cond);
803 }
Steve Block1e0659c2011-05-24 12:43:12 +0100804 void cmp_raw_immediate(Register src1, int raw_immediate, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000805
806 void cmn(Register src1, const Operand& src2, Condition cond = al);
807
808 void orr(Register dst, Register src1, const Operand& src2,
809 SBit s = LeaveCC, Condition cond = al);
810 void orr(Register dst, Register src1, Register src2,
811 SBit s = LeaveCC, Condition cond = al) {
812 orr(dst, src1, Operand(src2), s, cond);
813 }
814
815 void mov(Register dst, const Operand& src,
816 SBit s = LeaveCC, Condition cond = al);
817 void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
818 mov(dst, Operand(src), s, cond);
819 }
820
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100821 // ARMv7 instructions for loading a 32 bit immediate in two instructions.
822 // This may actually emit a different mov instruction, but on an ARMv7 it
823 // is guaranteed to only emit one instruction.
824 void movw(Register reg, uint32_t immediate, Condition cond = al);
825 // The constant for movt should be in the range 0-0xffff.
826 void movt(Register reg, uint32_t immediate, Condition cond = al);
827
Steve Blocka7e24c12009-10-30 11:49:00 +0000828 void bic(Register dst, Register src1, const Operand& src2,
829 SBit s = LeaveCC, Condition cond = al);
830
831 void mvn(Register dst, const Operand& src,
832 SBit s = LeaveCC, Condition cond = al);
833
834 // Multiply instructions
835
836 void mla(Register dst, Register src1, Register src2, Register srcA,
837 SBit s = LeaveCC, Condition cond = al);
838
839 void mul(Register dst, Register src1, Register src2,
840 SBit s = LeaveCC, Condition cond = al);
841
842 void smlal(Register dstL, Register dstH, Register src1, Register src2,
843 SBit s = LeaveCC, Condition cond = al);
844
845 void smull(Register dstL, Register dstH, Register src1, Register src2,
846 SBit s = LeaveCC, Condition cond = al);
847
848 void umlal(Register dstL, Register dstH, Register src1, Register src2,
849 SBit s = LeaveCC, Condition cond = al);
850
851 void umull(Register dstL, Register dstH, Register src1, Register src2,
852 SBit s = LeaveCC, Condition cond = al);
853
854 // Miscellaneous arithmetic instructions
855
856 void clz(Register dst, Register src, Condition cond = al); // v5 and above
857
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100858 // Saturating instructions. v6 and above.
859
860 // Unsigned saturate.
861 //
862 // Saturate an optionally shifted signed value to an unsigned range.
863 //
864 // usat dst, #satpos, src
865 // usat dst, #satpos, src, lsl #sh
866 // usat dst, #satpos, src, asr #sh
867 //
868 // Register dst will contain:
869 //
870 // 0, if s < 0
871 // (1 << satpos) - 1, if s > ((1 << satpos) - 1)
872 // s, otherwise
873 //
874 // where s is the contents of src after shifting (if used.)
875 void usat(Register dst, int satpos, const Operand& src, Condition cond = al);
876
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100877 // Bitfield manipulation instructions. v7 and above.
878
879 void ubfx(Register dst, Register src, int lsb, int width,
880 Condition cond = al);
881
882 void sbfx(Register dst, Register src, int lsb, int width,
883 Condition cond = al);
884
885 void bfc(Register dst, int lsb, int width, Condition cond = al);
886
887 void bfi(Register dst, Register src, int lsb, int width,
888 Condition cond = al);
889
Steve Blocka7e24c12009-10-30 11:49:00 +0000890 // Status register access instructions
891
892 void mrs(Register dst, SRegister s, Condition cond = al);
893 void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al);
894
895 // Load/Store instructions
896 void ldr(Register dst, const MemOperand& src, Condition cond = al);
897 void str(Register src, const MemOperand& dst, Condition cond = al);
898 void ldrb(Register dst, const MemOperand& src, Condition cond = al);
899 void strb(Register src, const MemOperand& dst, Condition cond = al);
900 void ldrh(Register dst, const MemOperand& src, Condition cond = al);
901 void strh(Register src, const MemOperand& dst, Condition cond = al);
902 void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
903 void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
Leon Clarkef7060e22010-06-03 12:02:55 +0100904 void ldrd(Register dst1,
905 Register dst2,
906 const MemOperand& src, Condition cond = al);
907 void strd(Register src1,
908 Register src2,
909 const MemOperand& dst, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000910
911 // Load/Store multiple instructions
912 void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
913 void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
914
Steve Blocka7e24c12009-10-30 11:49:00 +0000915 // Exception-generating instructions and debugging support
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800916 void stop(const char* msg,
917 Condition cond = al,
918 int32_t code = kDefaultStopCode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000919
920 void bkpt(uint32_t imm16); // v5 and above
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800921 void svc(uint32_t imm24, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000922
923 // Coprocessor instructions
924
925 void cdp(Coprocessor coproc, int opcode_1,
926 CRegister crd, CRegister crn, CRegister crm,
927 int opcode_2, Condition cond = al);
928
929 void cdp2(Coprocessor coproc, int opcode_1,
930 CRegister crd, CRegister crn, CRegister crm,
931 int opcode_2); // v5 and above
932
933 void mcr(Coprocessor coproc, int opcode_1,
934 Register rd, CRegister crn, CRegister crm,
935 int opcode_2 = 0, Condition cond = al);
936
937 void mcr2(Coprocessor coproc, int opcode_1,
938 Register rd, CRegister crn, CRegister crm,
939 int opcode_2 = 0); // v5 and above
940
941 void mrc(Coprocessor coproc, int opcode_1,
942 Register rd, CRegister crn, CRegister crm,
943 int opcode_2 = 0, Condition cond = al);
944
945 void mrc2(Coprocessor coproc, int opcode_1,
946 Register rd, CRegister crn, CRegister crm,
947 int opcode_2 = 0); // v5 and above
948
949 void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src,
950 LFlag l = Short, Condition cond = al);
951 void ldc(Coprocessor coproc, CRegister crd, Register base, int option,
952 LFlag l = Short, Condition cond = al);
953
954 void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
955 LFlag l = Short); // v5 and above
956 void ldc2(Coprocessor coproc, CRegister crd, Register base, int option,
957 LFlag l = Short); // v5 and above
958
Steve Blockd0582a62009-12-15 09:54:21 +0000959 // Support for VFP.
960 // All these APIs support S0 to S31 and D0 to D15.
961 // Currently these APIs do not support extended D registers, i.e, D16 to D31.
962 // However, some simple modifications can allow
963 // these APIs to support D16 to D31.
964
Leon Clarked91b9f72010-01-27 17:25:45 +0000965 void vldr(const DwVfpRegister dst,
966 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100967 int offset,
968 const Condition cond = al);
969 void vldr(const DwVfpRegister dst,
970 const MemOperand& src,
Leon Clarked91b9f72010-01-27 17:25:45 +0000971 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +0100972
973 void vldr(const SwVfpRegister dst,
974 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100975 int offset,
976 const Condition cond = al);
977 void vldr(const SwVfpRegister dst,
978 const MemOperand& src,
Steve Block6ded16b2010-05-10 14:33:55 +0100979 const Condition cond = al);
980
Leon Clarked91b9f72010-01-27 17:25:45 +0000981 void vstr(const DwVfpRegister src,
982 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100983 int offset,
984 const Condition cond = al);
985 void vstr(const DwVfpRegister src,
986 const MemOperand& dst,
Leon Clarked91b9f72010-01-27 17:25:45 +0000987 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +0100988
Iain Merrick75681382010-08-19 15:07:18 +0100989 void vstr(const SwVfpRegister src,
990 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100991 int offset,
992 const Condition cond = al);
993 void vstr(const SwVfpRegister src,
994 const MemOperand& dst,
Iain Merrick75681382010-08-19 15:07:18 +0100995 const Condition cond = al);
996
Ben Murdoch8b112d22011-06-08 16:22:53 +0100997 void vldm(BlockAddrMode am,
998 Register base,
999 DwVfpRegister first,
1000 DwVfpRegister last,
1001 Condition cond = al);
1002
1003 void vstm(BlockAddrMode am,
1004 Register base,
1005 DwVfpRegister first,
1006 DwVfpRegister last,
1007 Condition cond = al);
1008
1009 void vldm(BlockAddrMode am,
1010 Register base,
1011 SwVfpRegister first,
1012 SwVfpRegister last,
1013 Condition cond = al);
1014
1015 void vstm(BlockAddrMode am,
1016 Register base,
1017 SwVfpRegister first,
1018 SwVfpRegister last,
1019 Condition cond = al);
1020
Steve Block8defd9f2010-07-08 12:39:36 +01001021 void vmov(const DwVfpRegister dst,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001022 double imm,
1023 const Condition cond = al);
1024 void vmov(const SwVfpRegister dst,
1025 const SwVfpRegister src,
1026 const Condition cond = al);
1027 void vmov(const DwVfpRegister dst,
Steve Block8defd9f2010-07-08 12:39:36 +01001028 const DwVfpRegister src,
1029 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001030 void vmov(const DwVfpRegister dst,
1031 const Register src1,
Steve Blockd0582a62009-12-15 09:54:21 +00001032 const Register src2,
Leon Clarkee46be812010-01-19 14:06:41 +00001033 const Condition cond = al);
1034 void vmov(const Register dst1,
1035 const Register dst2,
1036 const DwVfpRegister src,
1037 const Condition cond = al);
1038 void vmov(const SwVfpRegister dst,
1039 const Register src,
1040 const Condition cond = al);
1041 void vmov(const Register dst,
1042 const SwVfpRegister src,
1043 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +01001044 void vcvt_f64_s32(const DwVfpRegister dst,
1045 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001046 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001047 const Condition cond = al);
1048 void vcvt_f32_s32(const SwVfpRegister dst,
1049 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001050 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001051 const Condition cond = al);
1052 void vcvt_f64_u32(const DwVfpRegister dst,
1053 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001054 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001055 const Condition cond = al);
1056 void vcvt_s32_f64(const SwVfpRegister dst,
1057 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001058 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001059 const Condition cond = al);
1060 void vcvt_u32_f64(const SwVfpRegister dst,
1061 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001062 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001063 const Condition cond = al);
1064 void vcvt_f64_f32(const DwVfpRegister dst,
1065 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001066 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001067 const Condition cond = al);
1068 void vcvt_f32_f64(const SwVfpRegister dst,
1069 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001070 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001071 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001072
Steve Block44f0eee2011-05-26 01:26:41 +01001073 void vneg(const DwVfpRegister dst,
1074 const DwVfpRegister src,
1075 const Condition cond = al);
Steve Block1e0659c2011-05-24 12:43:12 +01001076 void vabs(const DwVfpRegister dst,
1077 const DwVfpRegister src,
1078 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001079 void vadd(const DwVfpRegister dst,
1080 const DwVfpRegister src1,
1081 const DwVfpRegister src2,
1082 const Condition cond = al);
1083 void vsub(const DwVfpRegister dst,
1084 const DwVfpRegister src1,
1085 const DwVfpRegister src2,
1086 const Condition cond = al);
1087 void vmul(const DwVfpRegister dst,
1088 const DwVfpRegister src1,
1089 const DwVfpRegister src2,
1090 const Condition cond = al);
1091 void vdiv(const DwVfpRegister dst,
1092 const DwVfpRegister src1,
1093 const DwVfpRegister src2,
1094 const Condition cond = al);
1095 void vcmp(const DwVfpRegister src1,
1096 const DwVfpRegister src2,
Steve Blockd0582a62009-12-15 09:54:21 +00001097 const Condition cond = al);
Iain Merrick75681382010-08-19 15:07:18 +01001098 void vcmp(const DwVfpRegister src1,
1099 const double src2,
Iain Merrick75681382010-08-19 15:07:18 +01001100 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001101 void vmrs(const Register dst,
1102 const Condition cond = al);
Russell Brenner90bac252010-11-18 13:33:46 -08001103 void vmsr(const Register dst,
1104 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +01001105 void vsqrt(const DwVfpRegister dst,
1106 const DwVfpRegister src,
1107 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001108
Steve Blocka7e24c12009-10-30 11:49:00 +00001109 // Pseudo instructions
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001110
1111 // Different nop operations are used by the code generator to detect certain
1112 // states of the generated code.
1113 enum NopMarkerTypes {
1114 NON_MARKING_NOP = 0,
1115 DEBUG_BREAK_NOP,
1116 // IC markers.
1117 PROPERTY_ACCESS_INLINED,
1118 PROPERTY_ACCESS_INLINED_CONTEXT,
1119 PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE,
1120 // Helper values.
1121 LAST_CODE_MARKER,
1122 FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED
1123 };
1124
1125 void nop(int type = 0); // 0 is the default non-marking type.
Steve Blocka7e24c12009-10-30 11:49:00 +00001126
1127 void push(Register src, Condition cond = al) {
1128 str(src, MemOperand(sp, 4, NegPreIndex), cond);
1129 }
1130
1131 void pop(Register dst, Condition cond = al) {
1132 ldr(dst, MemOperand(sp, 4, PostIndex), cond);
1133 }
1134
1135 void pop() {
1136 add(sp, sp, Operand(kPointerSize));
1137 }
1138
Steve Blocka7e24c12009-10-30 11:49:00 +00001139 // Jump unconditionally to given label.
1140 void jmp(Label* L) { b(L, al); }
1141
1142 // Check the code size generated from label to here.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001143 int SizeOfCodeGeneratedSince(Label* label) {
1144 return pc_offset() - label->pos();
1145 }
1146
1147 // Check the number of instructions generated from label to here.
1148 int InstructionsGeneratedSince(Label* label) {
1149 return SizeOfCodeGeneratedSince(label) / kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +00001150 }
1151
Steve Blockd0582a62009-12-15 09:54:21 +00001152 // Check whether an immediate fits an addressing mode 1 instruction.
1153 bool ImmediateFitsAddrMode1Instruction(int32_t imm32);
1154
Steve Block6ded16b2010-05-10 14:33:55 +01001155 // Class for scoping postponing the constant pool generation.
1156 class BlockConstPoolScope {
1157 public:
1158 explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) {
1159 assem_->StartBlockConstPool();
1160 }
1161 ~BlockConstPoolScope() {
1162 assem_->EndBlockConstPool();
1163 }
1164
1165 private:
1166 Assembler* assem_;
1167
1168 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstPoolScope);
1169 };
1170
Steve Blocka7e24c12009-10-30 11:49:00 +00001171 // Debugging
1172
1173 // Mark address of the ExitJSFrame code.
1174 void RecordJSReturn();
1175
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001176 // Mark address of a debug break slot.
1177 void RecordDebugBreakSlot();
1178
Ben Murdoch257744e2011-11-30 15:57:28 +00001179 // Record the AST id of the CallIC being compiled, so that it can be placed
1180 // in the relocation information.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001181 void SetRecordedAstId(unsigned ast_id) {
1182 ASSERT(recorded_ast_id_ == kNoASTId);
1183 recorded_ast_id_ = ast_id;
1184 }
1185
1186 unsigned RecordedAstId() {
1187 ASSERT(recorded_ast_id_ != kNoASTId);
1188 return recorded_ast_id_;
1189 }
1190
1191 void ClearRecordedAstId() { recorded_ast_id_ = kNoASTId; }
Ben Murdoch257744e2011-11-30 15:57:28 +00001192
Steve Blocka7e24c12009-10-30 11:49:00 +00001193 // Record a comment relocation entry that can be used by a disassembler.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001194 // Use --code-comments to enable.
Steve Blocka7e24c12009-10-30 11:49:00 +00001195 void RecordComment(const char* msg);
1196
Ben Murdochb8e0da22011-05-16 14:20:40 +01001197 // Writes a single byte or word of data in the code stream. Used
1198 // for inline tables, e.g., jump-tables. The constant pool should be
1199 // emitted before any use of db and dd to ensure that constant pools
1200 // are not emitted as part of the tables generated.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001201 void db(uint8_t data);
1202 void dd(uint32_t data);
1203
Steve Blocka7e24c12009-10-30 11:49:00 +00001204 int pc_offset() const { return pc_ - buffer_; }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001205
1206 PositionsRecorder* positions_recorder() { return &positions_recorder_; }
Steve Block6ded16b2010-05-10 14:33:55 +01001207
1208 // Read/patch instructions
1209 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
1210 static void instr_at_put(byte* pc, Instr instr) {
1211 *reinterpret_cast<Instr*>(pc) = instr;
1212 }
Steve Block1e0659c2011-05-24 12:43:12 +01001213 static Condition GetCondition(Instr instr);
Steve Block6ded16b2010-05-10 14:33:55 +01001214 static bool IsBranch(Instr instr);
1215 static int GetBranchOffset(Instr instr);
1216 static bool IsLdrRegisterImmediate(Instr instr);
1217 static int GetLdrRegisterImmediateOffset(Instr instr);
1218 static Instr SetLdrRegisterImmediateOffset(Instr instr, int offset);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001219 static bool IsStrRegisterImmediate(Instr instr);
1220 static Instr SetStrRegisterImmediateOffset(Instr instr, int offset);
1221 static bool IsAddRegisterImmediate(Instr instr);
1222 static Instr SetAddRegisterImmediateOffset(Instr instr, int offset);
Leon Clarkef7060e22010-06-03 12:02:55 +01001223 static Register GetRd(Instr instr);
Steve Block1e0659c2011-05-24 12:43:12 +01001224 static Register GetRn(Instr instr);
1225 static Register GetRm(Instr instr);
Leon Clarkef7060e22010-06-03 12:02:55 +01001226 static bool IsPush(Instr instr);
1227 static bool IsPop(Instr instr);
1228 static bool IsStrRegFpOffset(Instr instr);
1229 static bool IsLdrRegFpOffset(Instr instr);
1230 static bool IsStrRegFpNegOffset(Instr instr);
1231 static bool IsLdrRegFpNegOffset(Instr instr);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001232 static bool IsLdrPcImmediateOffset(Instr instr);
Steve Block1e0659c2011-05-24 12:43:12 +01001233 static bool IsTstImmediate(Instr instr);
1234 static bool IsCmpRegister(Instr instr);
1235 static bool IsCmpImmediate(Instr instr);
1236 static Register GetCmpImmediateRegister(Instr instr);
1237 static int GetCmpImmediateRawImmediate(Instr instr);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001238 static bool IsNop(Instr instr, int type = NON_MARKING_NOP);
Steve Block6ded16b2010-05-10 14:33:55 +01001239
Ben Murdoch257744e2011-11-30 15:57:28 +00001240 // Constants in pools are accessed via pc relative addressing, which can
1241 // reach +/-4KB thereby defining a maximum distance between the instruction
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001242 // and the accessed constant.
1243 static const int kMaxDistToPool = 4*KB;
1244 static const int kMaxNumPendingRelocInfo = kMaxDistToPool/kInstrSize;
Ben Murdoch257744e2011-11-30 15:57:28 +00001245
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001246 // Postpone the generation of the constant pool for the specified number of
1247 // instructions.
1248 void BlockConstPoolFor(int instructions);
1249
1250 // Check if is time to emit a constant pool.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001251 void CheckConstPool(bool force_emit, bool require_jump);
Steve Blocka7e24c12009-10-30 11:49:00 +00001252
1253 protected:
Ben Murdoch257744e2011-11-30 15:57:28 +00001254 // Relocation for a type-recording IC has the AST id added to it. This
1255 // member variable is a way to pass the information from the call site to
1256 // the relocation info.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001257 unsigned recorded_ast_id_;
Ben Murdoch257744e2011-11-30 15:57:28 +00001258
Steve Block44f0eee2011-05-26 01:26:41 +01001259 bool emit_debug_code() const { return emit_debug_code_; }
1260
Steve Blocka7e24c12009-10-30 11:49:00 +00001261 int buffer_space() const { return reloc_info_writer.pos() - pc_; }
1262
1263 // Read/patch instructions
Steve Blocka7e24c12009-10-30 11:49:00 +00001264 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
1265 void instr_at_put(int pos, Instr instr) {
1266 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
1267 }
1268
1269 // Decode branch instruction at pos and return branch target pos
1270 int target_at(int pos);
1271
1272 // Patch branch instruction at pos to branch to given branch target pos
1273 void target_at_put(int pos, int target_pos);
1274
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001275 // Prevent contant pool emission until EndBlockConstPool is called.
1276 // Call to this function can be nested but must be followed by an equal
1277 // number of call to EndBlockConstpool.
1278 void StartBlockConstPool() {
1279 if (const_pool_blocked_nesting_++ == 0) {
1280 // Prevent constant pool checks happening by setting the next check to
1281 // the biggest possible offset.
1282 next_buffer_check_ = kMaxInt;
1283 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001284 }
1285
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001286 // Resume constant pool emission. Need to be called as many time as
1287 // StartBlockConstPool to have an effect.
Steve Block6ded16b2010-05-10 14:33:55 +01001288 void EndBlockConstPool() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001289 if (--const_pool_blocked_nesting_ == 0) {
1290 // Check the constant pool hasn't been blocked for too long.
1291 ASSERT((num_pending_reloc_info_ == 0) ||
1292 (pc_offset() < (first_const_pool_use_ + kMaxDistToPool)));
1293 // Two cases:
1294 // * no_const_pool_before_ >= next_buffer_check_ and the emission is
1295 // still blocked
1296 // * no_const_pool_before_ < next_buffer_check_ and the next emit will
1297 // trigger a check.
1298 next_buffer_check_ = no_const_pool_before_;
1299 }
Steve Block6ded16b2010-05-10 14:33:55 +01001300 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001301
1302 bool is_const_pool_blocked() const {
1303 return (const_pool_blocked_nesting_ > 0) ||
1304 (pc_offset() < no_const_pool_before_);
1305 }
Steve Block6ded16b2010-05-10 14:33:55 +01001306
Steve Blocka7e24c12009-10-30 11:49:00 +00001307 private:
1308 // Code buffer:
1309 // The buffer into which code and relocation info are generated.
1310 byte* buffer_;
1311 int buffer_size_;
1312 // True if the assembler owns the buffer, false if buffer is external.
1313 bool own_buffer_;
1314
Steve Blocka7e24c12009-10-30 11:49:00 +00001315 int next_buffer_check_; // pc offset of next buffer check
1316
1317 // Code generation
1318 // The relocation writer's position is at least kGap bytes below the end of
1319 // the generated instructions. This is so that multi-instruction sequences do
1320 // not have to check for overflow. The same is true for writes of large
1321 // relocation info entries.
1322 static const int kGap = 32;
1323 byte* pc_; // the program counter; moves forward
1324
1325 // Constant pool generation
1326 // Pools are emitted in the instruction stream, preferably after unconditional
1327 // jumps or after returns from functions (in dead code locations).
1328 // If a long code sequence does not contain unconditional jumps, it is
1329 // necessary to emit the constant pool before the pool gets too far from the
1330 // location it is accessed from. In this case, we emit a jump over the emitted
1331 // constant pool.
1332 // Constants in the pool may be addresses of functions that gets relocated;
1333 // if so, a relocation info entry is associated to the constant pool entry.
1334
1335 // Repeated checking whether the constant pool should be emitted is rather
1336 // expensive. By default we only check again once a number of instructions
1337 // has been generated. That also means that the sizing of the buffers is not
1338 // an exact science, and that we rely on some slop to not overrun buffers.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001339 static const int kCheckPoolIntervalInst = 32;
1340 static const int kCheckPoolInterval = kCheckPoolIntervalInst * kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +00001341
1342
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001343 // Average distance beetween a constant pool and the first instruction
1344 // accessing the constant pool. Longer distance should result in less I-cache
1345 // pollution.
1346 // In practice the distance will be smaller since constant pool emission is
1347 // forced after function return and sometimes after unconditional branches.
1348 static const int kAvgDistToPool = kMaxDistToPool - kCheckPoolInterval;
Steve Blocka7e24c12009-10-30 11:49:00 +00001349
Steve Block6ded16b2010-05-10 14:33:55 +01001350 // Emission of the constant pool may be blocked in some code sequences.
1351 int const_pool_blocked_nesting_; // Block emission if this is not zero.
1352 int no_const_pool_before_; // Block emission before this pc offset.
Steve Blocka7e24c12009-10-30 11:49:00 +00001353
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001354 // Keep track of the first instruction requiring a constant pool entry
1355 // since the previous constant pool was emitted.
1356 int first_const_pool_use_;
Steve Blocka7e24c12009-10-30 11:49:00 +00001357
1358 // Relocation info generation
1359 // Each relocation is encoded as a variable size value
1360 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1361 RelocInfoWriter reloc_info_writer;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001362
Steve Blocka7e24c12009-10-30 11:49:00 +00001363 // Relocation info records are also used during code generation as temporary
1364 // containers for constants and code target addresses until they are emitted
1365 // to the constant pool. These pending relocation info records are temporarily
1366 // stored in a separate buffer until a constant pool is emitted.
1367 // If every instruction in a long sequence is accessing the pool, we need one
1368 // pending relocation entry per instruction.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001369
1370 // the buffer of pending relocation info
1371 RelocInfo pending_reloc_info_[kMaxNumPendingRelocInfo];
1372 // number of pending reloc info entries in the buffer
1373 int num_pending_reloc_info_;
Steve Blocka7e24c12009-10-30 11:49:00 +00001374
1375 // The bound position, before this we cannot do instruction elimination.
1376 int last_bound_pos_;
1377
Steve Blocka7e24c12009-10-30 11:49:00 +00001378 // Code emission
1379 inline void CheckBuffer();
1380 void GrowBuffer();
1381 inline void emit(Instr x);
1382
1383 // Instruction generation
1384 void addrmod1(Instr instr, Register rn, Register rd, const Operand& x);
1385 void addrmod2(Instr instr, Register rd, const MemOperand& x);
1386 void addrmod3(Instr instr, Register rd, const MemOperand& x);
1387 void addrmod4(Instr instr, Register rn, RegList rl);
1388 void addrmod5(Instr instr, CRegister crd, const MemOperand& x);
1389
1390 // Labels
1391 void print(Label* L);
1392 void bind_to(Label* L, int pos);
1393 void link_to(Label* L, Label* appendix);
1394 void next(Label* L);
1395
1396 // Record reloc info for current pc_
1397 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
1398
1399 friend class RegExpMacroAssemblerARM;
1400 friend class RelocInfo;
1401 friend class CodePatcher;
Steve Block6ded16b2010-05-10 14:33:55 +01001402 friend class BlockConstPoolScope;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001403
1404 PositionsRecorder positions_recorder_;
Steve Block44f0eee2011-05-26 01:26:41 +01001405 bool emit_debug_code_;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001406 friend class PositionsRecorder;
1407 friend class EnsureSpace;
Steve Blocka7e24c12009-10-30 11:49:00 +00001408};
1409
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001410
1411class EnsureSpace BASE_EMBEDDED {
1412 public:
1413 explicit EnsureSpace(Assembler* assembler) {
1414 assembler->CheckBuffer();
1415 }
1416};
1417
1418
Steve Blocka7e24c12009-10-30 11:49:00 +00001419} } // namespace v8::internal
1420
1421#endif // V8_ARM_ASSEMBLER_ARM_H_