blob: 9050c2c5d9bb33a5fdae1ffee14076f2f5b2a454 [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;
75
76 static int ToAllocationIndex(Register reg) {
Steve Block9fac8402011-05-12 15:51:54 +010077 ASSERT(reg.code() < kNumAllocatableRegisters);
Ben Murdochb0fe1622011-05-05 13:52:32 +010078 return reg.code();
79 }
80
81 static Register FromAllocationIndex(int index) {
82 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
83 return from_code(index);
84 }
85
86 static const char* AllocationIndexToString(int index) {
87 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
88 const char* const names[] = {
89 "r0",
90 "r1",
91 "r2",
92 "r3",
93 "r4",
94 "r5",
95 "r6",
96 "r7",
97 };
98 return names[index];
99 }
100
101 static Register from_code(int code) {
102 Register r = { code };
103 return r;
104 }
105
106 bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100107 bool is(Register reg) const { return code_ == reg.code_; }
108 int code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000109 ASSERT(is_valid());
110 return code_;
111 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100112 int bit() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000113 ASSERT(is_valid());
114 return 1 << code_;
115 }
116
Leon Clarkef7060e22010-06-03 12:02:55 +0100117 void set_code(int code) {
118 code_ = code;
119 ASSERT(is_valid());
120 }
121
Andrei Popescu31002712010-02-23 13:46:05 +0000122 // Unfortunately we can't make this private in a struct.
Steve Blocka7e24c12009-10-30 11:49:00 +0000123 int code_;
124};
125
Steve Block6ded16b2010-05-10 14:33:55 +0100126const Register no_reg = { -1 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000127
Steve Block6ded16b2010-05-10 14:33:55 +0100128const Register r0 = { 0 };
129const Register r1 = { 1 };
130const Register r2 = { 2 };
131const Register r3 = { 3 };
132const Register r4 = { 4 };
133const Register r5 = { 5 };
134const Register r6 = { 6 };
135const Register r7 = { 7 };
136const Register r8 = { 8 }; // Used as context register.
Steve Block9fac8402011-05-12 15:51:54 +0100137const Register r9 = { 9 }; // Used as lithium codegen scratch register.
Steve Block6ded16b2010-05-10 14:33:55 +0100138const Register r10 = { 10 }; // Used as roots register.
139const Register fp = { 11 };
140const Register ip = { 12 };
141const Register sp = { 13 };
142const Register lr = { 14 };
143const Register pc = { 15 };
Steve Blockd0582a62009-12-15 09:54:21 +0000144
Leon Clarkee46be812010-01-19 14:06:41 +0000145// Single word VFP register.
146struct SwVfpRegister {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100147 bool is_valid() const { return 0 <= code_ && code_ < 32; }
148 bool is(SwVfpRegister reg) const { return code_ == reg.code_; }
149 int code() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000150 ASSERT(is_valid());
151 return code_;
152 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100153 int bit() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000154 ASSERT(is_valid());
155 return 1 << code_;
156 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100157 void split_code(int* vm, int* m) const {
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100158 ASSERT(is_valid());
159 *m = code_ & 0x1;
160 *vm = code_ >> 1;
161 }
Leon Clarkee46be812010-01-19 14:06:41 +0000162
163 int code_;
164};
165
166
167// Double word VFP register.
168struct DwVfpRegister {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100169 // d0 has been excluded from allocation. This is following ia32
170 // where xmm0 is excluded. This should be revisited.
Ben Murdochb8e0da22011-05-16 14:20:40 +0100171 // Currently d0 is used as a scratch register.
172 // d1 has also been excluded from allocation to be used as a scratch
173 // register as well.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100174 static const int kNumRegisters = 16;
175 static const int kNumAllocatableRegisters = 15;
176
177 static int ToAllocationIndex(DwVfpRegister reg) {
178 ASSERT(reg.code() != 0);
179 return reg.code() - 1;
180 }
181
182 static DwVfpRegister FromAllocationIndex(int index) {
183 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
184 return from_code(index + 1);
185 }
186
187 static const char* AllocationIndexToString(int index) {
188 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
189 const char* const names[] = {
190 "d1",
191 "d2",
192 "d3",
193 "d4",
194 "d5",
195 "d6",
196 "d7",
197 "d8",
198 "d9",
199 "d10",
200 "d11",
201 "d12",
202 "d13",
203 "d14",
204 "d15"
205 };
206 return names[index];
207 }
208
209 static DwVfpRegister from_code(int code) {
210 DwVfpRegister r = { code };
211 return r;
212 }
213
Leon Clarkee46be812010-01-19 14:06:41 +0000214 // Supporting d0 to d15, can be later extended to d31.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100215 bool is_valid() const { return 0 <= code_ && code_ < 16; }
216 bool is(DwVfpRegister reg) const { return code_ == reg.code_; }
217 SwVfpRegister low() const {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100218 SwVfpRegister reg;
219 reg.code_ = code_ * 2;
220
221 ASSERT(reg.is_valid());
222 return reg;
223 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100224 SwVfpRegister high() const {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100225 SwVfpRegister reg;
226 reg.code_ = (code_ * 2) + 1;
227
228 ASSERT(reg.is_valid());
229 return reg;
230 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100231 int code() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000232 ASSERT(is_valid());
233 return code_;
234 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100235 int bit() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000236 ASSERT(is_valid());
237 return 1 << code_;
238 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100239 void split_code(int* vm, int* m) const {
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100240 ASSERT(is_valid());
241 *m = (code_ & 0x10) >> 4;
242 *vm = code_ & 0x0F;
243 }
Leon Clarkee46be812010-01-19 14:06:41 +0000244
245 int code_;
246};
247
248
Ben Murdochb0fe1622011-05-05 13:52:32 +0100249typedef DwVfpRegister DoubleRegister;
250
251
Steve Block6ded16b2010-05-10 14:33:55 +0100252// Support for the VFP registers s0 to s31 (d0 to d15).
Leon Clarkee46be812010-01-19 14:06:41 +0000253// Note that "s(N):s(N+1)" is the same as "d(N/2)".
Steve Block6ded16b2010-05-10 14:33:55 +0100254const SwVfpRegister s0 = { 0 };
255const SwVfpRegister s1 = { 1 };
256const SwVfpRegister s2 = { 2 };
257const SwVfpRegister s3 = { 3 };
258const SwVfpRegister s4 = { 4 };
259const SwVfpRegister s5 = { 5 };
260const SwVfpRegister s6 = { 6 };
261const SwVfpRegister s7 = { 7 };
262const SwVfpRegister s8 = { 8 };
263const SwVfpRegister s9 = { 9 };
264const SwVfpRegister s10 = { 10 };
265const SwVfpRegister s11 = { 11 };
266const SwVfpRegister s12 = { 12 };
267const SwVfpRegister s13 = { 13 };
268const SwVfpRegister s14 = { 14 };
269const SwVfpRegister s15 = { 15 };
270const SwVfpRegister s16 = { 16 };
271const SwVfpRegister s17 = { 17 };
272const SwVfpRegister s18 = { 18 };
273const SwVfpRegister s19 = { 19 };
274const SwVfpRegister s20 = { 20 };
275const SwVfpRegister s21 = { 21 };
276const SwVfpRegister s22 = { 22 };
277const SwVfpRegister s23 = { 23 };
278const SwVfpRegister s24 = { 24 };
279const SwVfpRegister s25 = { 25 };
280const SwVfpRegister s26 = { 26 };
281const SwVfpRegister s27 = { 27 };
282const SwVfpRegister s28 = { 28 };
283const SwVfpRegister s29 = { 29 };
284const SwVfpRegister s30 = { 30 };
285const SwVfpRegister s31 = { 31 };
Leon Clarkee46be812010-01-19 14:06:41 +0000286
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100287const DwVfpRegister no_dreg = { -1 };
Steve Block6ded16b2010-05-10 14:33:55 +0100288const DwVfpRegister d0 = { 0 };
289const DwVfpRegister d1 = { 1 };
290const DwVfpRegister d2 = { 2 };
291const DwVfpRegister d3 = { 3 };
292const DwVfpRegister d4 = { 4 };
293const DwVfpRegister d5 = { 5 };
294const DwVfpRegister d6 = { 6 };
295const DwVfpRegister d7 = { 7 };
296const DwVfpRegister d8 = { 8 };
297const DwVfpRegister d9 = { 9 };
298const DwVfpRegister d10 = { 10 };
299const DwVfpRegister d11 = { 11 };
300const DwVfpRegister d12 = { 12 };
301const DwVfpRegister d13 = { 13 };
302const DwVfpRegister d14 = { 14 };
303const DwVfpRegister d15 = { 15 };
Leon Clarkee46be812010-01-19 14:06:41 +0000304
Steve Blocka7e24c12009-10-30 11:49:00 +0000305
306// Coprocessor register
307struct CRegister {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100308 bool is_valid() const { return 0 <= code_ && code_ < 16; }
309 bool is(CRegister creg) const { return code_ == creg.code_; }
310 int code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000311 ASSERT(is_valid());
312 return code_;
313 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100314 int bit() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000315 ASSERT(is_valid());
316 return 1 << code_;
317 }
318
Andrei Popescu31002712010-02-23 13:46:05 +0000319 // Unfortunately we can't make this private in a struct.
Steve Blocka7e24c12009-10-30 11:49:00 +0000320 int code_;
321};
322
323
Steve Block6ded16b2010-05-10 14:33:55 +0100324const CRegister no_creg = { -1 };
325
326const CRegister cr0 = { 0 };
327const CRegister cr1 = { 1 };
328const CRegister cr2 = { 2 };
329const CRegister cr3 = { 3 };
330const CRegister cr4 = { 4 };
331const CRegister cr5 = { 5 };
332const CRegister cr6 = { 6 };
333const CRegister cr7 = { 7 };
334const CRegister cr8 = { 8 };
335const CRegister cr9 = { 9 };
336const CRegister cr10 = { 10 };
337const CRegister cr11 = { 11 };
338const CRegister cr12 = { 12 };
339const CRegister cr13 = { 13 };
340const CRegister cr14 = { 14 };
341const CRegister cr15 = { 15 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000342
343
344// Coprocessor number
345enum Coprocessor {
346 p0 = 0,
347 p1 = 1,
348 p2 = 2,
349 p3 = 3,
350 p4 = 4,
351 p5 = 5,
352 p6 = 6,
353 p7 = 7,
354 p8 = 8,
355 p9 = 9,
356 p10 = 10,
357 p11 = 11,
358 p12 = 12,
359 p13 = 13,
360 p14 = 14,
361 p15 = 15
362};
363
364
Steve Blocka7e24c12009-10-30 11:49:00 +0000365// -----------------------------------------------------------------------------
366// Machine instruction Operands
367
368// Class Operand represents a shifter operand in data processing instructions
369class Operand BASE_EMBEDDED {
370 public:
371 // immediate
372 INLINE(explicit Operand(int32_t immediate,
373 RelocInfo::Mode rmode = RelocInfo::NONE));
374 INLINE(explicit Operand(const ExternalReference& f));
375 INLINE(explicit Operand(const char* s));
Steve Blocka7e24c12009-10-30 11:49:00 +0000376 explicit Operand(Handle<Object> handle);
377 INLINE(explicit Operand(Smi* value));
378
379 // rm
380 INLINE(explicit Operand(Register rm));
381
382 // rm <shift_op> shift_imm
383 explicit Operand(Register rm, ShiftOp shift_op, int shift_imm);
384
385 // rm <shift_op> rs
386 explicit Operand(Register rm, ShiftOp shift_op, Register rs);
387
388 // Return true if this is a register operand.
389 INLINE(bool is_reg() const);
390
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100391 // Return true if this operand fits in one instruction so that no
Steve Block44f0eee2011-05-26 01:26:41 +0100392 // 2-instruction solution with a load into the ip register is necessary. If
393 // the instruction this operand is used for is a MOV or MVN instruction the
394 // actual instruction to use is required for this calculation. For other
395 // instructions instr is ignored.
396 bool is_single_instruction(Instr instr = 0) const;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800397 bool must_use_constant_pool() const;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100398
399 inline int32_t immediate() const {
400 ASSERT(!rm_.is_valid());
401 return imm32_;
402 }
403
Steve Blocka7e24c12009-10-30 11:49:00 +0000404 Register rm() const { return rm_; }
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100405 Register rs() const { return rs_; }
406 ShiftOp shift_op() const { return shift_op_; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000407
408 private:
409 Register rm_;
410 Register rs_;
411 ShiftOp shift_op_;
412 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
413 int32_t imm32_; // valid if rm_ == no_reg
414 RelocInfo::Mode rmode_;
415
416 friend class Assembler;
417};
418
419
420// Class MemOperand represents a memory operand in load and store instructions
421class MemOperand BASE_EMBEDDED {
422 public:
423 // [rn +/- offset] Offset/NegOffset
424 // [rn +/- offset]! PreIndex/NegPreIndex
425 // [rn], +/- offset PostIndex/NegPostIndex
426 // offset is any signed 32-bit value; offset is first loaded to register ip if
427 // it does not fit the addressing mode (12-bit unsigned and sign bit)
428 explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset);
429
430 // [rn +/- rm] Offset/NegOffset
431 // [rn +/- rm]! PreIndex/NegPreIndex
432 // [rn], +/- rm PostIndex/NegPostIndex
433 explicit MemOperand(Register rn, Register rm, AddrMode am = Offset);
434
435 // [rn +/- rm <shift_op> shift_imm] Offset/NegOffset
436 // [rn +/- rm <shift_op> shift_imm]! PreIndex/NegPreIndex
437 // [rn], +/- rm <shift_op> shift_imm PostIndex/NegPostIndex
438 explicit MemOperand(Register rn, Register rm,
439 ShiftOp shift_op, int shift_imm, AddrMode am = Offset);
440
Kristian Monsen25f61362010-05-21 11:50:48 +0100441 void set_offset(int32_t offset) {
442 ASSERT(rm_.is(no_reg));
443 offset_ = offset;
444 }
445
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100446 uint32_t offset() const {
Kristian Monsen25f61362010-05-21 11:50:48 +0100447 ASSERT(rm_.is(no_reg));
448 return offset_;
449 }
450
Leon Clarkef7060e22010-06-03 12:02:55 +0100451 Register rn() const { return rn_; }
452 Register rm() const { return rm_; }
Kristian Monsen25f61362010-05-21 11:50:48 +0100453
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100454 bool OffsetIsUint12Encodable() const {
455 return offset_ >= 0 ? is_uint12(offset_) : is_uint12(-offset_);
456 }
457
Steve Blocka7e24c12009-10-30 11:49:00 +0000458 private:
459 Register rn_; // base
460 Register rm_; // register offset
461 int32_t offset_; // valid if rm_ == no_reg
462 ShiftOp shift_op_;
463 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
464 AddrMode am_; // bits P, U, and W
465
466 friend class Assembler;
467};
468
Steve Blockd0582a62009-12-15 09:54:21 +0000469// CpuFeatures keeps track of which features are supported by the target CPU.
470// Supported features must be enabled by a Scope before use.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100471class CpuFeatures : public AllStatic {
Steve Blockd0582a62009-12-15 09:54:21 +0000472 public:
473 // Detect features of the target CPU. Set safe defaults if the serializer
474 // is enabled (snapshots must be portable).
Ben Murdoch8b112d22011-06-08 16:22:53 +0100475 static void Probe();
Steve Blockd0582a62009-12-15 09:54:21 +0000476
477 // Check whether a feature is supported by the target CPU.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100478 static bool IsSupported(CpuFeature f) {
479 ASSERT(initialized_);
Steve Blockd0582a62009-12-15 09:54:21 +0000480 if (f == VFP3 && !FLAG_enable_vfp3) return false;
481 return (supported_ & (1u << f)) != 0;
482 }
483
Ben Murdoch8b112d22011-06-08 16:22:53 +0100484#ifdef DEBUG
Steve Blockd0582a62009-12-15 09:54:21 +0000485 // Check whether a feature is currently enabled.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100486 static bool IsEnabled(CpuFeature f) {
487 ASSERT(initialized_);
488 Isolate* isolate = Isolate::UncheckedCurrent();
489 if (isolate == NULL) {
490 // When no isolate is available, work as if we're running in
491 // release mode.
492 return IsSupported(f);
493 }
494 unsigned enabled = static_cast<unsigned>(isolate->enabled_cpu_features());
495 return (enabled & (1u << f)) != 0;
Steve Blockd0582a62009-12-15 09:54:21 +0000496 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100497#endif
Steve Blockd0582a62009-12-15 09:54:21 +0000498
499 // Enable a specified feature within a scope.
500 class Scope BASE_EMBEDDED {
501#ifdef DEBUG
502 public:
Ben Murdoch8b112d22011-06-08 16:22:53 +0100503 explicit Scope(CpuFeature f) {
504 unsigned mask = 1u << f;
505 ASSERT(CpuFeatures::IsSupported(f));
Steve Blockd0582a62009-12-15 09:54:21 +0000506 ASSERT(!Serializer::enabled() ||
Ben Murdoch8b112d22011-06-08 16:22:53 +0100507 (CpuFeatures::found_by_runtime_probing_ & mask) == 0);
508 isolate_ = Isolate::UncheckedCurrent();
509 old_enabled_ = 0;
510 if (isolate_ != NULL) {
511 old_enabled_ = static_cast<unsigned>(isolate_->enabled_cpu_features());
512 isolate_->set_enabled_cpu_features(old_enabled_ | mask);
513 }
Steve Blockd0582a62009-12-15 09:54:21 +0000514 }
Steve Block44f0eee2011-05-26 01:26:41 +0100515 ~Scope() {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100516 ASSERT_EQ(Isolate::UncheckedCurrent(), isolate_);
517 if (isolate_ != NULL) {
518 isolate_->set_enabled_cpu_features(old_enabled_);
519 }
Steve Block44f0eee2011-05-26 01:26:41 +0100520 }
Steve Blockd0582a62009-12-15 09:54:21 +0000521 private:
Steve Block44f0eee2011-05-26 01:26:41 +0100522 Isolate* isolate_;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100523 unsigned old_enabled_;
Steve Blockd0582a62009-12-15 09:54:21 +0000524#else
525 public:
526 explicit Scope(CpuFeature f) {}
527#endif
528 };
529
Ben Murdoch8b112d22011-06-08 16:22:53 +0100530 class TryForceFeatureScope BASE_EMBEDDED {
531 public:
532 explicit TryForceFeatureScope(CpuFeature f)
533 : old_supported_(CpuFeatures::supported_) {
534 if (CanForce()) {
535 CpuFeatures::supported_ |= (1u << f);
536 }
537 }
538
539 ~TryForceFeatureScope() {
540 if (CanForce()) {
541 CpuFeatures::supported_ = old_supported_;
542 }
543 }
544
545 private:
546 static bool CanForce() {
547 // It's only safe to temporarily force support of CPU features
548 // when there's only a single isolate, which is guaranteed when
549 // the serializer is enabled.
550 return Serializer::enabled();
551 }
552
553 const unsigned old_supported_;
554 };
555
Steve Blockd0582a62009-12-15 09:54:21 +0000556 private:
Ben Murdoch8b112d22011-06-08 16:22:53 +0100557#ifdef DEBUG
558 static bool initialized_;
559#endif
560 static unsigned supported_;
561 static unsigned found_by_runtime_probing_;
Steve Block44f0eee2011-05-26 01:26:41 +0100562
563 DISALLOW_COPY_AND_ASSIGN(CpuFeatures);
Steve Blockd0582a62009-12-15 09:54:21 +0000564};
565
Steve Blocka7e24c12009-10-30 11:49:00 +0000566
Steve Blocka7e24c12009-10-30 11:49:00 +0000567extern const Instr kMovLrPc;
Steve Block6ded16b2010-05-10 14:33:55 +0100568extern const Instr kLdrPCMask;
Steve Blocka7e24c12009-10-30 11:49:00 +0000569extern const Instr kLdrPCPattern;
Steve Block6ded16b2010-05-10 14:33:55 +0100570extern const Instr kBlxRegMask;
571extern const Instr kBlxRegPattern;
Steve Blocka7e24c12009-10-30 11:49:00 +0000572
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100573extern const Instr kMovMvnMask;
574extern const Instr kMovMvnPattern;
575extern const Instr kMovMvnFlip;
576
577extern const Instr kMovLeaveCCMask;
578extern const Instr kMovLeaveCCPattern;
579extern const Instr kMovwMask;
580extern const Instr kMovwPattern;
581extern const Instr kMovwLeaveCCFlip;
582
583extern const Instr kCmpCmnMask;
584extern const Instr kCmpCmnPattern;
585extern const Instr kCmpCmnFlip;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100586extern const Instr kAddSubFlip;
587extern const Instr kAndBicFlip;
Steve Blocka7e24c12009-10-30 11:49:00 +0000588
Steve Block1e0659c2011-05-24 12:43:12 +0100589
590
Steve Block44f0eee2011-05-26 01:26:41 +0100591class Assembler : public AssemblerBase {
Steve Blocka7e24c12009-10-30 11:49:00 +0000592 public:
593 // Create an assembler. Instructions and relocation information are emitted
594 // into a buffer, with the instructions starting from the beginning and the
595 // relocation information starting from the end of the buffer. See CodeDesc
596 // for a detailed comment on the layout (globals.h).
597 //
598 // If the provided buffer is NULL, the assembler allocates and grows its own
599 // buffer, and buffer_size determines the initial buffer size. The buffer is
600 // owned by the assembler and deallocated upon destruction of the assembler.
601 //
602 // If the provided buffer is not NULL, the assembler uses the provided buffer
603 // for code generation and assumes its size to be buffer_size. If the buffer
604 // is too small, a fatal error occurs. No deallocation of the buffer is done
605 // upon destruction of the assembler.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100606 Assembler(Isolate* isolate, void* buffer, int buffer_size);
Steve Blocka7e24c12009-10-30 11:49:00 +0000607 ~Assembler();
608
Steve Block44f0eee2011-05-26 01:26:41 +0100609 // Overrides the default provided by FLAG_debug_code.
610 void set_emit_debug_code(bool value) { emit_debug_code_ = value; }
611
Steve Blocka7e24c12009-10-30 11:49:00 +0000612 // GetCode emits any pending (non-emitted) code and fills the descriptor
613 // desc. GetCode() is idempotent; it returns the same result if no other
614 // Assembler functions are invoked in between GetCode() calls.
615 void GetCode(CodeDesc* desc);
616
617 // Label operations & relative jumps (PPUM Appendix D)
618 //
619 // Takes a branch opcode (cc) and a label (L) and generates
620 // either a backward branch or a forward branch and links it
621 // to the label fixup chain. Usage:
622 //
623 // Label L; // unbound label
624 // j(cc, &L); // forward branch to unbound label
625 // bind(&L); // bind label to the current pc
626 // j(cc, &L); // backward branch to bound label
627 // bind(&L); // illegal: a label may be bound only once
628 //
629 // Note: The same Label can be used for forward and backward branches
630 // but it may be bound only once.
631
632 void bind(Label* L); // binds an unbound label L to the current code position
633
634 // Returns the branch offset to the given label from the current code position
635 // Links the label to the current position if it is still unbound
636 // Manages the jump elimination optimization if the second parameter is true.
637 int branch_offset(Label* L, bool jump_elimination_allowed);
638
639 // Puts a labels target address at the given position.
640 // The high 8 bits are set to zero.
641 void label_at_put(Label* L, int at_offset);
642
643 // Return the address in the constant pool of the code target address used by
644 // the branch/call instruction at pc.
645 INLINE(static Address target_address_address_at(Address pc));
646
647 // Read/Modify the code target address in the branch/call instruction at pc.
648 INLINE(static Address target_address_at(Address pc));
649 INLINE(static void set_target_address_at(Address pc, Address target));
650
Steve Blockd0582a62009-12-15 09:54:21 +0000651 // This sets the branch destination (which is in the constant pool on ARM).
652 // This is for calls and branches within generated code.
653 inline static void set_target_at(Address constant_pool_entry, Address target);
654
655 // This sets the branch destination (which is in the constant pool on ARM).
656 // This is for calls and branches to runtime code.
657 inline static void set_external_target_at(Address constant_pool_entry,
658 Address target) {
659 set_target_at(constant_pool_entry, target);
660 }
661
662 // Here we are patching the address in the constant pool, not the actual call
663 // instruction. The address in the constant pool is the same size as a
664 // pointer.
665 static const int kCallTargetSize = kPointerSize;
666 static const int kExternalTargetSize = kPointerSize;
667
Steve Blocka7e24c12009-10-30 11:49:00 +0000668 // Size of an instruction.
669 static const int kInstrSize = sizeof(Instr);
670
671 // Distance between the instruction referring to the address of the call
Steve Block6ded16b2010-05-10 14:33:55 +0100672 // target and the return address.
673#ifdef USE_BLX
674 // Call sequence is:
675 // ldr ip, [pc, #...] @ call address
676 // blx ip
677 // @ return address
678 static const int kCallTargetAddressOffset = 2 * kInstrSize;
679#else
680 // Call sequence is:
681 // mov lr, pc
682 // ldr pc, [pc, #...] @ call address
683 // @ return address
Steve Blocka7e24c12009-10-30 11:49:00 +0000684 static const int kCallTargetAddressOffset = kInstrSize;
Steve Block6ded16b2010-05-10 14:33:55 +0100685#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000686
687 // Distance between start of patched return sequence and the emitted address
688 // to jump to.
Steve Block6ded16b2010-05-10 14:33:55 +0100689#ifdef USE_BLX
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100690 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100691 // ldr ip, [pc, #0] @ emited address and start
692 // blx ip
693 static const int kPatchReturnSequenceAddressOffset = 0 * kInstrSize;
694#else
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100695 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100696 // mov lr, pc @ start of sequence
697 // ldr pc, [pc, #-4] @ emited address
698 static const int kPatchReturnSequenceAddressOffset = kInstrSize;
699#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000700
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100701 // Distance between start of patched debug break slot and the emitted address
702 // to jump to.
703#ifdef USE_BLX
704 // Patched debug break slot code is:
705 // ldr ip, [pc, #0] @ emited address and start
706 // blx ip
707 static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
708#else
709 // Patched debug break slot code is:
710 // mov lr, pc @ start of sequence
711 // ldr pc, [pc, #-4] @ emited address
712 static const int kPatchDebugBreakSlotAddressOffset = kInstrSize;
713#endif
714
Steve Blocka7e24c12009-10-30 11:49:00 +0000715 // Difference between address of current opcode and value read from pc
716 // register.
717 static const int kPcLoadDelta = 8;
718
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100719 static const int kJSReturnSequenceInstructions = 4;
720 static const int kDebugBreakSlotInstructions = 3;
721 static const int kDebugBreakSlotLength =
722 kDebugBreakSlotInstructions * kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +0000723
724 // ---------------------------------------------------------------------------
725 // Code generation
726
727 // Insert the smallest number of nop instructions
728 // possible to align the pc offset to a multiple
729 // of m. m must be a power of 2 (>= 4).
730 void Align(int m);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100731 // Aligns code to something that's optimal for a jump target for the platform.
732 void CodeTargetAlign();
Steve Blocka7e24c12009-10-30 11:49:00 +0000733
734 // Branch instructions
735 void b(int branch_offset, Condition cond = al);
736 void bl(int branch_offset, Condition cond = al);
737 void blx(int branch_offset); // v5 and above
738 void blx(Register target, Condition cond = al); // v5 and above
739 void bx(Register target, Condition cond = al); // v5 and above, plus v4t
740
741 // Convenience branch instructions using labels
742 void b(Label* L, Condition cond = al) {
743 b(branch_offset(L, cond == al), cond);
744 }
745 void b(Condition cond, Label* L) { b(branch_offset(L, cond == al), cond); }
746 void bl(Label* L, Condition cond = al) { bl(branch_offset(L, false), cond); }
747 void bl(Condition cond, Label* L) { bl(branch_offset(L, false), cond); }
748 void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above
749
750 // Data-processing instructions
Andrei Popescu31002712010-02-23 13:46:05 +0000751
Steve Blocka7e24c12009-10-30 11:49:00 +0000752 void and_(Register dst, Register src1, const Operand& src2,
753 SBit s = LeaveCC, Condition cond = al);
754
755 void eor(Register dst, Register src1, const Operand& src2,
756 SBit s = LeaveCC, Condition cond = al);
757
758 void sub(Register dst, Register src1, const Operand& src2,
759 SBit s = LeaveCC, Condition cond = al);
760 void sub(Register dst, Register src1, Register src2,
761 SBit s = LeaveCC, Condition cond = al) {
762 sub(dst, src1, Operand(src2), s, cond);
763 }
764
765 void rsb(Register dst, Register src1, const Operand& src2,
766 SBit s = LeaveCC, Condition cond = al);
767
768 void add(Register dst, Register src1, const Operand& src2,
769 SBit s = LeaveCC, Condition cond = al);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100770 void add(Register dst, Register src1, Register src2,
771 SBit s = LeaveCC, Condition cond = al) {
772 add(dst, src1, Operand(src2), s, cond);
773 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000774
775 void adc(Register dst, Register src1, const Operand& src2,
776 SBit s = LeaveCC, Condition cond = al);
777
778 void sbc(Register dst, Register src1, const Operand& src2,
779 SBit s = LeaveCC, Condition cond = al);
780
781 void rsc(Register dst, Register src1, const Operand& src2,
782 SBit s = LeaveCC, Condition cond = al);
783
784 void tst(Register src1, const Operand& src2, Condition cond = al);
785 void tst(Register src1, Register src2, Condition cond = al) {
786 tst(src1, Operand(src2), cond);
787 }
788
789 void teq(Register src1, const Operand& src2, Condition cond = al);
790
791 void cmp(Register src1, const Operand& src2, Condition cond = al);
792 void cmp(Register src1, Register src2, Condition cond = al) {
793 cmp(src1, Operand(src2), cond);
794 }
Steve Block1e0659c2011-05-24 12:43:12 +0100795 void cmp_raw_immediate(Register src1, int raw_immediate, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000796
797 void cmn(Register src1, const Operand& src2, Condition cond = al);
798
799 void orr(Register dst, Register src1, const Operand& src2,
800 SBit s = LeaveCC, Condition cond = al);
801 void orr(Register dst, Register src1, Register src2,
802 SBit s = LeaveCC, Condition cond = al) {
803 orr(dst, src1, Operand(src2), s, cond);
804 }
805
806 void mov(Register dst, const Operand& src,
807 SBit s = LeaveCC, Condition cond = al);
808 void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
809 mov(dst, Operand(src), s, cond);
810 }
811
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100812 // ARMv7 instructions for loading a 32 bit immediate in two instructions.
813 // This may actually emit a different mov instruction, but on an ARMv7 it
814 // is guaranteed to only emit one instruction.
815 void movw(Register reg, uint32_t immediate, Condition cond = al);
816 // The constant for movt should be in the range 0-0xffff.
817 void movt(Register reg, uint32_t immediate, Condition cond = al);
818
Steve Blocka7e24c12009-10-30 11:49:00 +0000819 void bic(Register dst, Register src1, const Operand& src2,
820 SBit s = LeaveCC, Condition cond = al);
821
822 void mvn(Register dst, const Operand& src,
823 SBit s = LeaveCC, Condition cond = al);
824
825 // Multiply instructions
826
827 void mla(Register dst, Register src1, Register src2, Register srcA,
828 SBit s = LeaveCC, Condition cond = al);
829
830 void mul(Register dst, Register src1, Register src2,
831 SBit s = LeaveCC, Condition cond = al);
832
833 void smlal(Register dstL, Register dstH, Register src1, Register src2,
834 SBit s = LeaveCC, Condition cond = al);
835
836 void smull(Register dstL, Register dstH, Register src1, Register src2,
837 SBit s = LeaveCC, Condition cond = al);
838
839 void umlal(Register dstL, Register dstH, Register src1, Register src2,
840 SBit s = LeaveCC, Condition cond = al);
841
842 void umull(Register dstL, Register dstH, Register src1, Register src2,
843 SBit s = LeaveCC, Condition cond = al);
844
845 // Miscellaneous arithmetic instructions
846
847 void clz(Register dst, Register src, Condition cond = al); // v5 and above
848
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100849 // Saturating instructions. v6 and above.
850
851 // Unsigned saturate.
852 //
853 // Saturate an optionally shifted signed value to an unsigned range.
854 //
855 // usat dst, #satpos, src
856 // usat dst, #satpos, src, lsl #sh
857 // usat dst, #satpos, src, asr #sh
858 //
859 // Register dst will contain:
860 //
861 // 0, if s < 0
862 // (1 << satpos) - 1, if s > ((1 << satpos) - 1)
863 // s, otherwise
864 //
865 // where s is the contents of src after shifting (if used.)
866 void usat(Register dst, int satpos, const Operand& src, Condition cond = al);
867
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100868 // Bitfield manipulation instructions. v7 and above.
869
870 void ubfx(Register dst, Register src, int lsb, int width,
871 Condition cond = al);
872
873 void sbfx(Register dst, Register src, int lsb, int width,
874 Condition cond = al);
875
876 void bfc(Register dst, int lsb, int width, Condition cond = al);
877
878 void bfi(Register dst, Register src, int lsb, int width,
879 Condition cond = al);
880
Steve Blocka7e24c12009-10-30 11:49:00 +0000881 // Status register access instructions
882
883 void mrs(Register dst, SRegister s, Condition cond = al);
884 void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al);
885
886 // Load/Store instructions
887 void ldr(Register dst, const MemOperand& src, Condition cond = al);
888 void str(Register src, const MemOperand& dst, Condition cond = al);
889 void ldrb(Register dst, const MemOperand& src, Condition cond = al);
890 void strb(Register src, const MemOperand& dst, Condition cond = al);
891 void ldrh(Register dst, const MemOperand& src, Condition cond = al);
892 void strh(Register src, const MemOperand& dst, Condition cond = al);
893 void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
894 void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
Leon Clarkef7060e22010-06-03 12:02:55 +0100895 void ldrd(Register dst1,
896 Register dst2,
897 const MemOperand& src, Condition cond = al);
898 void strd(Register src1,
899 Register src2,
900 const MemOperand& dst, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000901
902 // Load/Store multiple instructions
903 void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
904 void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
905
Steve Blocka7e24c12009-10-30 11:49:00 +0000906 // Exception-generating instructions and debugging support
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800907 void stop(const char* msg,
908 Condition cond = al,
909 int32_t code = kDefaultStopCode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000910
911 void bkpt(uint32_t imm16); // v5 and above
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800912 void svc(uint32_t imm24, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000913
914 // Coprocessor instructions
915
916 void cdp(Coprocessor coproc, int opcode_1,
917 CRegister crd, CRegister crn, CRegister crm,
918 int opcode_2, Condition cond = al);
919
920 void cdp2(Coprocessor coproc, int opcode_1,
921 CRegister crd, CRegister crn, CRegister crm,
922 int opcode_2); // v5 and above
923
924 void mcr(Coprocessor coproc, int opcode_1,
925 Register rd, CRegister crn, CRegister crm,
926 int opcode_2 = 0, Condition cond = al);
927
928 void mcr2(Coprocessor coproc, int opcode_1,
929 Register rd, CRegister crn, CRegister crm,
930 int opcode_2 = 0); // v5 and above
931
932 void mrc(Coprocessor coproc, int opcode_1,
933 Register rd, CRegister crn, CRegister crm,
934 int opcode_2 = 0, Condition cond = al);
935
936 void mrc2(Coprocessor coproc, int opcode_1,
937 Register rd, CRegister crn, CRegister crm,
938 int opcode_2 = 0); // v5 and above
939
940 void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src,
941 LFlag l = Short, Condition cond = al);
942 void ldc(Coprocessor coproc, CRegister crd, Register base, int option,
943 LFlag l = Short, Condition cond = al);
944
945 void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
946 LFlag l = Short); // v5 and above
947 void ldc2(Coprocessor coproc, CRegister crd, Register base, int option,
948 LFlag l = Short); // v5 and above
949
Steve Blockd0582a62009-12-15 09:54:21 +0000950 // Support for VFP.
951 // All these APIs support S0 to S31 and D0 to D15.
952 // Currently these APIs do not support extended D registers, i.e, D16 to D31.
953 // However, some simple modifications can allow
954 // these APIs to support D16 to D31.
955
Leon Clarked91b9f72010-01-27 17:25:45 +0000956 void vldr(const DwVfpRegister dst,
957 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100958 int offset,
959 const Condition cond = al);
960 void vldr(const DwVfpRegister dst,
961 const MemOperand& src,
Leon Clarked91b9f72010-01-27 17:25:45 +0000962 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +0100963
964 void vldr(const SwVfpRegister dst,
965 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100966 int offset,
967 const Condition cond = al);
968 void vldr(const SwVfpRegister dst,
969 const MemOperand& src,
Steve Block6ded16b2010-05-10 14:33:55 +0100970 const Condition cond = al);
971
Leon Clarked91b9f72010-01-27 17:25:45 +0000972 void vstr(const DwVfpRegister src,
973 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100974 int offset,
975 const Condition cond = al);
976 void vstr(const DwVfpRegister src,
977 const MemOperand& dst,
Leon Clarked91b9f72010-01-27 17:25:45 +0000978 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +0100979
Iain Merrick75681382010-08-19 15:07:18 +0100980 void vstr(const SwVfpRegister src,
981 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100982 int offset,
983 const Condition cond = al);
984 void vstr(const SwVfpRegister src,
985 const MemOperand& dst,
Iain Merrick75681382010-08-19 15:07:18 +0100986 const Condition cond = al);
987
Ben Murdoch8b112d22011-06-08 16:22:53 +0100988 void vldm(BlockAddrMode am,
989 Register base,
990 DwVfpRegister first,
991 DwVfpRegister last,
992 Condition cond = al);
993
994 void vstm(BlockAddrMode am,
995 Register base,
996 DwVfpRegister first,
997 DwVfpRegister last,
998 Condition cond = al);
999
1000 void vldm(BlockAddrMode am,
1001 Register base,
1002 SwVfpRegister first,
1003 SwVfpRegister last,
1004 Condition cond = al);
1005
1006 void vstm(BlockAddrMode am,
1007 Register base,
1008 SwVfpRegister first,
1009 SwVfpRegister last,
1010 Condition cond = al);
1011
Steve Block8defd9f2010-07-08 12:39:36 +01001012 void vmov(const DwVfpRegister dst,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001013 double imm,
1014 const Condition cond = al);
1015 void vmov(const SwVfpRegister dst,
1016 const SwVfpRegister src,
1017 const Condition cond = al);
1018 void vmov(const DwVfpRegister dst,
Steve Block8defd9f2010-07-08 12:39:36 +01001019 const DwVfpRegister src,
1020 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001021 void vmov(const DwVfpRegister dst,
1022 const Register src1,
Steve Blockd0582a62009-12-15 09:54:21 +00001023 const Register src2,
Leon Clarkee46be812010-01-19 14:06:41 +00001024 const Condition cond = al);
1025 void vmov(const Register dst1,
1026 const Register dst2,
1027 const DwVfpRegister src,
1028 const Condition cond = al);
1029 void vmov(const SwVfpRegister dst,
1030 const Register src,
1031 const Condition cond = al);
1032 void vmov(const Register dst,
1033 const SwVfpRegister src,
1034 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +01001035 void vcvt_f64_s32(const DwVfpRegister dst,
1036 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001037 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001038 const Condition cond = al);
1039 void vcvt_f32_s32(const SwVfpRegister dst,
1040 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001041 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001042 const Condition cond = al);
1043 void vcvt_f64_u32(const DwVfpRegister dst,
1044 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001045 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001046 const Condition cond = al);
1047 void vcvt_s32_f64(const SwVfpRegister dst,
1048 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001049 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001050 const Condition cond = al);
1051 void vcvt_u32_f64(const SwVfpRegister dst,
1052 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001053 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001054 const Condition cond = al);
1055 void vcvt_f64_f32(const DwVfpRegister dst,
1056 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001057 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001058 const Condition cond = al);
1059 void vcvt_f32_f64(const SwVfpRegister dst,
1060 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01001061 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001062 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001063
Steve Block44f0eee2011-05-26 01:26:41 +01001064 void vneg(const DwVfpRegister dst,
1065 const DwVfpRegister src,
1066 const Condition cond = al);
Steve Block1e0659c2011-05-24 12:43:12 +01001067 void vabs(const DwVfpRegister dst,
1068 const DwVfpRegister src,
1069 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001070 void vadd(const DwVfpRegister dst,
1071 const DwVfpRegister src1,
1072 const DwVfpRegister src2,
1073 const Condition cond = al);
1074 void vsub(const DwVfpRegister dst,
1075 const DwVfpRegister src1,
1076 const DwVfpRegister src2,
1077 const Condition cond = al);
1078 void vmul(const DwVfpRegister dst,
1079 const DwVfpRegister src1,
1080 const DwVfpRegister src2,
1081 const Condition cond = al);
1082 void vdiv(const DwVfpRegister dst,
1083 const DwVfpRegister src1,
1084 const DwVfpRegister src2,
1085 const Condition cond = al);
1086 void vcmp(const DwVfpRegister src1,
1087 const DwVfpRegister src2,
Steve Blockd0582a62009-12-15 09:54:21 +00001088 const Condition cond = al);
Iain Merrick75681382010-08-19 15:07:18 +01001089 void vcmp(const DwVfpRegister src1,
1090 const double src2,
Iain Merrick75681382010-08-19 15:07:18 +01001091 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001092 void vmrs(const Register dst,
1093 const Condition cond = al);
Russell Brenner90bac252010-11-18 13:33:46 -08001094 void vmsr(const Register dst,
1095 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +01001096 void vsqrt(const DwVfpRegister dst,
1097 const DwVfpRegister src,
1098 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001099
Steve Blocka7e24c12009-10-30 11:49:00 +00001100 // Pseudo instructions
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001101
1102 // Different nop operations are used by the code generator to detect certain
1103 // states of the generated code.
1104 enum NopMarkerTypes {
1105 NON_MARKING_NOP = 0,
1106 DEBUG_BREAK_NOP,
1107 // IC markers.
1108 PROPERTY_ACCESS_INLINED,
1109 PROPERTY_ACCESS_INLINED_CONTEXT,
1110 PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE,
1111 // Helper values.
1112 LAST_CODE_MARKER,
1113 FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED
1114 };
1115
1116 void nop(int type = 0); // 0 is the default non-marking type.
Steve Blocka7e24c12009-10-30 11:49:00 +00001117
1118 void push(Register src, Condition cond = al) {
1119 str(src, MemOperand(sp, 4, NegPreIndex), cond);
1120 }
1121
1122 void pop(Register dst, Condition cond = al) {
1123 ldr(dst, MemOperand(sp, 4, PostIndex), cond);
1124 }
1125
1126 void pop() {
1127 add(sp, sp, Operand(kPointerSize));
1128 }
1129
Steve Blocka7e24c12009-10-30 11:49:00 +00001130 // Jump unconditionally to given label.
1131 void jmp(Label* L) { b(L, al); }
1132
1133 // Check the code size generated from label to here.
1134 int InstructionsGeneratedSince(Label* l) {
1135 return (pc_offset() - l->pos()) / kInstrSize;
1136 }
1137
Steve Blockd0582a62009-12-15 09:54:21 +00001138 // Check whether an immediate fits an addressing mode 1 instruction.
1139 bool ImmediateFitsAddrMode1Instruction(int32_t imm32);
1140
Steve Block6ded16b2010-05-10 14:33:55 +01001141 // Class for scoping postponing the constant pool generation.
1142 class BlockConstPoolScope {
1143 public:
1144 explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) {
1145 assem_->StartBlockConstPool();
1146 }
1147 ~BlockConstPoolScope() {
1148 assem_->EndBlockConstPool();
1149 }
1150
1151 private:
1152 Assembler* assem_;
1153
1154 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstPoolScope);
1155 };
1156
Steve Blockd0582a62009-12-15 09:54:21 +00001157 // Postpone the generation of the constant pool for the specified number of
1158 // instructions.
1159 void BlockConstPoolFor(int instructions);
1160
Steve Blocka7e24c12009-10-30 11:49:00 +00001161 // Debugging
1162
1163 // Mark address of the ExitJSFrame code.
1164 void RecordJSReturn();
1165
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001166 // Mark address of a debug break slot.
1167 void RecordDebugBreakSlot();
1168
Steve Blocka7e24c12009-10-30 11:49:00 +00001169 // Record a comment relocation entry that can be used by a disassembler.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001170 // Use --code-comments to enable.
Steve Blocka7e24c12009-10-30 11:49:00 +00001171 void RecordComment(const char* msg);
1172
Ben Murdochb8e0da22011-05-16 14:20:40 +01001173 // Writes a single byte or word of data in the code stream. Used
1174 // for inline tables, e.g., jump-tables. The constant pool should be
1175 // emitted before any use of db and dd to ensure that constant pools
1176 // are not emitted as part of the tables generated.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001177 void db(uint8_t data);
1178 void dd(uint32_t data);
1179
Steve Blocka7e24c12009-10-30 11:49:00 +00001180 int pc_offset() const { return pc_ - buffer_; }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001181
1182 PositionsRecorder* positions_recorder() { return &positions_recorder_; }
Steve Block6ded16b2010-05-10 14:33:55 +01001183
Leon Clarkef7060e22010-06-03 12:02:55 +01001184 bool can_peephole_optimize(int instructions) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001185 if (!allow_peephole_optimization_) return false;
Leon Clarkef7060e22010-06-03 12:02:55 +01001186 if (last_bound_pos_ > pc_offset() - instructions * kInstrSize) return false;
1187 return reloc_info_writer.last_pc() <= pc_ - instructions * kInstrSize;
1188 }
1189
Steve Block6ded16b2010-05-10 14:33:55 +01001190 // Read/patch instructions
1191 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
1192 static void instr_at_put(byte* pc, Instr instr) {
1193 *reinterpret_cast<Instr*>(pc) = instr;
1194 }
Steve Block1e0659c2011-05-24 12:43:12 +01001195 static Condition GetCondition(Instr instr);
Steve Block6ded16b2010-05-10 14:33:55 +01001196 static bool IsBranch(Instr instr);
1197 static int GetBranchOffset(Instr instr);
1198 static bool IsLdrRegisterImmediate(Instr instr);
1199 static int GetLdrRegisterImmediateOffset(Instr instr);
1200 static Instr SetLdrRegisterImmediateOffset(Instr instr, int offset);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001201 static bool IsStrRegisterImmediate(Instr instr);
1202 static Instr SetStrRegisterImmediateOffset(Instr instr, int offset);
1203 static bool IsAddRegisterImmediate(Instr instr);
1204 static Instr SetAddRegisterImmediateOffset(Instr instr, int offset);
Leon Clarkef7060e22010-06-03 12:02:55 +01001205 static Register GetRd(Instr instr);
Steve Block1e0659c2011-05-24 12:43:12 +01001206 static Register GetRn(Instr instr);
1207 static Register GetRm(Instr instr);
Leon Clarkef7060e22010-06-03 12:02:55 +01001208 static bool IsPush(Instr instr);
1209 static bool IsPop(Instr instr);
1210 static bool IsStrRegFpOffset(Instr instr);
1211 static bool IsLdrRegFpOffset(Instr instr);
1212 static bool IsStrRegFpNegOffset(Instr instr);
1213 static bool IsLdrRegFpNegOffset(Instr instr);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001214 static bool IsLdrPcImmediateOffset(Instr instr);
Steve Block1e0659c2011-05-24 12:43:12 +01001215 static bool IsTstImmediate(Instr instr);
1216 static bool IsCmpRegister(Instr instr);
1217 static bool IsCmpImmediate(Instr instr);
1218 static Register GetCmpImmediateRegister(Instr instr);
1219 static int GetCmpImmediateRawImmediate(Instr instr);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001220 static bool IsNop(Instr instr, int type = NON_MARKING_NOP);
Steve Block6ded16b2010-05-10 14:33:55 +01001221
Ben Murdochb0fe1622011-05-05 13:52:32 +01001222 // Check if is time to emit a constant pool for pending reloc info entries
1223 void CheckConstPool(bool force_emit, bool require_jump);
Steve Blocka7e24c12009-10-30 11:49:00 +00001224
1225 protected:
Steve Block44f0eee2011-05-26 01:26:41 +01001226 bool emit_debug_code() const { return emit_debug_code_; }
1227
Steve Blocka7e24c12009-10-30 11:49:00 +00001228 int buffer_space() const { return reloc_info_writer.pos() - pc_; }
1229
1230 // Read/patch instructions
Steve Blocka7e24c12009-10-30 11:49:00 +00001231 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
1232 void instr_at_put(int pos, Instr instr) {
1233 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
1234 }
1235
1236 // Decode branch instruction at pos and return branch target pos
1237 int target_at(int pos);
1238
1239 // Patch branch instruction at pos to branch to given branch target pos
1240 void target_at_put(int pos, int target_pos);
1241
Steve Blocka7e24c12009-10-30 11:49:00 +00001242 // Block the emission of the constant pool before pc_offset
1243 void BlockConstPoolBefore(int pc_offset) {
1244 if (no_const_pool_before_ < pc_offset) no_const_pool_before_ = pc_offset;
1245 }
1246
Steve Block6ded16b2010-05-10 14:33:55 +01001247 void StartBlockConstPool() {
1248 const_pool_blocked_nesting_++;
1249 }
1250 void EndBlockConstPool() {
1251 const_pool_blocked_nesting_--;
1252 }
Steve Block8defd9f2010-07-08 12:39:36 +01001253 bool is_const_pool_blocked() const { return const_pool_blocked_nesting_ > 0; }
Steve Block6ded16b2010-05-10 14:33:55 +01001254
Steve Blocka7e24c12009-10-30 11:49:00 +00001255 private:
1256 // Code buffer:
1257 // The buffer into which code and relocation info are generated.
1258 byte* buffer_;
1259 int buffer_size_;
1260 // True if the assembler owns the buffer, false if buffer is external.
1261 bool own_buffer_;
1262
1263 // Buffer size and constant pool distance are checked together at regular
1264 // intervals of kBufferCheckInterval emitted bytes
1265 static const int kBufferCheckInterval = 1*KB/2;
1266 int next_buffer_check_; // pc offset of next buffer check
1267
1268 // Code generation
1269 // The relocation writer's position is at least kGap bytes below the end of
1270 // the generated instructions. This is so that multi-instruction sequences do
1271 // not have to check for overflow. The same is true for writes of large
1272 // relocation info entries.
1273 static const int kGap = 32;
1274 byte* pc_; // the program counter; moves forward
1275
1276 // Constant pool generation
1277 // Pools are emitted in the instruction stream, preferably after unconditional
1278 // jumps or after returns from functions (in dead code locations).
1279 // If a long code sequence does not contain unconditional jumps, it is
1280 // necessary to emit the constant pool before the pool gets too far from the
1281 // location it is accessed from. In this case, we emit a jump over the emitted
1282 // constant pool.
1283 // Constants in the pool may be addresses of functions that gets relocated;
1284 // if so, a relocation info entry is associated to the constant pool entry.
1285
1286 // Repeated checking whether the constant pool should be emitted is rather
1287 // expensive. By default we only check again once a number of instructions
1288 // has been generated. That also means that the sizing of the buffers is not
1289 // an exact science, and that we rely on some slop to not overrun buffers.
1290 static const int kCheckConstIntervalInst = 32;
1291 static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize;
1292
1293
1294 // Pools are emitted after function return and in dead code at (more or less)
1295 // regular intervals of kDistBetweenPools bytes
1296 static const int kDistBetweenPools = 1*KB;
1297
1298 // Constants in pools are accessed via pc relative addressing, which can
1299 // reach +/-4KB thereby defining a maximum distance between the instruction
1300 // and the accessed constant. We satisfy this constraint by limiting the
1301 // distance between pools.
1302 static const int kMaxDistBetweenPools = 4*KB - 2*kBufferCheckInterval;
1303
Steve Block6ded16b2010-05-10 14:33:55 +01001304 // Emission of the constant pool may be blocked in some code sequences.
1305 int const_pool_blocked_nesting_; // Block emission if this is not zero.
1306 int no_const_pool_before_; // Block emission before this pc offset.
Steve Blocka7e24c12009-10-30 11:49:00 +00001307
1308 // Keep track of the last emitted pool to guarantee a maximal distance
1309 int last_const_pool_end_; // pc offset following the last constant pool
1310
1311 // Relocation info generation
1312 // Each relocation is encoded as a variable size value
1313 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1314 RelocInfoWriter reloc_info_writer;
1315 // Relocation info records are also used during code generation as temporary
1316 // containers for constants and code target addresses until they are emitted
1317 // to the constant pool. These pending relocation info records are temporarily
1318 // stored in a separate buffer until a constant pool is emitted.
1319 // If every instruction in a long sequence is accessing the pool, we need one
1320 // pending relocation entry per instruction.
1321 static const int kMaxNumPRInfo = kMaxDistBetweenPools/kInstrSize;
1322 RelocInfo prinfo_[kMaxNumPRInfo]; // the buffer of pending relocation info
1323 int num_prinfo_; // number of pending reloc info entries in the buffer
1324
1325 // The bound position, before this we cannot do instruction elimination.
1326 int last_bound_pos_;
1327
Steve Blocka7e24c12009-10-30 11:49:00 +00001328 // Code emission
1329 inline void CheckBuffer();
1330 void GrowBuffer();
1331 inline void emit(Instr x);
1332
1333 // Instruction generation
1334 void addrmod1(Instr instr, Register rn, Register rd, const Operand& x);
1335 void addrmod2(Instr instr, Register rd, const MemOperand& x);
1336 void addrmod3(Instr instr, Register rd, const MemOperand& x);
1337 void addrmod4(Instr instr, Register rn, RegList rl);
1338 void addrmod5(Instr instr, CRegister crd, const MemOperand& x);
1339
1340 // Labels
1341 void print(Label* L);
1342 void bind_to(Label* L, int pos);
1343 void link_to(Label* L, Label* appendix);
1344 void next(Label* L);
1345
1346 // Record reloc info for current pc_
1347 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
1348
1349 friend class RegExpMacroAssemblerARM;
1350 friend class RelocInfo;
1351 friend class CodePatcher;
Steve Block6ded16b2010-05-10 14:33:55 +01001352 friend class BlockConstPoolScope;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001353
1354 PositionsRecorder positions_recorder_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001355 bool allow_peephole_optimization_;
Steve Block44f0eee2011-05-26 01:26:41 +01001356 bool emit_debug_code_;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001357 friend class PositionsRecorder;
1358 friend class EnsureSpace;
Steve Blocka7e24c12009-10-30 11:49:00 +00001359};
1360
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001361
1362class EnsureSpace BASE_EMBEDDED {
1363 public:
1364 explicit EnsureSpace(Assembler* assembler) {
1365 assembler->CheckBuffer();
1366 }
1367};
1368
1369
Steve Blocka7e24c12009-10-30 11:49:00 +00001370} } // namespace v8::internal
1371
1372#endif // V8_ARM_ASSEMBLER_ARM_H_