blob: 2ab46b3b9e258e4e93d72fd4bc19f030a8b98925 [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 // d0 has been excluded from allocation. This is following ia32
171 // where xmm0 is excluded. This should be revisited.
Ben Murdochb8e0da22011-05-16 14:20:40 +0100172 // Currently d0 is used as a scratch register.
173 // d1 has also been excluded from allocation to be used as a scratch
174 // register as well.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100175 static const int kNumRegisters = 16;
176 static const int kNumAllocatableRegisters = 15;
177
178 static int ToAllocationIndex(DwVfpRegister reg) {
179 ASSERT(reg.code() != 0);
180 return reg.code() - 1;
181 }
182
183 static DwVfpRegister FromAllocationIndex(int index) {
184 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
185 return from_code(index + 1);
186 }
187
188 static const char* AllocationIndexToString(int index) {
189 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
190 const char* const names[] = {
191 "d1",
192 "d2",
193 "d3",
194 "d4",
195 "d5",
196 "d6",
197 "d7",
198 "d8",
199 "d9",
200 "d10",
201 "d11",
202 "d12",
203 "d13",
204 "d14",
205 "d15"
206 };
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;
309
Steve Blocka7e24c12009-10-30 11:49:00 +0000310
311// Coprocessor register
312struct CRegister {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100313 bool is_valid() const { return 0 <= code_ && code_ < 16; }
314 bool is(CRegister creg) const { return code_ == creg.code_; }
315 int code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000316 ASSERT(is_valid());
317 return code_;
318 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100319 int bit() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000320 ASSERT(is_valid());
321 return 1 << code_;
322 }
323
Andrei Popescu31002712010-02-23 13:46:05 +0000324 // Unfortunately we can't make this private in a struct.
Steve Blocka7e24c12009-10-30 11:49:00 +0000325 int code_;
326};
327
328
Steve Block6ded16b2010-05-10 14:33:55 +0100329const CRegister no_creg = { -1 };
330
331const CRegister cr0 = { 0 };
332const CRegister cr1 = { 1 };
333const CRegister cr2 = { 2 };
334const CRegister cr3 = { 3 };
335const CRegister cr4 = { 4 };
336const CRegister cr5 = { 5 };
337const CRegister cr6 = { 6 };
338const CRegister cr7 = { 7 };
339const CRegister cr8 = { 8 };
340const CRegister cr9 = { 9 };
341const CRegister cr10 = { 10 };
342const CRegister cr11 = { 11 };
343const CRegister cr12 = { 12 };
344const CRegister cr13 = { 13 };
345const CRegister cr14 = { 14 };
346const CRegister cr15 = { 15 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000347
348
349// Coprocessor number
350enum Coprocessor {
351 p0 = 0,
352 p1 = 1,
353 p2 = 2,
354 p3 = 3,
355 p4 = 4,
356 p5 = 5,
357 p6 = 6,
358 p7 = 7,
359 p8 = 8,
360 p9 = 9,
361 p10 = 10,
362 p11 = 11,
363 p12 = 12,
364 p13 = 13,
365 p14 = 14,
366 p15 = 15
367};
368
369
Steve Blocka7e24c12009-10-30 11:49:00 +0000370// -----------------------------------------------------------------------------
371// Machine instruction Operands
372
373// Class Operand represents a shifter operand in data processing instructions
374class Operand BASE_EMBEDDED {
375 public:
376 // immediate
377 INLINE(explicit Operand(int32_t immediate,
378 RelocInfo::Mode rmode = RelocInfo::NONE));
379 INLINE(explicit Operand(const ExternalReference& f));
380 INLINE(explicit Operand(const char* s));
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_; }
Kristian Monsen25f61362010-05-21 11:50:48 +0100458
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100459 bool OffsetIsUint12Encodable() const {
460 return offset_ >= 0 ? is_uint12(offset_) : is_uint12(-offset_);
461 }
462
Steve Blocka7e24c12009-10-30 11:49:00 +0000463 private:
464 Register rn_; // base
465 Register rm_; // register offset
466 int32_t offset_; // valid if rm_ == no_reg
467 ShiftOp shift_op_;
468 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
469 AddrMode am_; // bits P, U, and W
470
471 friend class Assembler;
472};
473
Steve Blockd0582a62009-12-15 09:54:21 +0000474// CpuFeatures keeps track of which features are supported by the target CPU.
475// Supported features must be enabled by a Scope before use.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100476class CpuFeatures : public AllStatic {
Steve Blockd0582a62009-12-15 09:54:21 +0000477 public:
478 // Detect features of the target CPU. Set safe defaults if the serializer
479 // is enabled (snapshots must be portable).
Ben Murdoch8b112d22011-06-08 16:22:53 +0100480 static void Probe();
Steve Blockd0582a62009-12-15 09:54:21 +0000481
482 // Check whether a feature is supported by the target CPU.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100483 static bool IsSupported(CpuFeature f) {
484 ASSERT(initialized_);
Steve Blockd0582a62009-12-15 09:54:21 +0000485 if (f == VFP3 && !FLAG_enable_vfp3) return false;
486 return (supported_ & (1u << f)) != 0;
487 }
488
Ben Murdoch8b112d22011-06-08 16:22:53 +0100489#ifdef DEBUG
Steve Blockd0582a62009-12-15 09:54:21 +0000490 // Check whether a feature is currently enabled.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100491 static bool IsEnabled(CpuFeature f) {
492 ASSERT(initialized_);
493 Isolate* isolate = Isolate::UncheckedCurrent();
494 if (isolate == NULL) {
495 // When no isolate is available, work as if we're running in
496 // release mode.
497 return IsSupported(f);
498 }
499 unsigned enabled = static_cast<unsigned>(isolate->enabled_cpu_features());
500 return (enabled & (1u << f)) != 0;
Steve Blockd0582a62009-12-15 09:54:21 +0000501 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100502#endif
Steve Blockd0582a62009-12-15 09:54:21 +0000503
504 // Enable a specified feature within a scope.
505 class Scope BASE_EMBEDDED {
506#ifdef DEBUG
507 public:
Ben Murdoch8b112d22011-06-08 16:22:53 +0100508 explicit Scope(CpuFeature f) {
509 unsigned mask = 1u << f;
510 ASSERT(CpuFeatures::IsSupported(f));
Steve Blockd0582a62009-12-15 09:54:21 +0000511 ASSERT(!Serializer::enabled() ||
Ben Murdoch8b112d22011-06-08 16:22:53 +0100512 (CpuFeatures::found_by_runtime_probing_ & mask) == 0);
513 isolate_ = Isolate::UncheckedCurrent();
514 old_enabled_ = 0;
515 if (isolate_ != NULL) {
516 old_enabled_ = static_cast<unsigned>(isolate_->enabled_cpu_features());
517 isolate_->set_enabled_cpu_features(old_enabled_ | mask);
518 }
Steve Blockd0582a62009-12-15 09:54:21 +0000519 }
Steve Block44f0eee2011-05-26 01:26:41 +0100520 ~Scope() {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100521 ASSERT_EQ(Isolate::UncheckedCurrent(), isolate_);
522 if (isolate_ != NULL) {
523 isolate_->set_enabled_cpu_features(old_enabled_);
524 }
Steve Block44f0eee2011-05-26 01:26:41 +0100525 }
Steve Blockd0582a62009-12-15 09:54:21 +0000526 private:
Steve Block44f0eee2011-05-26 01:26:41 +0100527 Isolate* isolate_;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100528 unsigned old_enabled_;
Steve Blockd0582a62009-12-15 09:54:21 +0000529#else
530 public:
531 explicit Scope(CpuFeature f) {}
532#endif
533 };
534
Ben Murdoch8b112d22011-06-08 16:22:53 +0100535 class TryForceFeatureScope BASE_EMBEDDED {
536 public:
537 explicit TryForceFeatureScope(CpuFeature f)
538 : old_supported_(CpuFeatures::supported_) {
539 if (CanForce()) {
540 CpuFeatures::supported_ |= (1u << f);
541 }
542 }
543
544 ~TryForceFeatureScope() {
545 if (CanForce()) {
546 CpuFeatures::supported_ = old_supported_;
547 }
548 }
549
550 private:
551 static bool CanForce() {
552 // It's only safe to temporarily force support of CPU features
553 // when there's only a single isolate, which is guaranteed when
554 // the serializer is enabled.
555 return Serializer::enabled();
556 }
557
558 const unsigned old_supported_;
559 };
560
Steve Blockd0582a62009-12-15 09:54:21 +0000561 private:
Ben Murdoch8b112d22011-06-08 16:22:53 +0100562#ifdef DEBUG
563 static bool initialized_;
564#endif
565 static unsigned supported_;
566 static unsigned found_by_runtime_probing_;
Steve Block44f0eee2011-05-26 01:26:41 +0100567
568 DISALLOW_COPY_AND_ASSIGN(CpuFeatures);
Steve Blockd0582a62009-12-15 09:54:21 +0000569};
570
Steve Blocka7e24c12009-10-30 11:49:00 +0000571
Steve Blocka7e24c12009-10-30 11:49:00 +0000572extern const Instr kMovLrPc;
Steve Block6ded16b2010-05-10 14:33:55 +0100573extern const Instr kLdrPCMask;
Steve Blocka7e24c12009-10-30 11:49:00 +0000574extern const Instr kLdrPCPattern;
Steve Block6ded16b2010-05-10 14:33:55 +0100575extern const Instr kBlxRegMask;
576extern const Instr kBlxRegPattern;
Steve Blocka7e24c12009-10-30 11:49:00 +0000577
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100578extern const Instr kMovMvnMask;
579extern const Instr kMovMvnPattern;
580extern const Instr kMovMvnFlip;
581
582extern const Instr kMovLeaveCCMask;
583extern const Instr kMovLeaveCCPattern;
584extern const Instr kMovwMask;
585extern const Instr kMovwPattern;
586extern const Instr kMovwLeaveCCFlip;
587
588extern const Instr kCmpCmnMask;
589extern const Instr kCmpCmnPattern;
590extern const Instr kCmpCmnFlip;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100591extern const Instr kAddSubFlip;
592extern const Instr kAndBicFlip;
Steve Blocka7e24c12009-10-30 11:49:00 +0000593
Steve Block1e0659c2011-05-24 12:43:12 +0100594
595
Steve Block44f0eee2011-05-26 01:26:41 +0100596class Assembler : public AssemblerBase {
Steve Blocka7e24c12009-10-30 11:49:00 +0000597 public:
598 // Create an assembler. Instructions and relocation information are emitted
599 // into a buffer, with the instructions starting from the beginning and the
600 // relocation information starting from the end of the buffer. See CodeDesc
601 // for a detailed comment on the layout (globals.h).
602 //
603 // If the provided buffer is NULL, the assembler allocates and grows its own
604 // buffer, and buffer_size determines the initial buffer size. The buffer is
605 // owned by the assembler and deallocated upon destruction of the assembler.
606 //
607 // If the provided buffer is not NULL, the assembler uses the provided buffer
608 // for code generation and assumes its size to be buffer_size. If the buffer
609 // is too small, a fatal error occurs. No deallocation of the buffer is done
610 // upon destruction of the assembler.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100611 Assembler(Isolate* isolate, void* buffer, int buffer_size);
Steve Blocka7e24c12009-10-30 11:49:00 +0000612 ~Assembler();
613
Steve Block44f0eee2011-05-26 01:26:41 +0100614 // Overrides the default provided by FLAG_debug_code.
615 void set_emit_debug_code(bool value) { emit_debug_code_ = value; }
616
Steve Blocka7e24c12009-10-30 11:49:00 +0000617 // GetCode emits any pending (non-emitted) code and fills the descriptor
618 // desc. GetCode() is idempotent; it returns the same result if no other
619 // Assembler functions are invoked in between GetCode() calls.
620 void GetCode(CodeDesc* desc);
621
622 // Label operations & relative jumps (PPUM Appendix D)
623 //
624 // Takes a branch opcode (cc) and a label (L) and generates
625 // either a backward branch or a forward branch and links it
626 // to the label fixup chain. Usage:
627 //
628 // Label L; // unbound label
629 // j(cc, &L); // forward branch to unbound label
630 // bind(&L); // bind label to the current pc
631 // j(cc, &L); // backward branch to bound label
632 // bind(&L); // illegal: a label may be bound only once
633 //
634 // Note: The same Label can be used for forward and backward branches
635 // but it may be bound only once.
636
637 void bind(Label* L); // binds an unbound label L to the current code position
638
639 // Returns the branch offset to the given label from the current code position
640 // Links the label to the current position if it is still unbound
641 // Manages the jump elimination optimization if the second parameter is true.
642 int branch_offset(Label* L, bool jump_elimination_allowed);
643
644 // Puts a labels target address at the given position.
645 // The high 8 bits are set to zero.
646 void label_at_put(Label* L, int at_offset);
647
648 // Return the address in the constant pool of the code target address used by
649 // the branch/call instruction at pc.
650 INLINE(static Address target_address_address_at(Address pc));
651
652 // Read/Modify the code target address in the branch/call instruction at pc.
653 INLINE(static Address target_address_at(Address pc));
654 INLINE(static void set_target_address_at(Address pc, Address target));
655
Steve Blockd0582a62009-12-15 09:54:21 +0000656 // This sets the branch destination (which is in the constant pool on ARM).
657 // This is for calls and branches within generated code.
658 inline static void set_target_at(Address constant_pool_entry, Address target);
659
660 // This sets the branch destination (which is in the constant pool on ARM).
661 // This is for calls and branches to runtime code.
662 inline static void set_external_target_at(Address constant_pool_entry,
663 Address target) {
664 set_target_at(constant_pool_entry, target);
665 }
666
667 // Here we are patching the address in the constant pool, not the actual call
668 // instruction. The address in the constant pool is the same size as a
669 // pointer.
670 static const int kCallTargetSize = kPointerSize;
671 static const int kExternalTargetSize = kPointerSize;
672
Steve Blocka7e24c12009-10-30 11:49:00 +0000673 // Size of an instruction.
674 static const int kInstrSize = sizeof(Instr);
675
676 // Distance between the instruction referring to the address of the call
Steve Block6ded16b2010-05-10 14:33:55 +0100677 // target and the return address.
678#ifdef USE_BLX
679 // Call sequence is:
680 // ldr ip, [pc, #...] @ call address
681 // blx ip
682 // @ return address
683 static const int kCallTargetAddressOffset = 2 * kInstrSize;
684#else
685 // Call sequence is:
686 // mov lr, pc
687 // ldr pc, [pc, #...] @ call address
688 // @ return address
Steve Blocka7e24c12009-10-30 11:49:00 +0000689 static const int kCallTargetAddressOffset = kInstrSize;
Steve Block6ded16b2010-05-10 14:33:55 +0100690#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000691
692 // Distance between start of patched return sequence and the emitted address
693 // to jump to.
Steve Block6ded16b2010-05-10 14:33:55 +0100694#ifdef USE_BLX
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100695 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100696 // ldr ip, [pc, #0] @ emited address and start
697 // blx ip
698 static const int kPatchReturnSequenceAddressOffset = 0 * kInstrSize;
699#else
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100700 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100701 // mov lr, pc @ start of sequence
702 // ldr pc, [pc, #-4] @ emited address
703 static const int kPatchReturnSequenceAddressOffset = kInstrSize;
704#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000705
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100706 // Distance between start of patched debug break slot and the emitted address
707 // to jump to.
708#ifdef USE_BLX
709 // Patched debug break slot code is:
710 // ldr ip, [pc, #0] @ emited address and start
711 // blx ip
712 static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
713#else
714 // Patched debug break slot code is:
715 // mov lr, pc @ start of sequence
716 // ldr pc, [pc, #-4] @ emited address
717 static const int kPatchDebugBreakSlotAddressOffset = kInstrSize;
718#endif
719
Steve Blocka7e24c12009-10-30 11:49:00 +0000720 // Difference between address of current opcode and value read from pc
721 // register.
722 static const int kPcLoadDelta = 8;
723
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100724 static const int kJSReturnSequenceInstructions = 4;
725 static const int kDebugBreakSlotInstructions = 3;
726 static const int kDebugBreakSlotLength =
727 kDebugBreakSlotInstructions * kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +0000728
729 // ---------------------------------------------------------------------------
730 // Code generation
731
732 // Insert the smallest number of nop instructions
733 // possible to align the pc offset to a multiple
734 // of m. m must be a power of 2 (>= 4).
735 void Align(int m);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100736 // Aligns code to something that's optimal for a jump target for the platform.
737 void CodeTargetAlign();
Steve Blocka7e24c12009-10-30 11:49:00 +0000738
739 // Branch instructions
740 void b(int branch_offset, Condition cond = al);
741 void bl(int branch_offset, Condition cond = al);
742 void blx(int branch_offset); // v5 and above
743 void blx(Register target, Condition cond = al); // v5 and above
744 void bx(Register target, Condition cond = al); // v5 and above, plus v4t
745
746 // Convenience branch instructions using labels
747 void b(Label* L, Condition cond = al) {
748 b(branch_offset(L, cond == al), cond);
749 }
750 void b(Condition cond, Label* L) { b(branch_offset(L, cond == al), cond); }
751 void bl(Label* L, Condition cond = al) { bl(branch_offset(L, false), cond); }
752 void bl(Condition cond, Label* L) { bl(branch_offset(L, false), cond); }
753 void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above
754
755 // Data-processing instructions
Andrei Popescu31002712010-02-23 13:46:05 +0000756
Steve Blocka7e24c12009-10-30 11:49:00 +0000757 void and_(Register dst, Register src1, const Operand& src2,
758 SBit s = LeaveCC, Condition cond = al);
759
760 void eor(Register dst, Register src1, const Operand& src2,
761 SBit s = LeaveCC, Condition cond = al);
762
763 void sub(Register dst, Register src1, const Operand& src2,
764 SBit s = LeaveCC, Condition cond = al);
765 void sub(Register dst, Register src1, Register src2,
766 SBit s = LeaveCC, Condition cond = al) {
767 sub(dst, src1, Operand(src2), s, cond);
768 }
769
770 void rsb(Register dst, Register src1, const Operand& src2,
771 SBit s = LeaveCC, Condition cond = al);
772
773 void add(Register dst, Register src1, const Operand& src2,
774 SBit s = LeaveCC, Condition cond = al);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100775 void add(Register dst, Register src1, Register src2,
776 SBit s = LeaveCC, Condition cond = al) {
777 add(dst, src1, Operand(src2), s, cond);
778 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000779
780 void adc(Register dst, Register src1, const Operand& src2,
781 SBit s = LeaveCC, Condition cond = al);
782
783 void sbc(Register dst, Register src1, const Operand& src2,
784 SBit s = LeaveCC, Condition cond = al);
785
786 void rsc(Register dst, Register src1, const Operand& src2,
787 SBit s = LeaveCC, Condition cond = al);
788
789 void tst(Register src1, const Operand& src2, Condition cond = al);
790 void tst(Register src1, Register src2, Condition cond = al) {
791 tst(src1, Operand(src2), cond);
792 }
793
794 void teq(Register src1, const Operand& src2, Condition cond = al);
795
796 void cmp(Register src1, const Operand& src2, Condition cond = al);
797 void cmp(Register src1, Register src2, Condition cond = al) {
798 cmp(src1, Operand(src2), cond);
799 }
Steve Block1e0659c2011-05-24 12:43:12 +0100800 void cmp_raw_immediate(Register src1, int raw_immediate, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000801
802 void cmn(Register src1, const Operand& src2, Condition cond = al);
803
804 void orr(Register dst, Register src1, const Operand& src2,
805 SBit s = LeaveCC, Condition cond = al);
806 void orr(Register dst, Register src1, Register src2,
807 SBit s = LeaveCC, Condition cond = al) {
808 orr(dst, src1, Operand(src2), s, cond);
809 }
810
811 void mov(Register dst, const Operand& src,
812 SBit s = LeaveCC, Condition cond = al);
813 void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
814 mov(dst, Operand(src), s, cond);
815 }
816
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100817 // ARMv7 instructions for loading a 32 bit immediate in two instructions.
818 // This may actually emit a different mov instruction, but on an ARMv7 it
819 // is guaranteed to only emit one instruction.
820 void movw(Register reg, uint32_t immediate, Condition cond = al);
821 // The constant for movt should be in the range 0-0xffff.
822 void movt(Register reg, uint32_t immediate, Condition cond = al);
823
Steve Blocka7e24c12009-10-30 11:49:00 +0000824 void bic(Register dst, Register src1, const Operand& src2,
825 SBit s = LeaveCC, Condition cond = al);
826
827 void mvn(Register dst, const Operand& src,
828 SBit s = LeaveCC, Condition cond = al);
829
830 // Multiply instructions
831
832 void mla(Register dst, Register src1, Register src2, Register srcA,
833 SBit s = LeaveCC, Condition cond = al);
834
835 void mul(Register dst, Register src1, Register src2,
836 SBit s = LeaveCC, Condition cond = al);
837
838 void smlal(Register dstL, Register dstH, Register src1, Register src2,
839 SBit s = LeaveCC, Condition cond = al);
840
841 void smull(Register dstL, Register dstH, Register src1, Register src2,
842 SBit s = LeaveCC, Condition cond = al);
843
844 void umlal(Register dstL, Register dstH, Register src1, Register src2,
845 SBit s = LeaveCC, Condition cond = al);
846
847 void umull(Register dstL, Register dstH, Register src1, Register src2,
848 SBit s = LeaveCC, Condition cond = al);
849
850 // Miscellaneous arithmetic instructions
851
852 void clz(Register dst, Register src, Condition cond = al); // v5 and above
853
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100854 // Saturating instructions. v6 and above.
855
856 // Unsigned saturate.
857 //
858 // Saturate an optionally shifted signed value to an unsigned range.
859 //
860 // usat dst, #satpos, src
861 // usat dst, #satpos, src, lsl #sh
862 // usat dst, #satpos, src, asr #sh
863 //
864 // Register dst will contain:
865 //
866 // 0, if s < 0
867 // (1 << satpos) - 1, if s > ((1 << satpos) - 1)
868 // s, otherwise
869 //
870 // where s is the contents of src after shifting (if used.)
871 void usat(Register dst, int satpos, const Operand& src, Condition cond = al);
872
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100873 // Bitfield manipulation instructions. v7 and above.
874
875 void ubfx(Register dst, Register src, int lsb, int width,
876 Condition cond = al);
877
878 void sbfx(Register dst, Register src, int lsb, int width,
879 Condition cond = al);
880
881 void bfc(Register dst, int lsb, int width, Condition cond = al);
882
883 void bfi(Register dst, Register src, int lsb, int width,
884 Condition cond = al);
885
Steve Blocka7e24c12009-10-30 11:49:00 +0000886 // Status register access instructions
887
888 void mrs(Register dst, SRegister s, Condition cond = al);
889 void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al);
890
891 // Load/Store instructions
892 void ldr(Register dst, const MemOperand& src, Condition cond = al);
893 void str(Register src, const MemOperand& dst, Condition cond = al);
894 void ldrb(Register dst, const MemOperand& src, Condition cond = al);
895 void strb(Register src, const MemOperand& dst, Condition cond = al);
896 void ldrh(Register dst, const MemOperand& src, Condition cond = al);
897 void strh(Register src, const MemOperand& dst, Condition cond = al);
898 void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
899 void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
Leon Clarkef7060e22010-06-03 12:02:55 +0100900 void ldrd(Register dst1,
901 Register dst2,
902 const MemOperand& src, Condition cond = al);
903 void strd(Register src1,
904 Register src2,
905 const MemOperand& dst, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000906
907 // Load/Store multiple instructions
908 void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
909 void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
910
Steve Blocka7e24c12009-10-30 11:49:00 +0000911 // Exception-generating instructions and debugging support
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800912 void stop(const char* msg,
913 Condition cond = al,
914 int32_t code = kDefaultStopCode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000915
916 void bkpt(uint32_t imm16); // v5 and above
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800917 void svc(uint32_t imm24, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000918
919 // Coprocessor instructions
920
921 void cdp(Coprocessor coproc, int opcode_1,
922 CRegister crd, CRegister crn, CRegister crm,
923 int opcode_2, Condition cond = al);
924
925 void cdp2(Coprocessor coproc, int opcode_1,
926 CRegister crd, CRegister crn, CRegister crm,
927 int opcode_2); // v5 and above
928
929 void mcr(Coprocessor coproc, int opcode_1,
930 Register rd, CRegister crn, CRegister crm,
931 int opcode_2 = 0, Condition cond = al);
932
933 void mcr2(Coprocessor coproc, int opcode_1,
934 Register rd, CRegister crn, CRegister crm,
935 int opcode_2 = 0); // v5 and above
936
937 void mrc(Coprocessor coproc, int opcode_1,
938 Register rd, CRegister crn, CRegister crm,
939 int opcode_2 = 0, Condition cond = al);
940
941 void mrc2(Coprocessor coproc, int opcode_1,
942 Register rd, CRegister crn, CRegister crm,
943 int opcode_2 = 0); // v5 and above
944
945 void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src,
946 LFlag l = Short, Condition cond = al);
947 void ldc(Coprocessor coproc, CRegister crd, Register base, int option,
948 LFlag l = Short, Condition cond = al);
949
950 void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
951 LFlag l = Short); // v5 and above
952 void ldc2(Coprocessor coproc, CRegister crd, Register base, int option,
953 LFlag l = Short); // v5 and above
954
Steve Blockd0582a62009-12-15 09:54:21 +0000955 // Support for VFP.
956 // All these APIs support S0 to S31 and D0 to D15.
957 // Currently these APIs do not support extended D registers, i.e, D16 to D31.
958 // However, some simple modifications can allow
959 // these APIs to support D16 to D31.
960
Leon Clarked91b9f72010-01-27 17:25:45 +0000961 void vldr(const DwVfpRegister dst,
962 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100963 int offset,
964 const Condition cond = al);
965 void vldr(const DwVfpRegister dst,
966 const MemOperand& src,
Leon Clarked91b9f72010-01-27 17:25:45 +0000967 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +0100968
969 void vldr(const SwVfpRegister dst,
970 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100971 int offset,
972 const Condition cond = al);
973 void vldr(const SwVfpRegister dst,
974 const MemOperand& src,
Steve Block6ded16b2010-05-10 14:33:55 +0100975 const Condition cond = al);
976
Leon Clarked91b9f72010-01-27 17:25:45 +0000977 void vstr(const DwVfpRegister src,
978 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100979 int offset,
980 const Condition cond = al);
981 void vstr(const DwVfpRegister src,
982 const MemOperand& dst,
Leon Clarked91b9f72010-01-27 17:25:45 +0000983 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +0100984
Iain Merrick75681382010-08-19 15:07:18 +0100985 void vstr(const SwVfpRegister src,
986 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100987 int offset,
988 const Condition cond = al);
989 void vstr(const SwVfpRegister src,
990 const MemOperand& dst,
Iain Merrick75681382010-08-19 15:07:18 +0100991 const Condition cond = al);
992
Ben Murdoch8b112d22011-06-08 16:22:53 +0100993 void vldm(BlockAddrMode am,
994 Register base,
995 DwVfpRegister first,
996 DwVfpRegister last,
997 Condition cond = al);
998
999 void vstm(BlockAddrMode am,
1000 Register base,
1001 DwVfpRegister first,
1002 DwVfpRegister last,
1003 Condition cond = al);
1004
1005 void vldm(BlockAddrMode am,
1006 Register base,
1007 SwVfpRegister first,
1008 SwVfpRegister last,
1009 Condition cond = al);
1010
1011 void vstm(BlockAddrMode am,
1012 Register base,
1013 SwVfpRegister first,
1014 SwVfpRegister last,
1015 Condition cond = al);
1016
Steve Block8defd9f2010-07-08 12:39:36 +01001017 void vmov(const DwVfpRegister dst,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001018 double imm,
1019 const Condition cond = al);
1020 void vmov(const SwVfpRegister dst,
1021 const SwVfpRegister src,
1022 const Condition cond = al);
1023 void vmov(const DwVfpRegister dst,
Steve Block8defd9f2010-07-08 12:39:36 +01001024 const DwVfpRegister src,
1025 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001026 void vmov(const DwVfpRegister dst,
1027 const Register src1,
Steve Blockd0582a62009-12-15 09:54:21 +00001028 const Register src2,
Leon Clarkee46be812010-01-19 14:06:41 +00001029 const Condition cond = al);
1030 void vmov(const Register dst1,
1031 const Register dst2,
1032 const DwVfpRegister src,
1033 const Condition cond = al);
1034 void vmov(const SwVfpRegister dst,
1035 const Register src,
1036 const Condition cond = al);
1037 void vmov(const Register dst,
1038 const SwVfpRegister src,
1039 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +01001040 void vcvt_f64_s32(const DwVfpRegister dst,
1041 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001042 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001043 const Condition cond = al);
1044 void vcvt_f32_s32(const SwVfpRegister 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_f64_u32(const DwVfpRegister 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_s32_f64(const SwVfpRegister dst,
1053 const DwVfpRegister 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_u32_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_f64_f32(const DwVfpRegister dst,
1061 const SwVfpRegister 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_f32_f64(const SwVfpRegister dst,
1065 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001066 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001067 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001068
Steve Block44f0eee2011-05-26 01:26:41 +01001069 void vneg(const DwVfpRegister dst,
1070 const DwVfpRegister src,
1071 const Condition cond = al);
Steve Block1e0659c2011-05-24 12:43:12 +01001072 void vabs(const DwVfpRegister dst,
1073 const DwVfpRegister src,
1074 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001075 void vadd(const DwVfpRegister dst,
1076 const DwVfpRegister src1,
1077 const DwVfpRegister src2,
1078 const Condition cond = al);
1079 void vsub(const DwVfpRegister dst,
1080 const DwVfpRegister src1,
1081 const DwVfpRegister src2,
1082 const Condition cond = al);
1083 void vmul(const DwVfpRegister dst,
1084 const DwVfpRegister src1,
1085 const DwVfpRegister src2,
1086 const Condition cond = al);
1087 void vdiv(const DwVfpRegister dst,
1088 const DwVfpRegister src1,
1089 const DwVfpRegister src2,
1090 const Condition cond = al);
1091 void vcmp(const DwVfpRegister src1,
1092 const DwVfpRegister src2,
Steve Blockd0582a62009-12-15 09:54:21 +00001093 const Condition cond = al);
Iain Merrick75681382010-08-19 15:07:18 +01001094 void vcmp(const DwVfpRegister src1,
1095 const double src2,
Iain Merrick75681382010-08-19 15:07:18 +01001096 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001097 void vmrs(const Register dst,
1098 const Condition cond = al);
Russell Brenner90bac252010-11-18 13:33:46 -08001099 void vmsr(const Register dst,
1100 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +01001101 void vsqrt(const DwVfpRegister dst,
1102 const DwVfpRegister src,
1103 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001104
Steve Blocka7e24c12009-10-30 11:49:00 +00001105 // Pseudo instructions
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001106
1107 // Different nop operations are used by the code generator to detect certain
1108 // states of the generated code.
1109 enum NopMarkerTypes {
1110 NON_MARKING_NOP = 0,
1111 DEBUG_BREAK_NOP,
1112 // IC markers.
1113 PROPERTY_ACCESS_INLINED,
1114 PROPERTY_ACCESS_INLINED_CONTEXT,
1115 PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE,
1116 // Helper values.
1117 LAST_CODE_MARKER,
1118 FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED
1119 };
1120
1121 void nop(int type = 0); // 0 is the default non-marking type.
Steve Blocka7e24c12009-10-30 11:49:00 +00001122
1123 void push(Register src, Condition cond = al) {
1124 str(src, MemOperand(sp, 4, NegPreIndex), cond);
1125 }
1126
1127 void pop(Register dst, Condition cond = al) {
1128 ldr(dst, MemOperand(sp, 4, PostIndex), cond);
1129 }
1130
1131 void pop() {
1132 add(sp, sp, Operand(kPointerSize));
1133 }
1134
Steve Blocka7e24c12009-10-30 11:49:00 +00001135 // Jump unconditionally to given label.
1136 void jmp(Label* L) { b(L, al); }
1137
1138 // Check the code size generated from label to here.
1139 int InstructionsGeneratedSince(Label* l) {
1140 return (pc_offset() - l->pos()) / kInstrSize;
1141 }
1142
Steve Blockd0582a62009-12-15 09:54:21 +00001143 // Check whether an immediate fits an addressing mode 1 instruction.
1144 bool ImmediateFitsAddrMode1Instruction(int32_t imm32);
1145
Steve Block6ded16b2010-05-10 14:33:55 +01001146 // Class for scoping postponing the constant pool generation.
1147 class BlockConstPoolScope {
1148 public:
1149 explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) {
1150 assem_->StartBlockConstPool();
1151 }
1152 ~BlockConstPoolScope() {
1153 assem_->EndBlockConstPool();
1154 }
1155
1156 private:
1157 Assembler* assem_;
1158
1159 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstPoolScope);
1160 };
1161
Steve Blockd0582a62009-12-15 09:54:21 +00001162 // Postpone the generation of the constant pool for the specified number of
1163 // instructions.
1164 void BlockConstPoolFor(int instructions);
1165
Steve Blocka7e24c12009-10-30 11:49:00 +00001166 // Debugging
1167
1168 // Mark address of the ExitJSFrame code.
1169 void RecordJSReturn();
1170
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001171 // Mark address of a debug break slot.
1172 void RecordDebugBreakSlot();
1173
Ben Murdoch257744e2011-11-30 15:57:28 +00001174 // Record the AST id of the CallIC being compiled, so that it can be placed
1175 // in the relocation information.
1176 void RecordAstId(unsigned ast_id) { ast_id_for_reloc_info_ = ast_id; }
1177
Steve Blocka7e24c12009-10-30 11:49:00 +00001178 // Record a comment relocation entry that can be used by a disassembler.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001179 // Use --code-comments to enable.
Steve Blocka7e24c12009-10-30 11:49:00 +00001180 void RecordComment(const char* msg);
1181
Ben Murdochb8e0da22011-05-16 14:20:40 +01001182 // Writes a single byte or word of data in the code stream. Used
1183 // for inline tables, e.g., jump-tables. The constant pool should be
1184 // emitted before any use of db and dd to ensure that constant pools
1185 // are not emitted as part of the tables generated.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001186 void db(uint8_t data);
1187 void dd(uint32_t data);
1188
Steve Blocka7e24c12009-10-30 11:49:00 +00001189 int pc_offset() const { return pc_ - buffer_; }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001190
1191 PositionsRecorder* positions_recorder() { return &positions_recorder_; }
Steve Block6ded16b2010-05-10 14:33:55 +01001192
1193 // Read/patch instructions
1194 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
1195 static void instr_at_put(byte* pc, Instr instr) {
1196 *reinterpret_cast<Instr*>(pc) = instr;
1197 }
Steve Block1e0659c2011-05-24 12:43:12 +01001198 static Condition GetCondition(Instr instr);
Steve Block6ded16b2010-05-10 14:33:55 +01001199 static bool IsBranch(Instr instr);
1200 static int GetBranchOffset(Instr instr);
1201 static bool IsLdrRegisterImmediate(Instr instr);
1202 static int GetLdrRegisterImmediateOffset(Instr instr);
1203 static Instr SetLdrRegisterImmediateOffset(Instr instr, int offset);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001204 static bool IsStrRegisterImmediate(Instr instr);
1205 static Instr SetStrRegisterImmediateOffset(Instr instr, int offset);
1206 static bool IsAddRegisterImmediate(Instr instr);
1207 static Instr SetAddRegisterImmediateOffset(Instr instr, int offset);
Leon Clarkef7060e22010-06-03 12:02:55 +01001208 static Register GetRd(Instr instr);
Steve Block1e0659c2011-05-24 12:43:12 +01001209 static Register GetRn(Instr instr);
1210 static Register GetRm(Instr instr);
Leon Clarkef7060e22010-06-03 12:02:55 +01001211 static bool IsPush(Instr instr);
1212 static bool IsPop(Instr instr);
1213 static bool IsStrRegFpOffset(Instr instr);
1214 static bool IsLdrRegFpOffset(Instr instr);
1215 static bool IsStrRegFpNegOffset(Instr instr);
1216 static bool IsLdrRegFpNegOffset(Instr instr);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001217 static bool IsLdrPcImmediateOffset(Instr instr);
Steve Block1e0659c2011-05-24 12:43:12 +01001218 static bool IsTstImmediate(Instr instr);
1219 static bool IsCmpRegister(Instr instr);
1220 static bool IsCmpImmediate(Instr instr);
1221 static Register GetCmpImmediateRegister(Instr instr);
1222 static int GetCmpImmediateRawImmediate(Instr instr);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001223 static bool IsNop(Instr instr, int type = NON_MARKING_NOP);
Steve Block6ded16b2010-05-10 14:33:55 +01001224
Ben Murdoch257744e2011-11-30 15:57:28 +00001225 // Buffer size and constant pool distance are checked together at regular
1226 // intervals of kBufferCheckInterval emitted bytes
1227 static const int kBufferCheckInterval = 1*KB/2;
1228 // Constants in pools are accessed via pc relative addressing, which can
1229 // reach +/-4KB thereby defining a maximum distance between the instruction
1230 // and the accessed constant. We satisfy this constraint by limiting the
1231 // distance between pools.
1232 static const int kMaxDistBetweenPools = 4*KB - 2*kBufferCheckInterval;
1233 static const int kMaxNumPRInfo = kMaxDistBetweenPools/kInstrSize;
1234
Ben Murdochb0fe1622011-05-05 13:52:32 +01001235 // Check if is time to emit a constant pool for pending reloc info entries
1236 void CheckConstPool(bool force_emit, bool require_jump);
Steve Blocka7e24c12009-10-30 11:49:00 +00001237
1238 protected:
Ben Murdoch257744e2011-11-30 15:57:28 +00001239 // Relocation for a type-recording IC has the AST id added to it. This
1240 // member variable is a way to pass the information from the call site to
1241 // the relocation info.
1242 unsigned ast_id_for_reloc_info_;
1243
Steve Block44f0eee2011-05-26 01:26:41 +01001244 bool emit_debug_code() const { return emit_debug_code_; }
1245
Steve Blocka7e24c12009-10-30 11:49:00 +00001246 int buffer_space() const { return reloc_info_writer.pos() - pc_; }
1247
1248 // Read/patch instructions
Steve Blocka7e24c12009-10-30 11:49:00 +00001249 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
1250 void instr_at_put(int pos, Instr instr) {
1251 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
1252 }
1253
1254 // Decode branch instruction at pos and return branch target pos
1255 int target_at(int pos);
1256
1257 // Patch branch instruction at pos to branch to given branch target pos
1258 void target_at_put(int pos, int target_pos);
1259
Steve Blocka7e24c12009-10-30 11:49:00 +00001260 // Block the emission of the constant pool before pc_offset
1261 void BlockConstPoolBefore(int pc_offset) {
1262 if (no_const_pool_before_ < pc_offset) no_const_pool_before_ = pc_offset;
1263 }
1264
Steve Block6ded16b2010-05-10 14:33:55 +01001265 void StartBlockConstPool() {
1266 const_pool_blocked_nesting_++;
1267 }
1268 void EndBlockConstPool() {
1269 const_pool_blocked_nesting_--;
1270 }
Steve Block8defd9f2010-07-08 12:39:36 +01001271 bool is_const_pool_blocked() const { return const_pool_blocked_nesting_ > 0; }
Steve Block6ded16b2010-05-10 14:33:55 +01001272
Steve Blocka7e24c12009-10-30 11:49:00 +00001273 private:
1274 // Code buffer:
1275 // The buffer into which code and relocation info are generated.
1276 byte* buffer_;
1277 int buffer_size_;
1278 // True if the assembler owns the buffer, false if buffer is external.
1279 bool own_buffer_;
1280
Steve Blocka7e24c12009-10-30 11:49:00 +00001281 int next_buffer_check_; // pc offset of next buffer check
1282
1283 // Code generation
1284 // The relocation writer's position is at least kGap bytes below the end of
1285 // the generated instructions. This is so that multi-instruction sequences do
1286 // not have to check for overflow. The same is true for writes of large
1287 // relocation info entries.
1288 static const int kGap = 32;
1289 byte* pc_; // the program counter; moves forward
1290
1291 // Constant pool generation
1292 // Pools are emitted in the instruction stream, preferably after unconditional
1293 // jumps or after returns from functions (in dead code locations).
1294 // If a long code sequence does not contain unconditional jumps, it is
1295 // necessary to emit the constant pool before the pool gets too far from the
1296 // location it is accessed from. In this case, we emit a jump over the emitted
1297 // constant pool.
1298 // Constants in the pool may be addresses of functions that gets relocated;
1299 // if so, a relocation info entry is associated to the constant pool entry.
1300
1301 // Repeated checking whether the constant pool should be emitted is rather
1302 // expensive. By default we only check again once a number of instructions
1303 // has been generated. That also means that the sizing of the buffers is not
1304 // an exact science, and that we rely on some slop to not overrun buffers.
1305 static const int kCheckConstIntervalInst = 32;
1306 static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize;
1307
1308
1309 // Pools are emitted after function return and in dead code at (more or less)
1310 // regular intervals of kDistBetweenPools bytes
1311 static const int kDistBetweenPools = 1*KB;
1312
Steve Block6ded16b2010-05-10 14:33:55 +01001313 // Emission of the constant pool may be blocked in some code sequences.
1314 int const_pool_blocked_nesting_; // Block emission if this is not zero.
1315 int no_const_pool_before_; // Block emission before this pc offset.
Steve Blocka7e24c12009-10-30 11:49:00 +00001316
1317 // Keep track of the last emitted pool to guarantee a maximal distance
1318 int last_const_pool_end_; // pc offset following the last constant pool
1319
1320 // Relocation info generation
1321 // Each relocation is encoded as a variable size value
1322 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1323 RelocInfoWriter reloc_info_writer;
1324 // Relocation info records are also used during code generation as temporary
1325 // containers for constants and code target addresses until they are emitted
1326 // to the constant pool. These pending relocation info records are temporarily
1327 // stored in a separate buffer until a constant pool is emitted.
1328 // If every instruction in a long sequence is accessing the pool, we need one
1329 // pending relocation entry per instruction.
Steve Blocka7e24c12009-10-30 11:49:00 +00001330 RelocInfo prinfo_[kMaxNumPRInfo]; // the buffer of pending relocation info
1331 int num_prinfo_; // number of pending reloc info entries in the buffer
1332
1333 // The bound position, before this we cannot do instruction elimination.
1334 int last_bound_pos_;
1335
Steve Blocka7e24c12009-10-30 11:49:00 +00001336 // Code emission
1337 inline void CheckBuffer();
1338 void GrowBuffer();
1339 inline void emit(Instr x);
1340
1341 // Instruction generation
1342 void addrmod1(Instr instr, Register rn, Register rd, const Operand& x);
1343 void addrmod2(Instr instr, Register rd, const MemOperand& x);
1344 void addrmod3(Instr instr, Register rd, const MemOperand& x);
1345 void addrmod4(Instr instr, Register rn, RegList rl);
1346 void addrmod5(Instr instr, CRegister crd, const MemOperand& x);
1347
1348 // Labels
1349 void print(Label* L);
1350 void bind_to(Label* L, int pos);
1351 void link_to(Label* L, Label* appendix);
1352 void next(Label* L);
1353
1354 // Record reloc info for current pc_
1355 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
1356
1357 friend class RegExpMacroAssemblerARM;
1358 friend class RelocInfo;
1359 friend class CodePatcher;
Steve Block6ded16b2010-05-10 14:33:55 +01001360 friend class BlockConstPoolScope;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001361
1362 PositionsRecorder positions_recorder_;
Steve Block44f0eee2011-05-26 01:26:41 +01001363 bool emit_debug_code_;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001364 friend class PositionsRecorder;
1365 friend class EnsureSpace;
Steve Blocka7e24c12009-10-30 11:49:00 +00001366};
1367
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001368
1369class EnsureSpace BASE_EMBEDDED {
1370 public:
1371 explicit EnsureSpace(Assembler* assembler) {
1372 assembler->CheckBuffer();
1373 }
1374};
1375
1376
Steve Blocka7e24c12009-10-30 11:49:00 +00001377} } // namespace v8::internal
1378
1379#endif // V8_ARM_ASSEMBLER_ARM_H_