blob: ad1bdabd01cd73cb18eea60a0a23ee60cb68e615 [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.
35// Copyright 2010 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 Blockd0582a62009-12-15 09:54:21 +000044#include "serialize.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000045
46namespace v8 {
47namespace internal {
48
49// CPU Registers.
50//
51// 1) We would prefer to use an enum, but enum values are assignment-
52// compatible with int, which has caused code-generation bugs.
53//
54// 2) We would prefer to use a class instead of a struct but we don't like
55// the register initialization to depend on the particular initialization
56// order (which appears to be different on OS X, Linux, and Windows for the
57// installed versions of C++ we tried). Using a struct permits C-style
58// "initialization". Also, the Register objects cannot be const as this
59// forces initialization stubs in MSVC, making us dependent on initialization
60// order.
61//
62// 3) By not using an enum, we are possibly preventing the compiler from
63// doing certain constant folds, which may significantly reduce the
64// code generated for some assembly instructions (because they boil down
65// to a few constants). If this is a problem, we could change the code
66// such that we use an enum in optimized mode, and the struct in debug
67// mode. This way we get the compile-time error checking in debug mode
68// and best performance in optimized code.
Steve Block9fac8402011-05-12 15:51:54 +010069
Steve Blocka7e24c12009-10-30 11:49:00 +000070// Core register
71struct Register {
Ben Murdochb0fe1622011-05-05 13:52:32 +010072 static const int kNumRegisters = 16;
73 static const int kNumAllocatableRegisters = 8;
74
75 static int ToAllocationIndex(Register reg) {
Steve Block9fac8402011-05-12 15:51:54 +010076 ASSERT(reg.code() < kNumAllocatableRegisters);
Ben Murdochb0fe1622011-05-05 13:52:32 +010077 return reg.code();
78 }
79
80 static Register FromAllocationIndex(int index) {
81 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
82 return from_code(index);
83 }
84
85 static const char* AllocationIndexToString(int index) {
86 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
87 const char* const names[] = {
88 "r0",
89 "r1",
90 "r2",
91 "r3",
92 "r4",
93 "r5",
94 "r6",
95 "r7",
96 };
97 return names[index];
98 }
99
100 static Register from_code(int code) {
101 Register r = { code };
102 return r;
103 }
104
105 bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100106 bool is(Register reg) const { return code_ == reg.code_; }
107 int code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000108 ASSERT(is_valid());
109 return code_;
110 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100111 int bit() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000112 ASSERT(is_valid());
113 return 1 << code_;
114 }
115
Leon Clarkef7060e22010-06-03 12:02:55 +0100116 void set_code(int code) {
117 code_ = code;
118 ASSERT(is_valid());
119 }
120
Andrei Popescu31002712010-02-23 13:46:05 +0000121 // Unfortunately we can't make this private in a struct.
Steve Blocka7e24c12009-10-30 11:49:00 +0000122 int code_;
123};
124
Steve Block6ded16b2010-05-10 14:33:55 +0100125const Register no_reg = { -1 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000126
Steve Block6ded16b2010-05-10 14:33:55 +0100127const Register r0 = { 0 };
128const Register r1 = { 1 };
129const Register r2 = { 2 };
130const Register r3 = { 3 };
131const Register r4 = { 4 };
132const Register r5 = { 5 };
133const Register r6 = { 6 };
134const Register r7 = { 7 };
135const Register r8 = { 8 }; // Used as context register.
Steve Block9fac8402011-05-12 15:51:54 +0100136const Register r9 = { 9 }; // Used as lithium codegen scratch register.
Steve Block6ded16b2010-05-10 14:33:55 +0100137const Register r10 = { 10 }; // Used as roots register.
138const Register fp = { 11 };
139const Register ip = { 12 };
140const Register sp = { 13 };
141const Register lr = { 14 };
142const Register pc = { 15 };
Steve Blockd0582a62009-12-15 09:54:21 +0000143
Leon Clarkee46be812010-01-19 14:06:41 +0000144// Single word VFP register.
145struct SwVfpRegister {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100146 bool is_valid() const { return 0 <= code_ && code_ < 32; }
147 bool is(SwVfpRegister reg) const { return code_ == reg.code_; }
148 int code() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000149 ASSERT(is_valid());
150 return code_;
151 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100152 int bit() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000153 ASSERT(is_valid());
154 return 1 << code_;
155 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100156 void split_code(int* vm, int* m) const {
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100157 ASSERT(is_valid());
158 *m = code_ & 0x1;
159 *vm = code_ >> 1;
160 }
Leon Clarkee46be812010-01-19 14:06:41 +0000161
162 int code_;
163};
164
165
166// Double word VFP register.
167struct DwVfpRegister {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100168 // d0 has been excluded from allocation. This is following ia32
169 // where xmm0 is excluded. This should be revisited.
Ben Murdochb8e0da22011-05-16 14:20:40 +0100170 // Currently d0 is used as a scratch register.
171 // d1 has also been excluded from allocation to be used as a scratch
172 // register as well.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100173 static const int kNumRegisters = 16;
174 static const int kNumAllocatableRegisters = 15;
175
176 static int ToAllocationIndex(DwVfpRegister reg) {
177 ASSERT(reg.code() != 0);
178 return reg.code() - 1;
179 }
180
181 static DwVfpRegister FromAllocationIndex(int index) {
182 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
183 return from_code(index + 1);
184 }
185
186 static const char* AllocationIndexToString(int index) {
187 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
188 const char* const names[] = {
189 "d1",
190 "d2",
191 "d3",
192 "d4",
193 "d5",
194 "d6",
195 "d7",
196 "d8",
197 "d9",
198 "d10",
199 "d11",
200 "d12",
201 "d13",
202 "d14",
203 "d15"
204 };
205 return names[index];
206 }
207
208 static DwVfpRegister from_code(int code) {
209 DwVfpRegister r = { code };
210 return r;
211 }
212
Leon Clarkee46be812010-01-19 14:06:41 +0000213 // Supporting d0 to d15, can be later extended to d31.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100214 bool is_valid() const { return 0 <= code_ && code_ < 16; }
215 bool is(DwVfpRegister reg) const { return code_ == reg.code_; }
216 SwVfpRegister low() const {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100217 SwVfpRegister reg;
218 reg.code_ = code_ * 2;
219
220 ASSERT(reg.is_valid());
221 return reg;
222 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100223 SwVfpRegister high() const {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100224 SwVfpRegister reg;
225 reg.code_ = (code_ * 2) + 1;
226
227 ASSERT(reg.is_valid());
228 return reg;
229 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100230 int code() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000231 ASSERT(is_valid());
232 return code_;
233 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100234 int bit() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000235 ASSERT(is_valid());
236 return 1 << code_;
237 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100238 void split_code(int* vm, int* m) const {
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100239 ASSERT(is_valid());
240 *m = (code_ & 0x10) >> 4;
241 *vm = code_ & 0x0F;
242 }
Leon Clarkee46be812010-01-19 14:06:41 +0000243
244 int code_;
245};
246
247
Ben Murdochb0fe1622011-05-05 13:52:32 +0100248typedef DwVfpRegister DoubleRegister;
249
250
Steve Block6ded16b2010-05-10 14:33:55 +0100251// Support for the VFP registers s0 to s31 (d0 to d15).
Leon Clarkee46be812010-01-19 14:06:41 +0000252// Note that "s(N):s(N+1)" is the same as "d(N/2)".
Steve Block6ded16b2010-05-10 14:33:55 +0100253const SwVfpRegister s0 = { 0 };
254const SwVfpRegister s1 = { 1 };
255const SwVfpRegister s2 = { 2 };
256const SwVfpRegister s3 = { 3 };
257const SwVfpRegister s4 = { 4 };
258const SwVfpRegister s5 = { 5 };
259const SwVfpRegister s6 = { 6 };
260const SwVfpRegister s7 = { 7 };
261const SwVfpRegister s8 = { 8 };
262const SwVfpRegister s9 = { 9 };
263const SwVfpRegister s10 = { 10 };
264const SwVfpRegister s11 = { 11 };
265const SwVfpRegister s12 = { 12 };
266const SwVfpRegister s13 = { 13 };
267const SwVfpRegister s14 = { 14 };
268const SwVfpRegister s15 = { 15 };
269const SwVfpRegister s16 = { 16 };
270const SwVfpRegister s17 = { 17 };
271const SwVfpRegister s18 = { 18 };
272const SwVfpRegister s19 = { 19 };
273const SwVfpRegister s20 = { 20 };
274const SwVfpRegister s21 = { 21 };
275const SwVfpRegister s22 = { 22 };
276const SwVfpRegister s23 = { 23 };
277const SwVfpRegister s24 = { 24 };
278const SwVfpRegister s25 = { 25 };
279const SwVfpRegister s26 = { 26 };
280const SwVfpRegister s27 = { 27 };
281const SwVfpRegister s28 = { 28 };
282const SwVfpRegister s29 = { 29 };
283const SwVfpRegister s30 = { 30 };
284const SwVfpRegister s31 = { 31 };
Leon Clarkee46be812010-01-19 14:06:41 +0000285
Steve Block6ded16b2010-05-10 14:33:55 +0100286const DwVfpRegister d0 = { 0 };
287const DwVfpRegister d1 = { 1 };
288const DwVfpRegister d2 = { 2 };
289const DwVfpRegister d3 = { 3 };
290const DwVfpRegister d4 = { 4 };
291const DwVfpRegister d5 = { 5 };
292const DwVfpRegister d6 = { 6 };
293const DwVfpRegister d7 = { 7 };
294const DwVfpRegister d8 = { 8 };
295const DwVfpRegister d9 = { 9 };
296const DwVfpRegister d10 = { 10 };
297const DwVfpRegister d11 = { 11 };
298const DwVfpRegister d12 = { 12 };
299const DwVfpRegister d13 = { 13 };
300const DwVfpRegister d14 = { 14 };
301const DwVfpRegister d15 = { 15 };
Leon Clarkee46be812010-01-19 14:06:41 +0000302
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800303// VFP FPSCR constants.
Ben Murdochb8e0da22011-05-16 14:20:40 +0100304static const uint32_t kVFPNConditionFlagBit = 1 << 31;
Ben Murdoch086aeea2011-05-13 15:57:08 +0100305static const uint32_t kVFPZConditionFlagBit = 1 << 30;
Ben Murdochb8e0da22011-05-16 14:20:40 +0100306static const uint32_t kVFPCConditionFlagBit = 1 << 29;
307static const uint32_t kVFPVConditionFlagBit = 1 << 28;
308
309static const uint32_t kVFPFlushToZeroMask = 1 << 24;
310
311static const uint32_t kVFPRoundingModeMask = 3 << 22;
312static const uint32_t kVFPRoundToMinusInfinityBits = 2 << 22;
313
314static const uint32_t kVFPExceptionMask = 0xf;
Steve Blocka7e24c12009-10-30 11:49:00 +0000315
316// Coprocessor register
317struct CRegister {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100318 bool is_valid() const { return 0 <= code_ && code_ < 16; }
319 bool is(CRegister creg) const { return code_ == creg.code_; }
320 int code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000321 ASSERT(is_valid());
322 return code_;
323 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100324 int bit() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000325 ASSERT(is_valid());
326 return 1 << code_;
327 }
328
Andrei Popescu31002712010-02-23 13:46:05 +0000329 // Unfortunately we can't make this private in a struct.
Steve Blocka7e24c12009-10-30 11:49:00 +0000330 int code_;
331};
332
333
Steve Block6ded16b2010-05-10 14:33:55 +0100334const CRegister no_creg = { -1 };
335
336const CRegister cr0 = { 0 };
337const CRegister cr1 = { 1 };
338const CRegister cr2 = { 2 };
339const CRegister cr3 = { 3 };
340const CRegister cr4 = { 4 };
341const CRegister cr5 = { 5 };
342const CRegister cr6 = { 6 };
343const CRegister cr7 = { 7 };
344const CRegister cr8 = { 8 };
345const CRegister cr9 = { 9 };
346const CRegister cr10 = { 10 };
347const CRegister cr11 = { 11 };
348const CRegister cr12 = { 12 };
349const CRegister cr13 = { 13 };
350const CRegister cr14 = { 14 };
351const CRegister cr15 = { 15 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000352
353
354// Coprocessor number
355enum Coprocessor {
356 p0 = 0,
357 p1 = 1,
358 p2 = 2,
359 p3 = 3,
360 p4 = 4,
361 p5 = 5,
362 p6 = 6,
363 p7 = 7,
364 p8 = 8,
365 p9 = 9,
366 p10 = 10,
367 p11 = 11,
368 p12 = 12,
369 p13 = 13,
370 p14 = 14,
371 p15 = 15
372};
373
374
Andrei Popescu31002712010-02-23 13:46:05 +0000375// Condition field in instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +0000376enum Condition {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100377 // any value < 0 is considered no_condition
378 no_condition = -1,
379
Steve Blocka7e24c12009-10-30 11:49:00 +0000380 eq = 0 << 28, // Z set equal.
381 ne = 1 << 28, // Z clear not equal.
382 nz = 1 << 28, // Z clear not zero.
383 cs = 2 << 28, // C set carry set.
384 hs = 2 << 28, // C set unsigned higher or same.
385 cc = 3 << 28, // C clear carry clear.
386 lo = 3 << 28, // C clear unsigned lower.
387 mi = 4 << 28, // N set negative.
388 pl = 5 << 28, // N clear positive or zero.
389 vs = 6 << 28, // V set overflow.
390 vc = 7 << 28, // V clear no overflow.
391 hi = 8 << 28, // C set, Z clear unsigned higher.
392 ls = 9 << 28, // C clear or Z set unsigned lower or same.
393 ge = 10 << 28, // N == V greater or equal.
394 lt = 11 << 28, // N != V less than.
395 gt = 12 << 28, // Z clear, N == V greater than.
396 le = 13 << 28, // Z set or N != V less then or equal
397 al = 14 << 28 // always.
398};
399
400
401// Returns the equivalent of !cc.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100402inline Condition NegateCondition(Condition cc) {
403 ASSERT(cc != al);
404 return static_cast<Condition>(cc ^ ne);
405}
Steve Blocka7e24c12009-10-30 11:49:00 +0000406
407
408// Corresponds to transposing the operands of a comparison.
409inline Condition ReverseCondition(Condition cc) {
410 switch (cc) {
411 case lo:
412 return hi;
413 case hi:
414 return lo;
415 case hs:
416 return ls;
417 case ls:
418 return hs;
419 case lt:
420 return gt;
421 case gt:
422 return lt;
423 case ge:
424 return le;
425 case le:
426 return ge;
427 default:
428 return cc;
429 };
430}
431
432
433// Branch hints are not used on the ARM. They are defined so that they can
434// appear in shared function signatures, but will be ignored in ARM
435// implementations.
436enum Hint { no_hint };
437
438// Hints are not used on the arm. Negating is trivial.
439inline Hint NegateHint(Hint ignored) { return no_hint; }
440
441
442// -----------------------------------------------------------------------------
443// Addressing modes and instruction variants
444
445// Shifter operand shift operation
446enum ShiftOp {
447 LSL = 0 << 5,
448 LSR = 1 << 5,
449 ASR = 2 << 5,
450 ROR = 3 << 5,
451 RRX = -1
452};
453
454
455// Condition code updating mode
456enum SBit {
457 SetCC = 1 << 20, // set condition code
458 LeaveCC = 0 << 20 // leave condition code unchanged
459};
460
461
462// Status register selection
463enum SRegister {
464 CPSR = 0 << 22,
465 SPSR = 1 << 22
466};
467
468
469// Status register fields
470enum SRegisterField {
471 CPSR_c = CPSR | 1 << 16,
472 CPSR_x = CPSR | 1 << 17,
473 CPSR_s = CPSR | 1 << 18,
474 CPSR_f = CPSR | 1 << 19,
475 SPSR_c = SPSR | 1 << 16,
476 SPSR_x = SPSR | 1 << 17,
477 SPSR_s = SPSR | 1 << 18,
478 SPSR_f = SPSR | 1 << 19
479};
480
481// Status register field mask (or'ed SRegisterField enum values)
482typedef uint32_t SRegisterFieldMask;
483
484
485// Memory operand addressing mode
486enum AddrMode {
487 // bit encoding P U W
488 Offset = (8|4|0) << 21, // offset (without writeback to base)
489 PreIndex = (8|4|1) << 21, // pre-indexed addressing with writeback
490 PostIndex = (0|4|0) << 21, // post-indexed addressing with writeback
491 NegOffset = (8|0|0) << 21, // negative offset (without writeback to base)
492 NegPreIndex = (8|0|1) << 21, // negative pre-indexed with writeback
493 NegPostIndex = (0|0|0) << 21 // negative post-indexed with writeback
494};
495
496
497// Load/store multiple addressing mode
498enum BlockAddrMode {
499 // bit encoding P U W
500 da = (0|0|0) << 21, // decrement after
501 ia = (0|4|0) << 21, // increment after
502 db = (8|0|0) << 21, // decrement before
503 ib = (8|4|0) << 21, // increment before
504 da_w = (0|0|1) << 21, // decrement after with writeback to base
505 ia_w = (0|4|1) << 21, // increment after with writeback to base
506 db_w = (8|0|1) << 21, // decrement before with writeback to base
507 ib_w = (8|4|1) << 21 // increment before with writeback to base
508};
509
510
511// Coprocessor load/store operand size
512enum LFlag {
513 Long = 1 << 22, // long load/store coprocessor
514 Short = 0 << 22 // short load/store coprocessor
515};
516
517
518// -----------------------------------------------------------------------------
519// Machine instruction Operands
520
521// Class Operand represents a shifter operand in data processing instructions
522class Operand BASE_EMBEDDED {
523 public:
524 // immediate
525 INLINE(explicit Operand(int32_t immediate,
526 RelocInfo::Mode rmode = RelocInfo::NONE));
527 INLINE(explicit Operand(const ExternalReference& f));
528 INLINE(explicit Operand(const char* s));
Steve Blocka7e24c12009-10-30 11:49:00 +0000529 explicit Operand(Handle<Object> handle);
530 INLINE(explicit Operand(Smi* value));
531
532 // rm
533 INLINE(explicit Operand(Register rm));
534
535 // rm <shift_op> shift_imm
536 explicit Operand(Register rm, ShiftOp shift_op, int shift_imm);
537
538 // rm <shift_op> rs
539 explicit Operand(Register rm, ShiftOp shift_op, Register rs);
540
541 // Return true if this is a register operand.
542 INLINE(bool is_reg() const);
543
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100544 // Return true of this operand fits in one instruction so that no
545 // 2-instruction solution with a load into the ip register is necessary.
546 bool is_single_instruction() const;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800547 bool must_use_constant_pool() const;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100548
549 inline int32_t immediate() const {
550 ASSERT(!rm_.is_valid());
551 return imm32_;
552 }
553
Steve Blocka7e24c12009-10-30 11:49:00 +0000554 Register rm() const { return rm_; }
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100555 Register rs() const { return rs_; }
556 ShiftOp shift_op() const { return shift_op_; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000557
558 private:
559 Register rm_;
560 Register rs_;
561 ShiftOp shift_op_;
562 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
563 int32_t imm32_; // valid if rm_ == no_reg
564 RelocInfo::Mode rmode_;
565
566 friend class Assembler;
567};
568
569
570// Class MemOperand represents a memory operand in load and store instructions
571class MemOperand BASE_EMBEDDED {
572 public:
573 // [rn +/- offset] Offset/NegOffset
574 // [rn +/- offset]! PreIndex/NegPreIndex
575 // [rn], +/- offset PostIndex/NegPostIndex
576 // offset is any signed 32-bit value; offset is first loaded to register ip if
577 // it does not fit the addressing mode (12-bit unsigned and sign bit)
578 explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset);
579
580 // [rn +/- rm] Offset/NegOffset
581 // [rn +/- rm]! PreIndex/NegPreIndex
582 // [rn], +/- rm PostIndex/NegPostIndex
583 explicit MemOperand(Register rn, Register rm, AddrMode am = Offset);
584
585 // [rn +/- rm <shift_op> shift_imm] Offset/NegOffset
586 // [rn +/- rm <shift_op> shift_imm]! PreIndex/NegPreIndex
587 // [rn], +/- rm <shift_op> shift_imm PostIndex/NegPostIndex
588 explicit MemOperand(Register rn, Register rm,
589 ShiftOp shift_op, int shift_imm, AddrMode am = Offset);
590
Kristian Monsen25f61362010-05-21 11:50:48 +0100591 void set_offset(int32_t offset) {
592 ASSERT(rm_.is(no_reg));
593 offset_ = offset;
594 }
595
596 uint32_t offset() {
597 ASSERT(rm_.is(no_reg));
598 return offset_;
599 }
600
Leon Clarkef7060e22010-06-03 12:02:55 +0100601 Register rn() const { return rn_; }
602 Register rm() const { return rm_; }
Kristian Monsen25f61362010-05-21 11:50:48 +0100603
Steve Blocka7e24c12009-10-30 11:49:00 +0000604 private:
605 Register rn_; // base
606 Register rm_; // register offset
607 int32_t offset_; // valid if rm_ == no_reg
608 ShiftOp shift_op_;
609 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
610 AddrMode am_; // bits P, U, and W
611
612 friend class Assembler;
613};
614
Steve Blockd0582a62009-12-15 09:54:21 +0000615// CpuFeatures keeps track of which features are supported by the target CPU.
616// Supported features must be enabled by a Scope before use.
617class CpuFeatures : public AllStatic {
618 public:
619 // Detect features of the target CPU. Set safe defaults if the serializer
620 // is enabled (snapshots must be portable).
Ben Murdochb0fe1622011-05-05 13:52:32 +0100621 static void Probe(bool portable);
Steve Blockd0582a62009-12-15 09:54:21 +0000622
623 // Check whether a feature is supported by the target CPU.
624 static bool IsSupported(CpuFeature f) {
625 if (f == VFP3 && !FLAG_enable_vfp3) return false;
626 return (supported_ & (1u << f)) != 0;
627 }
628
629 // Check whether a feature is currently enabled.
630 static bool IsEnabled(CpuFeature f) {
631 return (enabled_ & (1u << f)) != 0;
632 }
633
634 // Enable a specified feature within a scope.
635 class Scope BASE_EMBEDDED {
636#ifdef DEBUG
637 public:
638 explicit Scope(CpuFeature f) {
639 ASSERT(CpuFeatures::IsSupported(f));
640 ASSERT(!Serializer::enabled() ||
641 (found_by_runtime_probing_ & (1u << f)) == 0);
642 old_enabled_ = CpuFeatures::enabled_;
643 CpuFeatures::enabled_ |= 1u << f;
644 }
645 ~Scope() { CpuFeatures::enabled_ = old_enabled_; }
646 private:
647 unsigned old_enabled_;
648#else
649 public:
650 explicit Scope(CpuFeature f) {}
651#endif
652 };
653
654 private:
655 static unsigned supported_;
656 static unsigned enabled_;
657 static unsigned found_by_runtime_probing_;
658};
659
Steve Blocka7e24c12009-10-30 11:49:00 +0000660
661typedef int32_t Instr;
662
663
664extern const Instr kMovLrPc;
Steve Block6ded16b2010-05-10 14:33:55 +0100665extern const Instr kLdrPCMask;
Steve Blocka7e24c12009-10-30 11:49:00 +0000666extern const Instr kLdrPCPattern;
Steve Block6ded16b2010-05-10 14:33:55 +0100667extern const Instr kBlxRegMask;
668extern const Instr kBlxRegPattern;
Steve Blocka7e24c12009-10-30 11:49:00 +0000669
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100670extern const Instr kMovMvnMask;
671extern const Instr kMovMvnPattern;
672extern const Instr kMovMvnFlip;
673
674extern const Instr kMovLeaveCCMask;
675extern const Instr kMovLeaveCCPattern;
676extern const Instr kMovwMask;
677extern const Instr kMovwPattern;
678extern const Instr kMovwLeaveCCFlip;
679
680extern const Instr kCmpCmnMask;
681extern const Instr kCmpCmnPattern;
682extern const Instr kCmpCmnFlip;
683
684extern const Instr kALUMask;
685extern const Instr kAddPattern;
686extern const Instr kSubPattern;
687extern const Instr kAndPattern;
688extern const Instr kBicPattern;
689extern const Instr kAddSubFlip;
690extern const Instr kAndBicFlip;
Steve Blocka7e24c12009-10-30 11:49:00 +0000691
692class Assembler : public Malloced {
693 public:
694 // Create an assembler. Instructions and relocation information are emitted
695 // into a buffer, with the instructions starting from the beginning and the
696 // relocation information starting from the end of the buffer. See CodeDesc
697 // for a detailed comment on the layout (globals.h).
698 //
699 // If the provided buffer is NULL, the assembler allocates and grows its own
700 // buffer, and buffer_size determines the initial buffer size. The buffer is
701 // owned by the assembler and deallocated upon destruction of the assembler.
702 //
703 // If the provided buffer is not NULL, the assembler uses the provided buffer
704 // for code generation and assumes its size to be buffer_size. If the buffer
705 // is too small, a fatal error occurs. No deallocation of the buffer is done
706 // upon destruction of the assembler.
707 Assembler(void* buffer, int buffer_size);
708 ~Assembler();
709
710 // GetCode emits any pending (non-emitted) code and fills the descriptor
711 // desc. GetCode() is idempotent; it returns the same result if no other
712 // Assembler functions are invoked in between GetCode() calls.
713 void GetCode(CodeDesc* desc);
714
715 // Label operations & relative jumps (PPUM Appendix D)
716 //
717 // Takes a branch opcode (cc) and a label (L) and generates
718 // either a backward branch or a forward branch and links it
719 // to the label fixup chain. Usage:
720 //
721 // Label L; // unbound label
722 // j(cc, &L); // forward branch to unbound label
723 // bind(&L); // bind label to the current pc
724 // j(cc, &L); // backward branch to bound label
725 // bind(&L); // illegal: a label may be bound only once
726 //
727 // Note: The same Label can be used for forward and backward branches
728 // but it may be bound only once.
729
730 void bind(Label* L); // binds an unbound label L to the current code position
731
732 // Returns the branch offset to the given label from the current code position
733 // Links the label to the current position if it is still unbound
734 // Manages the jump elimination optimization if the second parameter is true.
735 int branch_offset(Label* L, bool jump_elimination_allowed);
736
737 // Puts a labels target address at the given position.
738 // The high 8 bits are set to zero.
739 void label_at_put(Label* L, int at_offset);
740
741 // Return the address in the constant pool of the code target address used by
742 // the branch/call instruction at pc.
743 INLINE(static Address target_address_address_at(Address pc));
744
745 // Read/Modify the code target address in the branch/call instruction at pc.
746 INLINE(static Address target_address_at(Address pc));
747 INLINE(static void set_target_address_at(Address pc, Address target));
748
Steve Blockd0582a62009-12-15 09:54:21 +0000749 // This sets the branch destination (which is in the constant pool on ARM).
750 // This is for calls and branches within generated code.
751 inline static void set_target_at(Address constant_pool_entry, Address target);
752
753 // This sets the branch destination (which is in the constant pool on ARM).
754 // This is for calls and branches to runtime code.
755 inline static void set_external_target_at(Address constant_pool_entry,
756 Address target) {
757 set_target_at(constant_pool_entry, target);
758 }
759
760 // Here we are patching the address in the constant pool, not the actual call
761 // instruction. The address in the constant pool is the same size as a
762 // pointer.
763 static const int kCallTargetSize = kPointerSize;
764 static const int kExternalTargetSize = kPointerSize;
765
Steve Blocka7e24c12009-10-30 11:49:00 +0000766 // Size of an instruction.
767 static const int kInstrSize = sizeof(Instr);
768
769 // Distance between the instruction referring to the address of the call
Steve Block6ded16b2010-05-10 14:33:55 +0100770 // target and the return address.
771#ifdef USE_BLX
772 // Call sequence is:
773 // ldr ip, [pc, #...] @ call address
774 // blx ip
775 // @ return address
776 static const int kCallTargetAddressOffset = 2 * kInstrSize;
777#else
778 // Call sequence is:
779 // mov lr, pc
780 // ldr pc, [pc, #...] @ call address
781 // @ return address
Steve Blocka7e24c12009-10-30 11:49:00 +0000782 static const int kCallTargetAddressOffset = kInstrSize;
Steve Block6ded16b2010-05-10 14:33:55 +0100783#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000784
785 // Distance between start of patched return sequence and the emitted address
786 // to jump to.
Steve Block6ded16b2010-05-10 14:33:55 +0100787#ifdef USE_BLX
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100788 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100789 // ldr ip, [pc, #0] @ emited address and start
790 // blx ip
791 static const int kPatchReturnSequenceAddressOffset = 0 * kInstrSize;
792#else
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100793 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100794 // mov lr, pc @ start of sequence
795 // ldr pc, [pc, #-4] @ emited address
796 static const int kPatchReturnSequenceAddressOffset = kInstrSize;
797#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000798
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100799 // Distance between start of patched debug break slot and the emitted address
800 // to jump to.
801#ifdef USE_BLX
802 // Patched debug break slot code is:
803 // ldr ip, [pc, #0] @ emited address and start
804 // blx ip
805 static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
806#else
807 // Patched debug break slot code is:
808 // mov lr, pc @ start of sequence
809 // ldr pc, [pc, #-4] @ emited address
810 static const int kPatchDebugBreakSlotAddressOffset = kInstrSize;
811#endif
812
Steve Blocka7e24c12009-10-30 11:49:00 +0000813 // Difference between address of current opcode and value read from pc
814 // register.
815 static const int kPcLoadDelta = 8;
816
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100817 static const int kJSReturnSequenceInstructions = 4;
818 static const int kDebugBreakSlotInstructions = 3;
819 static const int kDebugBreakSlotLength =
820 kDebugBreakSlotInstructions * kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +0000821
822 // ---------------------------------------------------------------------------
823 // Code generation
824
825 // Insert the smallest number of nop instructions
826 // possible to align the pc offset to a multiple
827 // of m. m must be a power of 2 (>= 4).
828 void Align(int m);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100829 // Aligns code to something that's optimal for a jump target for the platform.
830 void CodeTargetAlign();
Steve Blocka7e24c12009-10-30 11:49:00 +0000831
832 // Branch instructions
833 void b(int branch_offset, Condition cond = al);
834 void bl(int branch_offset, Condition cond = al);
835 void blx(int branch_offset); // v5 and above
836 void blx(Register target, Condition cond = al); // v5 and above
837 void bx(Register target, Condition cond = al); // v5 and above, plus v4t
838
839 // Convenience branch instructions using labels
840 void b(Label* L, Condition cond = al) {
841 b(branch_offset(L, cond == al), cond);
842 }
843 void b(Condition cond, Label* L) { b(branch_offset(L, cond == al), cond); }
844 void bl(Label* L, Condition cond = al) { bl(branch_offset(L, false), cond); }
845 void bl(Condition cond, Label* L) { bl(branch_offset(L, false), cond); }
846 void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above
847
848 // Data-processing instructions
Andrei Popescu31002712010-02-23 13:46:05 +0000849
Steve Blocka7e24c12009-10-30 11:49:00 +0000850 void and_(Register dst, Register src1, const Operand& src2,
851 SBit s = LeaveCC, Condition cond = al);
852
853 void eor(Register dst, Register src1, const Operand& src2,
854 SBit s = LeaveCC, Condition cond = al);
855
856 void sub(Register dst, Register src1, const Operand& src2,
857 SBit s = LeaveCC, Condition cond = al);
858 void sub(Register dst, Register src1, Register src2,
859 SBit s = LeaveCC, Condition cond = al) {
860 sub(dst, src1, Operand(src2), s, cond);
861 }
862
863 void rsb(Register dst, Register src1, const Operand& src2,
864 SBit s = LeaveCC, Condition cond = al);
865
866 void add(Register dst, Register src1, const Operand& src2,
867 SBit s = LeaveCC, Condition cond = al);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100868 void add(Register dst, Register src1, Register src2,
869 SBit s = LeaveCC, Condition cond = al) {
870 add(dst, src1, Operand(src2), s, cond);
871 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000872
873 void adc(Register dst, Register src1, const Operand& src2,
874 SBit s = LeaveCC, Condition cond = al);
875
876 void sbc(Register dst, Register src1, const Operand& src2,
877 SBit s = LeaveCC, Condition cond = al);
878
879 void rsc(Register dst, Register src1, const Operand& src2,
880 SBit s = LeaveCC, Condition cond = al);
881
882 void tst(Register src1, const Operand& src2, Condition cond = al);
883 void tst(Register src1, Register src2, Condition cond = al) {
884 tst(src1, Operand(src2), cond);
885 }
886
887 void teq(Register src1, const Operand& src2, Condition cond = al);
888
889 void cmp(Register src1, const Operand& src2, Condition cond = al);
890 void cmp(Register src1, Register src2, Condition cond = al) {
891 cmp(src1, Operand(src2), cond);
892 }
893
894 void cmn(Register src1, const Operand& src2, Condition cond = al);
895
896 void orr(Register dst, Register src1, const Operand& src2,
897 SBit s = LeaveCC, Condition cond = al);
898 void orr(Register dst, Register src1, Register src2,
899 SBit s = LeaveCC, Condition cond = al) {
900 orr(dst, src1, Operand(src2), s, cond);
901 }
902
903 void mov(Register dst, const Operand& src,
904 SBit s = LeaveCC, Condition cond = al);
905 void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
906 mov(dst, Operand(src), s, cond);
907 }
908
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100909 // ARMv7 instructions for loading a 32 bit immediate in two instructions.
910 // This may actually emit a different mov instruction, but on an ARMv7 it
911 // is guaranteed to only emit one instruction.
912 void movw(Register reg, uint32_t immediate, Condition cond = al);
913 // The constant for movt should be in the range 0-0xffff.
914 void movt(Register reg, uint32_t immediate, Condition cond = al);
915
Steve Blocka7e24c12009-10-30 11:49:00 +0000916 void bic(Register dst, Register src1, const Operand& src2,
917 SBit s = LeaveCC, Condition cond = al);
918
919 void mvn(Register dst, const Operand& src,
920 SBit s = LeaveCC, Condition cond = al);
921
922 // Multiply instructions
923
924 void mla(Register dst, Register src1, Register src2, Register srcA,
925 SBit s = LeaveCC, Condition cond = al);
926
927 void mul(Register dst, Register src1, Register src2,
928 SBit s = LeaveCC, Condition cond = al);
929
930 void smlal(Register dstL, Register dstH, Register src1, Register src2,
931 SBit s = LeaveCC, Condition cond = al);
932
933 void smull(Register dstL, Register dstH, Register src1, Register src2,
934 SBit s = LeaveCC, Condition cond = al);
935
936 void umlal(Register dstL, Register dstH, Register src1, Register src2,
937 SBit s = LeaveCC, Condition cond = al);
938
939 void umull(Register dstL, Register dstH, Register src1, Register src2,
940 SBit s = LeaveCC, Condition cond = al);
941
942 // Miscellaneous arithmetic instructions
943
944 void clz(Register dst, Register src, Condition cond = al); // v5 and above
945
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100946 // Saturating instructions. v6 and above.
947
948 // Unsigned saturate.
949 //
950 // Saturate an optionally shifted signed value to an unsigned range.
951 //
952 // usat dst, #satpos, src
953 // usat dst, #satpos, src, lsl #sh
954 // usat dst, #satpos, src, asr #sh
955 //
956 // Register dst will contain:
957 //
958 // 0, if s < 0
959 // (1 << satpos) - 1, if s > ((1 << satpos) - 1)
960 // s, otherwise
961 //
962 // where s is the contents of src after shifting (if used.)
963 void usat(Register dst, int satpos, const Operand& src, Condition cond = al);
964
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100965 // Bitfield manipulation instructions. v7 and above.
966
967 void ubfx(Register dst, Register src, int lsb, int width,
968 Condition cond = al);
969
970 void sbfx(Register dst, Register src, int lsb, int width,
971 Condition cond = al);
972
973 void bfc(Register dst, int lsb, int width, Condition cond = al);
974
975 void bfi(Register dst, Register src, int lsb, int width,
976 Condition cond = al);
977
Steve Blocka7e24c12009-10-30 11:49:00 +0000978 // Status register access instructions
979
980 void mrs(Register dst, SRegister s, Condition cond = al);
981 void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al);
982
983 // Load/Store instructions
984 void ldr(Register dst, const MemOperand& src, Condition cond = al);
985 void str(Register src, const MemOperand& dst, Condition cond = al);
986 void ldrb(Register dst, const MemOperand& src, Condition cond = al);
987 void strb(Register src, const MemOperand& dst, Condition cond = al);
988 void ldrh(Register dst, const MemOperand& src, Condition cond = al);
989 void strh(Register src, const MemOperand& dst, Condition cond = al);
990 void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
991 void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
Leon Clarkef7060e22010-06-03 12:02:55 +0100992 void ldrd(Register dst1,
993 Register dst2,
994 const MemOperand& src, Condition cond = al);
995 void strd(Register src1,
996 Register src2,
997 const MemOperand& dst, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000998
999 // Load/Store multiple instructions
1000 void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
1001 void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
1002
Steve Blocka7e24c12009-10-30 11:49:00 +00001003 // Exception-generating instructions and debugging support
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001004 static const int kDefaultStopCode = -1;
1005 void stop(const char* msg,
1006 Condition cond = al,
1007 int32_t code = kDefaultStopCode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001008
1009 void bkpt(uint32_t imm16); // v5 and above
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001010 void svc(uint32_t imm24, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +00001011
1012 // Coprocessor instructions
1013
1014 void cdp(Coprocessor coproc, int opcode_1,
1015 CRegister crd, CRegister crn, CRegister crm,
1016 int opcode_2, Condition cond = al);
1017
1018 void cdp2(Coprocessor coproc, int opcode_1,
1019 CRegister crd, CRegister crn, CRegister crm,
1020 int opcode_2); // v5 and above
1021
1022 void mcr(Coprocessor coproc, int opcode_1,
1023 Register rd, CRegister crn, CRegister crm,
1024 int opcode_2 = 0, Condition cond = al);
1025
1026 void mcr2(Coprocessor coproc, int opcode_1,
1027 Register rd, CRegister crn, CRegister crm,
1028 int opcode_2 = 0); // v5 and above
1029
1030 void mrc(Coprocessor coproc, int opcode_1,
1031 Register rd, CRegister crn, CRegister crm,
1032 int opcode_2 = 0, Condition cond = al);
1033
1034 void mrc2(Coprocessor coproc, int opcode_1,
1035 Register rd, CRegister crn, CRegister crm,
1036 int opcode_2 = 0); // v5 and above
1037
1038 void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src,
1039 LFlag l = Short, Condition cond = al);
1040 void ldc(Coprocessor coproc, CRegister crd, Register base, int option,
1041 LFlag l = Short, Condition cond = al);
1042
1043 void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
1044 LFlag l = Short); // v5 and above
1045 void ldc2(Coprocessor coproc, CRegister crd, Register base, int option,
1046 LFlag l = Short); // v5 and above
1047
1048 void stc(Coprocessor coproc, CRegister crd, const MemOperand& dst,
1049 LFlag l = Short, Condition cond = al);
1050 void stc(Coprocessor coproc, CRegister crd, Register base, int option,
1051 LFlag l = Short, Condition cond = al);
1052
1053 void stc2(Coprocessor coproc, CRegister crd, const MemOperand& dst,
1054 LFlag l = Short); // v5 and above
1055 void stc2(Coprocessor coproc, CRegister crd, Register base, int option,
1056 LFlag l = Short); // v5 and above
1057
Steve Blockd0582a62009-12-15 09:54:21 +00001058 // Support for VFP.
1059 // All these APIs support S0 to S31 and D0 to D15.
1060 // Currently these APIs do not support extended D registers, i.e, D16 to D31.
1061 // However, some simple modifications can allow
1062 // these APIs to support D16 to D31.
1063
Leon Clarked91b9f72010-01-27 17:25:45 +00001064 void vldr(const DwVfpRegister dst,
1065 const Register base,
1066 int offset, // Offset must be a multiple of 4.
1067 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +01001068
1069 void vldr(const SwVfpRegister dst,
1070 const Register base,
1071 int offset, // Offset must be a multiple of 4.
1072 const Condition cond = al);
1073
Leon Clarked91b9f72010-01-27 17:25:45 +00001074 void vstr(const DwVfpRegister src,
1075 const Register base,
1076 int offset, // Offset must be a multiple of 4.
1077 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +01001078
Iain Merrick75681382010-08-19 15:07:18 +01001079 void vstr(const SwVfpRegister src,
1080 const Register base,
1081 int offset, // Offset must be a multiple of 4.
1082 const Condition cond = al);
1083
Steve Block8defd9f2010-07-08 12:39:36 +01001084 void vmov(const DwVfpRegister dst,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001085 double imm,
1086 const Condition cond = al);
1087 void vmov(const SwVfpRegister dst,
1088 const SwVfpRegister src,
1089 const Condition cond = al);
1090 void vmov(const DwVfpRegister dst,
Steve Block8defd9f2010-07-08 12:39:36 +01001091 const DwVfpRegister src,
1092 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001093 void vmov(const DwVfpRegister dst,
1094 const Register src1,
Steve Blockd0582a62009-12-15 09:54:21 +00001095 const Register src2,
Leon Clarkee46be812010-01-19 14:06:41 +00001096 const Condition cond = al);
1097 void vmov(const Register dst1,
1098 const Register dst2,
1099 const DwVfpRegister src,
1100 const Condition cond = al);
1101 void vmov(const SwVfpRegister dst,
1102 const Register src,
1103 const Condition cond = al);
1104 void vmov(const Register dst,
1105 const SwVfpRegister src,
1106 const Condition cond = al);
Russell Brenner90bac252010-11-18 13:33:46 -08001107 enum ConversionMode {
1108 FPSCRRounding = 0,
1109 RoundToZero = 1
1110 };
Steve Block6ded16b2010-05-10 14:33:55 +01001111 void vcvt_f64_s32(const DwVfpRegister dst,
1112 const SwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001113 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001114 const Condition cond = al);
1115 void vcvt_f32_s32(const SwVfpRegister dst,
1116 const SwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001117 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001118 const Condition cond = al);
1119 void vcvt_f64_u32(const DwVfpRegister dst,
1120 const SwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001121 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001122 const Condition cond = al);
1123 void vcvt_s32_f64(const SwVfpRegister dst,
1124 const DwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001125 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001126 const Condition cond = al);
1127 void vcvt_u32_f64(const SwVfpRegister dst,
1128 const DwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001129 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001130 const Condition cond = al);
1131 void vcvt_f64_f32(const DwVfpRegister dst,
1132 const SwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001133 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001134 const Condition cond = al);
1135 void vcvt_f32_f64(const SwVfpRegister dst,
1136 const DwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001137 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001138 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001139
1140 void vadd(const DwVfpRegister dst,
1141 const DwVfpRegister src1,
1142 const DwVfpRegister src2,
1143 const Condition cond = al);
1144 void vsub(const DwVfpRegister dst,
1145 const DwVfpRegister src1,
1146 const DwVfpRegister src2,
1147 const Condition cond = al);
1148 void vmul(const DwVfpRegister dst,
1149 const DwVfpRegister src1,
1150 const DwVfpRegister src2,
1151 const Condition cond = al);
1152 void vdiv(const DwVfpRegister dst,
1153 const DwVfpRegister src1,
1154 const DwVfpRegister src2,
1155 const Condition cond = al);
1156 void vcmp(const DwVfpRegister src1,
1157 const DwVfpRegister src2,
Steve Blockd0582a62009-12-15 09:54:21 +00001158 const Condition cond = al);
Iain Merrick75681382010-08-19 15:07:18 +01001159 void vcmp(const DwVfpRegister src1,
1160 const double src2,
Iain Merrick75681382010-08-19 15:07:18 +01001161 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001162 void vmrs(const Register dst,
1163 const Condition cond = al);
Russell Brenner90bac252010-11-18 13:33:46 -08001164 void vmsr(const Register dst,
1165 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +01001166 void vsqrt(const DwVfpRegister dst,
1167 const DwVfpRegister src,
1168 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001169
Steve Blocka7e24c12009-10-30 11:49:00 +00001170 // Pseudo instructions
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001171
1172 // Different nop operations are used by the code generator to detect certain
1173 // states of the generated code.
1174 enum NopMarkerTypes {
1175 NON_MARKING_NOP = 0,
1176 DEBUG_BREAK_NOP,
1177 // IC markers.
1178 PROPERTY_ACCESS_INLINED,
1179 PROPERTY_ACCESS_INLINED_CONTEXT,
1180 PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE,
1181 // Helper values.
1182 LAST_CODE_MARKER,
1183 FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED
1184 };
1185
1186 void nop(int type = 0); // 0 is the default non-marking type.
Steve Blocka7e24c12009-10-30 11:49:00 +00001187
1188 void push(Register src, Condition cond = al) {
1189 str(src, MemOperand(sp, 4, NegPreIndex), cond);
1190 }
1191
1192 void pop(Register dst, Condition cond = al) {
1193 ldr(dst, MemOperand(sp, 4, PostIndex), cond);
1194 }
1195
1196 void pop() {
1197 add(sp, sp, Operand(kPointerSize));
1198 }
1199
Steve Blocka7e24c12009-10-30 11:49:00 +00001200 // Jump unconditionally to given label.
1201 void jmp(Label* L) { b(L, al); }
1202
1203 // Check the code size generated from label to here.
1204 int InstructionsGeneratedSince(Label* l) {
1205 return (pc_offset() - l->pos()) / kInstrSize;
1206 }
1207
Steve Blockd0582a62009-12-15 09:54:21 +00001208 // Check whether an immediate fits an addressing mode 1 instruction.
1209 bool ImmediateFitsAddrMode1Instruction(int32_t imm32);
1210
Steve Block6ded16b2010-05-10 14:33:55 +01001211 // Class for scoping postponing the constant pool generation.
1212 class BlockConstPoolScope {
1213 public:
1214 explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) {
1215 assem_->StartBlockConstPool();
1216 }
1217 ~BlockConstPoolScope() {
1218 assem_->EndBlockConstPool();
1219 }
1220
1221 private:
1222 Assembler* assem_;
1223
1224 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstPoolScope);
1225 };
1226
Steve Blockd0582a62009-12-15 09:54:21 +00001227 // Postpone the generation of the constant pool for the specified number of
1228 // instructions.
1229 void BlockConstPoolFor(int instructions);
1230
Steve Blocka7e24c12009-10-30 11:49:00 +00001231 // Debugging
1232
1233 // Mark address of the ExitJSFrame code.
1234 void RecordJSReturn();
1235
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001236 // Mark address of a debug break slot.
1237 void RecordDebugBreakSlot();
1238
Steve Blocka7e24c12009-10-30 11:49:00 +00001239 // Record a comment relocation entry that can be used by a disassembler.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001240 // Use --code-comments to enable.
Steve Blocka7e24c12009-10-30 11:49:00 +00001241 void RecordComment(const char* msg);
1242
Ben Murdochb8e0da22011-05-16 14:20:40 +01001243 // Writes a single byte or word of data in the code stream. Used
1244 // for inline tables, e.g., jump-tables. The constant pool should be
1245 // emitted before any use of db and dd to ensure that constant pools
1246 // are not emitted as part of the tables generated.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001247 void db(uint8_t data);
1248 void dd(uint32_t data);
1249
Steve Blocka7e24c12009-10-30 11:49:00 +00001250 int pc_offset() const { return pc_ - buffer_; }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001251
1252 PositionsRecorder* positions_recorder() { return &positions_recorder_; }
Steve Block6ded16b2010-05-10 14:33:55 +01001253
Leon Clarkef7060e22010-06-03 12:02:55 +01001254 bool can_peephole_optimize(int instructions) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001255 if (!allow_peephole_optimization_) return false;
Leon Clarkef7060e22010-06-03 12:02:55 +01001256 if (last_bound_pos_ > pc_offset() - instructions * kInstrSize) return false;
1257 return reloc_info_writer.last_pc() <= pc_ - instructions * kInstrSize;
1258 }
1259
Steve Block6ded16b2010-05-10 14:33:55 +01001260 // Read/patch instructions
1261 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
1262 static void instr_at_put(byte* pc, Instr instr) {
1263 *reinterpret_cast<Instr*>(pc) = instr;
1264 }
Steve Block6ded16b2010-05-10 14:33:55 +01001265 static bool IsBranch(Instr instr);
1266 static int GetBranchOffset(Instr instr);
1267 static bool IsLdrRegisterImmediate(Instr instr);
1268 static int GetLdrRegisterImmediateOffset(Instr instr);
1269 static Instr SetLdrRegisterImmediateOffset(Instr instr, int offset);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001270 static bool IsStrRegisterImmediate(Instr instr);
1271 static Instr SetStrRegisterImmediateOffset(Instr instr, int offset);
1272 static bool IsAddRegisterImmediate(Instr instr);
1273 static Instr SetAddRegisterImmediateOffset(Instr instr, int offset);
Leon Clarkef7060e22010-06-03 12:02:55 +01001274 static Register GetRd(Instr instr);
1275 static bool IsPush(Instr instr);
1276 static bool IsPop(Instr instr);
1277 static bool IsStrRegFpOffset(Instr instr);
1278 static bool IsLdrRegFpOffset(Instr instr);
1279 static bool IsStrRegFpNegOffset(Instr instr);
1280 static bool IsLdrRegFpNegOffset(Instr instr);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001281 static bool IsLdrPcImmediateOffset(Instr instr);
1282 static bool IsNop(Instr instr, int type = NON_MARKING_NOP);
Steve Block6ded16b2010-05-10 14:33:55 +01001283
Ben Murdochb0fe1622011-05-05 13:52:32 +01001284 // Check if is time to emit a constant pool for pending reloc info entries
1285 void CheckConstPool(bool force_emit, bool require_jump);
Steve Blocka7e24c12009-10-30 11:49:00 +00001286
1287 protected:
1288 int buffer_space() const { return reloc_info_writer.pos() - pc_; }
1289
1290 // Read/patch instructions
Steve Blocka7e24c12009-10-30 11:49:00 +00001291 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
1292 void instr_at_put(int pos, Instr instr) {
1293 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
1294 }
1295
1296 // Decode branch instruction at pos and return branch target pos
1297 int target_at(int pos);
1298
1299 // Patch branch instruction at pos to branch to given branch target pos
1300 void target_at_put(int pos, int target_pos);
1301
Steve Blocka7e24c12009-10-30 11:49:00 +00001302 // Block the emission of the constant pool before pc_offset
1303 void BlockConstPoolBefore(int pc_offset) {
1304 if (no_const_pool_before_ < pc_offset) no_const_pool_before_ = pc_offset;
1305 }
1306
Steve Block6ded16b2010-05-10 14:33:55 +01001307 void StartBlockConstPool() {
1308 const_pool_blocked_nesting_++;
1309 }
1310 void EndBlockConstPool() {
1311 const_pool_blocked_nesting_--;
1312 }
Steve Block8defd9f2010-07-08 12:39:36 +01001313 bool is_const_pool_blocked() const { return const_pool_blocked_nesting_ > 0; }
Steve Block6ded16b2010-05-10 14:33:55 +01001314
Steve Blocka7e24c12009-10-30 11:49:00 +00001315 private:
1316 // Code buffer:
1317 // The buffer into which code and relocation info are generated.
1318 byte* buffer_;
1319 int buffer_size_;
1320 // True if the assembler owns the buffer, false if buffer is external.
1321 bool own_buffer_;
1322
1323 // Buffer size and constant pool distance are checked together at regular
1324 // intervals of kBufferCheckInterval emitted bytes
1325 static const int kBufferCheckInterval = 1*KB/2;
1326 int next_buffer_check_; // pc offset of next buffer check
1327
1328 // Code generation
1329 // The relocation writer's position is at least kGap bytes below the end of
1330 // the generated instructions. This is so that multi-instruction sequences do
1331 // not have to check for overflow. The same is true for writes of large
1332 // relocation info entries.
1333 static const int kGap = 32;
1334 byte* pc_; // the program counter; moves forward
1335
1336 // Constant pool generation
1337 // Pools are emitted in the instruction stream, preferably after unconditional
1338 // jumps or after returns from functions (in dead code locations).
1339 // If a long code sequence does not contain unconditional jumps, it is
1340 // necessary to emit the constant pool before the pool gets too far from the
1341 // location it is accessed from. In this case, we emit a jump over the emitted
1342 // constant pool.
1343 // Constants in the pool may be addresses of functions that gets relocated;
1344 // if so, a relocation info entry is associated to the constant pool entry.
1345
1346 // Repeated checking whether the constant pool should be emitted is rather
1347 // expensive. By default we only check again once a number of instructions
1348 // has been generated. That also means that the sizing of the buffers is not
1349 // an exact science, and that we rely on some slop to not overrun buffers.
1350 static const int kCheckConstIntervalInst = 32;
1351 static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize;
1352
1353
1354 // Pools are emitted after function return and in dead code at (more or less)
1355 // regular intervals of kDistBetweenPools bytes
1356 static const int kDistBetweenPools = 1*KB;
1357
1358 // Constants in pools are accessed via pc relative addressing, which can
1359 // reach +/-4KB thereby defining a maximum distance between the instruction
1360 // and the accessed constant. We satisfy this constraint by limiting the
1361 // distance between pools.
1362 static const int kMaxDistBetweenPools = 4*KB - 2*kBufferCheckInterval;
1363
Steve Block6ded16b2010-05-10 14:33:55 +01001364 // Emission of the constant pool may be blocked in some code sequences.
1365 int const_pool_blocked_nesting_; // Block emission if this is not zero.
1366 int no_const_pool_before_; // Block emission before this pc offset.
Steve Blocka7e24c12009-10-30 11:49:00 +00001367
1368 // Keep track of the last emitted pool to guarantee a maximal distance
1369 int last_const_pool_end_; // pc offset following the last constant pool
1370
1371 // Relocation info generation
1372 // Each relocation is encoded as a variable size value
1373 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1374 RelocInfoWriter reloc_info_writer;
1375 // Relocation info records are also used during code generation as temporary
1376 // containers for constants and code target addresses until they are emitted
1377 // to the constant pool. These pending relocation info records are temporarily
1378 // stored in a separate buffer until a constant pool is emitted.
1379 // If every instruction in a long sequence is accessing the pool, we need one
1380 // pending relocation entry per instruction.
1381 static const int kMaxNumPRInfo = kMaxDistBetweenPools/kInstrSize;
1382 RelocInfo prinfo_[kMaxNumPRInfo]; // the buffer of pending relocation info
1383 int num_prinfo_; // number of pending reloc info entries in the buffer
1384
1385 // The bound position, before this we cannot do instruction elimination.
1386 int last_bound_pos_;
1387
Steve Blocka7e24c12009-10-30 11:49:00 +00001388 // Code emission
1389 inline void CheckBuffer();
1390 void GrowBuffer();
1391 inline void emit(Instr x);
1392
1393 // Instruction generation
1394 void addrmod1(Instr instr, Register rn, Register rd, const Operand& x);
1395 void addrmod2(Instr instr, Register rd, const MemOperand& x);
1396 void addrmod3(Instr instr, Register rd, const MemOperand& x);
1397 void addrmod4(Instr instr, Register rn, RegList rl);
1398 void addrmod5(Instr instr, CRegister crd, const MemOperand& x);
1399
1400 // Labels
1401 void print(Label* L);
1402 void bind_to(Label* L, int pos);
1403 void link_to(Label* L, Label* appendix);
1404 void next(Label* L);
1405
1406 // Record reloc info for current pc_
1407 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
1408
1409 friend class RegExpMacroAssemblerARM;
1410 friend class RelocInfo;
1411 friend class CodePatcher;
Steve Block6ded16b2010-05-10 14:33:55 +01001412 friend class BlockConstPoolScope;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001413
1414 PositionsRecorder positions_recorder_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001415 bool allow_peephole_optimization_;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001416 friend class PositionsRecorder;
1417 friend class EnsureSpace;
Steve Blocka7e24c12009-10-30 11:49:00 +00001418};
1419
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001420
1421class EnsureSpace BASE_EMBEDDED {
1422 public:
1423 explicit EnsureSpace(Assembler* assembler) {
1424 assembler->CheckBuffer();
1425 }
1426};
1427
1428
Steve Blocka7e24c12009-10-30 11:49:00 +00001429} } // namespace v8::internal
1430
1431#endif // V8_ARM_ASSEMBLER_ARM_H_