blob: 36f7507fe790bb3f07eb926df6c342e9bb46863d [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.
69//
70// 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) {
76 return reg.code();
77 }
78
79 static Register FromAllocationIndex(int index) {
80 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
81 return from_code(index);
82 }
83
84 static const char* AllocationIndexToString(int index) {
85 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
86 const char* const names[] = {
87 "r0",
88 "r1",
89 "r2",
90 "r3",
91 "r4",
92 "r5",
93 "r6",
94 "r7",
95 };
96 return names[index];
97 }
98
99 static Register from_code(int code) {
100 Register r = { code };
101 return r;
102 }
103
104 bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100105 bool is(Register reg) const { return code_ == reg.code_; }
106 int code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000107 ASSERT(is_valid());
108 return code_;
109 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100110 int bit() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000111 ASSERT(is_valid());
112 return 1 << code_;
113 }
114
Leon Clarkef7060e22010-06-03 12:02:55 +0100115 void set_code(int code) {
116 code_ = code;
117 ASSERT(is_valid());
118 }
119
Andrei Popescu31002712010-02-23 13:46:05 +0000120 // Unfortunately we can't make this private in a struct.
Steve Blocka7e24c12009-10-30 11:49:00 +0000121 int code_;
122};
123
Steve Block6ded16b2010-05-10 14:33:55 +0100124const Register no_reg = { -1 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000125
Steve Block6ded16b2010-05-10 14:33:55 +0100126const Register r0 = { 0 };
127const Register r1 = { 1 };
128const Register r2 = { 2 };
129const Register r3 = { 3 };
130const Register r4 = { 4 };
131const Register r5 = { 5 };
132const Register r6 = { 6 };
133const Register r7 = { 7 };
134const Register r8 = { 8 }; // Used as context register.
135const Register r9 = { 9 };
136const Register r10 = { 10 }; // Used as roots register.
137const Register fp = { 11 };
138const Register ip = { 12 };
139const Register sp = { 13 };
140const Register lr = { 14 };
141const Register pc = { 15 };
Steve Blockd0582a62009-12-15 09:54:21 +0000142
Leon Clarkee46be812010-01-19 14:06:41 +0000143// Single word VFP register.
144struct SwVfpRegister {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100145 bool is_valid() const { return 0 <= code_ && code_ < 32; }
146 bool is(SwVfpRegister reg) const { return code_ == reg.code_; }
147 int code() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000148 ASSERT(is_valid());
149 return code_;
150 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100151 int bit() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000152 ASSERT(is_valid());
153 return 1 << code_;
154 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100155 void split_code(int* vm, int* m) const {
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100156 ASSERT(is_valid());
157 *m = code_ & 0x1;
158 *vm = code_ >> 1;
159 }
Leon Clarkee46be812010-01-19 14:06:41 +0000160
161 int code_;
162};
163
164
165// Double word VFP register.
166struct DwVfpRegister {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100167 // d0 has been excluded from allocation. This is following ia32
168 // where xmm0 is excluded. This should be revisited.
169 static const int kNumRegisters = 16;
170 static const int kNumAllocatableRegisters = 15;
171
172 static int ToAllocationIndex(DwVfpRegister reg) {
173 ASSERT(reg.code() != 0);
174 return reg.code() - 1;
175 }
176
177 static DwVfpRegister FromAllocationIndex(int index) {
178 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
179 return from_code(index + 1);
180 }
181
182 static const char* AllocationIndexToString(int index) {
183 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
184 const char* const names[] = {
185 "d1",
186 "d2",
187 "d3",
188 "d4",
189 "d5",
190 "d6",
191 "d7",
192 "d8",
193 "d9",
194 "d10",
195 "d11",
196 "d12",
197 "d13",
198 "d14",
199 "d15"
200 };
201 return names[index];
202 }
203
204 static DwVfpRegister from_code(int code) {
205 DwVfpRegister r = { code };
206 return r;
207 }
208
Leon Clarkee46be812010-01-19 14:06:41 +0000209 // Supporting d0 to d15, can be later extended to d31.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100210 bool is_valid() const { return 0 <= code_ && code_ < 16; }
211 bool is(DwVfpRegister reg) const { return code_ == reg.code_; }
212 SwVfpRegister low() const {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100213 SwVfpRegister reg;
214 reg.code_ = code_ * 2;
215
216 ASSERT(reg.is_valid());
217 return reg;
218 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100219 SwVfpRegister high() const {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100220 SwVfpRegister reg;
221 reg.code_ = (code_ * 2) + 1;
222
223 ASSERT(reg.is_valid());
224 return reg;
225 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100226 int code() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000227 ASSERT(is_valid());
228 return code_;
229 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100230 int bit() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000231 ASSERT(is_valid());
232 return 1 << code_;
233 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100234 void split_code(int* vm, int* m) const {
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100235 ASSERT(is_valid());
236 *m = (code_ & 0x10) >> 4;
237 *vm = code_ & 0x0F;
238 }
Leon Clarkee46be812010-01-19 14:06:41 +0000239
240 int code_;
241};
242
243
Ben Murdochb0fe1622011-05-05 13:52:32 +0100244typedef DwVfpRegister DoubleRegister;
245
246
Steve Block6ded16b2010-05-10 14:33:55 +0100247// Support for the VFP registers s0 to s31 (d0 to d15).
Leon Clarkee46be812010-01-19 14:06:41 +0000248// Note that "s(N):s(N+1)" is the same as "d(N/2)".
Steve Block6ded16b2010-05-10 14:33:55 +0100249const SwVfpRegister s0 = { 0 };
250const SwVfpRegister s1 = { 1 };
251const SwVfpRegister s2 = { 2 };
252const SwVfpRegister s3 = { 3 };
253const SwVfpRegister s4 = { 4 };
254const SwVfpRegister s5 = { 5 };
255const SwVfpRegister s6 = { 6 };
256const SwVfpRegister s7 = { 7 };
257const SwVfpRegister s8 = { 8 };
258const SwVfpRegister s9 = { 9 };
259const SwVfpRegister s10 = { 10 };
260const SwVfpRegister s11 = { 11 };
261const SwVfpRegister s12 = { 12 };
262const SwVfpRegister s13 = { 13 };
263const SwVfpRegister s14 = { 14 };
264const SwVfpRegister s15 = { 15 };
265const SwVfpRegister s16 = { 16 };
266const SwVfpRegister s17 = { 17 };
267const SwVfpRegister s18 = { 18 };
268const SwVfpRegister s19 = { 19 };
269const SwVfpRegister s20 = { 20 };
270const SwVfpRegister s21 = { 21 };
271const SwVfpRegister s22 = { 22 };
272const SwVfpRegister s23 = { 23 };
273const SwVfpRegister s24 = { 24 };
274const SwVfpRegister s25 = { 25 };
275const SwVfpRegister s26 = { 26 };
276const SwVfpRegister s27 = { 27 };
277const SwVfpRegister s28 = { 28 };
278const SwVfpRegister s29 = { 29 };
279const SwVfpRegister s30 = { 30 };
280const SwVfpRegister s31 = { 31 };
Leon Clarkee46be812010-01-19 14:06:41 +0000281
Steve Block6ded16b2010-05-10 14:33:55 +0100282const DwVfpRegister d0 = { 0 };
283const DwVfpRegister d1 = { 1 };
284const DwVfpRegister d2 = { 2 };
285const DwVfpRegister d3 = { 3 };
286const DwVfpRegister d4 = { 4 };
287const DwVfpRegister d5 = { 5 };
288const DwVfpRegister d6 = { 6 };
289const DwVfpRegister d7 = { 7 };
290const DwVfpRegister d8 = { 8 };
291const DwVfpRegister d9 = { 9 };
292const DwVfpRegister d10 = { 10 };
293const DwVfpRegister d11 = { 11 };
294const DwVfpRegister d12 = { 12 };
295const DwVfpRegister d13 = { 13 };
296const DwVfpRegister d14 = { 14 };
297const DwVfpRegister d15 = { 15 };
Leon Clarkee46be812010-01-19 14:06:41 +0000298
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800299// VFP FPSCR constants.
300static const uint32_t kVFPExceptionMask = 0xf;
301static const uint32_t kVFPRoundingModeMask = 3 << 22;
302static const uint32_t kVFPFlushToZeroMask = 1 << 24;
303static const uint32_t kVFPRoundToMinusInfinityBits = 2 << 22;
Steve Blocka7e24c12009-10-30 11:49:00 +0000304
305// Coprocessor register
306struct CRegister {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100307 bool is_valid() const { return 0 <= code_ && code_ < 16; }
308 bool is(CRegister creg) const { return code_ == creg.code_; }
309 int code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000310 ASSERT(is_valid());
311 return code_;
312 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100313 int bit() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000314 ASSERT(is_valid());
315 return 1 << code_;
316 }
317
Andrei Popescu31002712010-02-23 13:46:05 +0000318 // Unfortunately we can't make this private in a struct.
Steve Blocka7e24c12009-10-30 11:49:00 +0000319 int code_;
320};
321
322
Steve Block6ded16b2010-05-10 14:33:55 +0100323const CRegister no_creg = { -1 };
324
325const CRegister cr0 = { 0 };
326const CRegister cr1 = { 1 };
327const CRegister cr2 = { 2 };
328const CRegister cr3 = { 3 };
329const CRegister cr4 = { 4 };
330const CRegister cr5 = { 5 };
331const CRegister cr6 = { 6 };
332const CRegister cr7 = { 7 };
333const CRegister cr8 = { 8 };
334const CRegister cr9 = { 9 };
335const CRegister cr10 = { 10 };
336const CRegister cr11 = { 11 };
337const CRegister cr12 = { 12 };
338const CRegister cr13 = { 13 };
339const CRegister cr14 = { 14 };
340const CRegister cr15 = { 15 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000341
342
343// Coprocessor number
344enum Coprocessor {
345 p0 = 0,
346 p1 = 1,
347 p2 = 2,
348 p3 = 3,
349 p4 = 4,
350 p5 = 5,
351 p6 = 6,
352 p7 = 7,
353 p8 = 8,
354 p9 = 9,
355 p10 = 10,
356 p11 = 11,
357 p12 = 12,
358 p13 = 13,
359 p14 = 14,
360 p15 = 15
361};
362
363
Andrei Popescu31002712010-02-23 13:46:05 +0000364// Condition field in instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +0000365enum Condition {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100366 // any value < 0 is considered no_condition
367 no_condition = -1,
368
Steve Blocka7e24c12009-10-30 11:49:00 +0000369 eq = 0 << 28, // Z set equal.
370 ne = 1 << 28, // Z clear not equal.
371 nz = 1 << 28, // Z clear not zero.
372 cs = 2 << 28, // C set carry set.
373 hs = 2 << 28, // C set unsigned higher or same.
374 cc = 3 << 28, // C clear carry clear.
375 lo = 3 << 28, // C clear unsigned lower.
376 mi = 4 << 28, // N set negative.
377 pl = 5 << 28, // N clear positive or zero.
378 vs = 6 << 28, // V set overflow.
379 vc = 7 << 28, // V clear no overflow.
380 hi = 8 << 28, // C set, Z clear unsigned higher.
381 ls = 9 << 28, // C clear or Z set unsigned lower or same.
382 ge = 10 << 28, // N == V greater or equal.
383 lt = 11 << 28, // N != V less than.
384 gt = 12 << 28, // Z clear, N == V greater than.
385 le = 13 << 28, // Z set or N != V less then or equal
386 al = 14 << 28 // always.
387};
388
389
390// Returns the equivalent of !cc.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100391inline Condition NegateCondition(Condition cc) {
392 ASSERT(cc != al);
393 return static_cast<Condition>(cc ^ ne);
394}
Steve Blocka7e24c12009-10-30 11:49:00 +0000395
396
397// Corresponds to transposing the operands of a comparison.
398inline Condition ReverseCondition(Condition cc) {
399 switch (cc) {
400 case lo:
401 return hi;
402 case hi:
403 return lo;
404 case hs:
405 return ls;
406 case ls:
407 return hs;
408 case lt:
409 return gt;
410 case gt:
411 return lt;
412 case ge:
413 return le;
414 case le:
415 return ge;
416 default:
417 return cc;
418 };
419}
420
421
422// Branch hints are not used on the ARM. They are defined so that they can
423// appear in shared function signatures, but will be ignored in ARM
424// implementations.
425enum Hint { no_hint };
426
427// Hints are not used on the arm. Negating is trivial.
428inline Hint NegateHint(Hint ignored) { return no_hint; }
429
430
431// -----------------------------------------------------------------------------
432// Addressing modes and instruction variants
433
434// Shifter operand shift operation
435enum ShiftOp {
436 LSL = 0 << 5,
437 LSR = 1 << 5,
438 ASR = 2 << 5,
439 ROR = 3 << 5,
440 RRX = -1
441};
442
443
444// Condition code updating mode
445enum SBit {
446 SetCC = 1 << 20, // set condition code
447 LeaveCC = 0 << 20 // leave condition code unchanged
448};
449
450
451// Status register selection
452enum SRegister {
453 CPSR = 0 << 22,
454 SPSR = 1 << 22
455};
456
457
458// Status register fields
459enum SRegisterField {
460 CPSR_c = CPSR | 1 << 16,
461 CPSR_x = CPSR | 1 << 17,
462 CPSR_s = CPSR | 1 << 18,
463 CPSR_f = CPSR | 1 << 19,
464 SPSR_c = SPSR | 1 << 16,
465 SPSR_x = SPSR | 1 << 17,
466 SPSR_s = SPSR | 1 << 18,
467 SPSR_f = SPSR | 1 << 19
468};
469
470// Status register field mask (or'ed SRegisterField enum values)
471typedef uint32_t SRegisterFieldMask;
472
473
474// Memory operand addressing mode
475enum AddrMode {
476 // bit encoding P U W
477 Offset = (8|4|0) << 21, // offset (without writeback to base)
478 PreIndex = (8|4|1) << 21, // pre-indexed addressing with writeback
479 PostIndex = (0|4|0) << 21, // post-indexed addressing with writeback
480 NegOffset = (8|0|0) << 21, // negative offset (without writeback to base)
481 NegPreIndex = (8|0|1) << 21, // negative pre-indexed with writeback
482 NegPostIndex = (0|0|0) << 21 // negative post-indexed with writeback
483};
484
485
486// Load/store multiple addressing mode
487enum BlockAddrMode {
488 // bit encoding P U W
489 da = (0|0|0) << 21, // decrement after
490 ia = (0|4|0) << 21, // increment after
491 db = (8|0|0) << 21, // decrement before
492 ib = (8|4|0) << 21, // increment before
493 da_w = (0|0|1) << 21, // decrement after with writeback to base
494 ia_w = (0|4|1) << 21, // increment after with writeback to base
495 db_w = (8|0|1) << 21, // decrement before with writeback to base
496 ib_w = (8|4|1) << 21 // increment before with writeback to base
497};
498
499
500// Coprocessor load/store operand size
501enum LFlag {
502 Long = 1 << 22, // long load/store coprocessor
503 Short = 0 << 22 // short load/store coprocessor
504};
505
506
507// -----------------------------------------------------------------------------
508// Machine instruction Operands
509
510// Class Operand represents a shifter operand in data processing instructions
511class Operand BASE_EMBEDDED {
512 public:
513 // immediate
514 INLINE(explicit Operand(int32_t immediate,
515 RelocInfo::Mode rmode = RelocInfo::NONE));
516 INLINE(explicit Operand(const ExternalReference& f));
517 INLINE(explicit Operand(const char* s));
Steve Blocka7e24c12009-10-30 11:49:00 +0000518 explicit Operand(Handle<Object> handle);
519 INLINE(explicit Operand(Smi* value));
520
521 // rm
522 INLINE(explicit Operand(Register rm));
523
524 // rm <shift_op> shift_imm
525 explicit Operand(Register rm, ShiftOp shift_op, int shift_imm);
526
527 // rm <shift_op> rs
528 explicit Operand(Register rm, ShiftOp shift_op, Register rs);
529
530 // Return true if this is a register operand.
531 INLINE(bool is_reg() const);
532
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100533 // Return true of this operand fits in one instruction so that no
534 // 2-instruction solution with a load into the ip register is necessary.
535 bool is_single_instruction() const;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800536 bool must_use_constant_pool() const;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100537
538 inline int32_t immediate() const {
539 ASSERT(!rm_.is_valid());
540 return imm32_;
541 }
542
Steve Blocka7e24c12009-10-30 11:49:00 +0000543 Register rm() const { return rm_; }
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100544 Register rs() const { return rs_; }
545 ShiftOp shift_op() const { return shift_op_; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000546
547 private:
548 Register rm_;
549 Register rs_;
550 ShiftOp shift_op_;
551 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
552 int32_t imm32_; // valid if rm_ == no_reg
553 RelocInfo::Mode rmode_;
554
555 friend class Assembler;
556};
557
558
559// Class MemOperand represents a memory operand in load and store instructions
560class MemOperand BASE_EMBEDDED {
561 public:
562 // [rn +/- offset] Offset/NegOffset
563 // [rn +/- offset]! PreIndex/NegPreIndex
564 // [rn], +/- offset PostIndex/NegPostIndex
565 // offset is any signed 32-bit value; offset is first loaded to register ip if
566 // it does not fit the addressing mode (12-bit unsigned and sign bit)
567 explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset);
568
569 // [rn +/- rm] Offset/NegOffset
570 // [rn +/- rm]! PreIndex/NegPreIndex
571 // [rn], +/- rm PostIndex/NegPostIndex
572 explicit MemOperand(Register rn, Register rm, AddrMode am = Offset);
573
574 // [rn +/- rm <shift_op> shift_imm] Offset/NegOffset
575 // [rn +/- rm <shift_op> shift_imm]! PreIndex/NegPreIndex
576 // [rn], +/- rm <shift_op> shift_imm PostIndex/NegPostIndex
577 explicit MemOperand(Register rn, Register rm,
578 ShiftOp shift_op, int shift_imm, AddrMode am = Offset);
579
Kristian Monsen25f61362010-05-21 11:50:48 +0100580 void set_offset(int32_t offset) {
581 ASSERT(rm_.is(no_reg));
582 offset_ = offset;
583 }
584
585 uint32_t offset() {
586 ASSERT(rm_.is(no_reg));
587 return offset_;
588 }
589
Leon Clarkef7060e22010-06-03 12:02:55 +0100590 Register rn() const { return rn_; }
591 Register rm() const { return rm_; }
Kristian Monsen25f61362010-05-21 11:50:48 +0100592
Steve Blocka7e24c12009-10-30 11:49:00 +0000593 private:
594 Register rn_; // base
595 Register rm_; // register offset
596 int32_t offset_; // valid if rm_ == no_reg
597 ShiftOp shift_op_;
598 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
599 AddrMode am_; // bits P, U, and W
600
601 friend class Assembler;
602};
603
Steve Blockd0582a62009-12-15 09:54:21 +0000604// CpuFeatures keeps track of which features are supported by the target CPU.
605// Supported features must be enabled by a Scope before use.
606class CpuFeatures : public AllStatic {
607 public:
608 // Detect features of the target CPU. Set safe defaults if the serializer
609 // is enabled (snapshots must be portable).
Ben Murdochb0fe1622011-05-05 13:52:32 +0100610 static void Probe(bool portable);
Steve Blockd0582a62009-12-15 09:54:21 +0000611
612 // Check whether a feature is supported by the target CPU.
613 static bool IsSupported(CpuFeature f) {
614 if (f == VFP3 && !FLAG_enable_vfp3) return false;
615 return (supported_ & (1u << f)) != 0;
616 }
617
618 // Check whether a feature is currently enabled.
619 static bool IsEnabled(CpuFeature f) {
620 return (enabled_ & (1u << f)) != 0;
621 }
622
623 // Enable a specified feature within a scope.
624 class Scope BASE_EMBEDDED {
625#ifdef DEBUG
626 public:
627 explicit Scope(CpuFeature f) {
628 ASSERT(CpuFeatures::IsSupported(f));
629 ASSERT(!Serializer::enabled() ||
630 (found_by_runtime_probing_ & (1u << f)) == 0);
631 old_enabled_ = CpuFeatures::enabled_;
632 CpuFeatures::enabled_ |= 1u << f;
633 }
634 ~Scope() { CpuFeatures::enabled_ = old_enabled_; }
635 private:
636 unsigned old_enabled_;
637#else
638 public:
639 explicit Scope(CpuFeature f) {}
640#endif
641 };
642
643 private:
644 static unsigned supported_;
645 static unsigned enabled_;
646 static unsigned found_by_runtime_probing_;
647};
648
Steve Blocka7e24c12009-10-30 11:49:00 +0000649
650typedef int32_t Instr;
651
652
653extern const Instr kMovLrPc;
Steve Block6ded16b2010-05-10 14:33:55 +0100654extern const Instr kLdrPCMask;
Steve Blocka7e24c12009-10-30 11:49:00 +0000655extern const Instr kLdrPCPattern;
Steve Block6ded16b2010-05-10 14:33:55 +0100656extern const Instr kBlxRegMask;
657extern const Instr kBlxRegPattern;
Steve Blocka7e24c12009-10-30 11:49:00 +0000658
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100659extern const Instr kMovMvnMask;
660extern const Instr kMovMvnPattern;
661extern const Instr kMovMvnFlip;
662
663extern const Instr kMovLeaveCCMask;
664extern const Instr kMovLeaveCCPattern;
665extern const Instr kMovwMask;
666extern const Instr kMovwPattern;
667extern const Instr kMovwLeaveCCFlip;
668
669extern const Instr kCmpCmnMask;
670extern const Instr kCmpCmnPattern;
671extern const Instr kCmpCmnFlip;
672
673extern const Instr kALUMask;
674extern const Instr kAddPattern;
675extern const Instr kSubPattern;
676extern const Instr kAndPattern;
677extern const Instr kBicPattern;
678extern const Instr kAddSubFlip;
679extern const Instr kAndBicFlip;
Steve Blocka7e24c12009-10-30 11:49:00 +0000680
681class Assembler : public Malloced {
682 public:
683 // Create an assembler. Instructions and relocation information are emitted
684 // into a buffer, with the instructions starting from the beginning and the
685 // relocation information starting from the end of the buffer. See CodeDesc
686 // for a detailed comment on the layout (globals.h).
687 //
688 // If the provided buffer is NULL, the assembler allocates and grows its own
689 // buffer, and buffer_size determines the initial buffer size. The buffer is
690 // owned by the assembler and deallocated upon destruction of the assembler.
691 //
692 // If the provided buffer is not NULL, the assembler uses the provided buffer
693 // for code generation and assumes its size to be buffer_size. If the buffer
694 // is too small, a fatal error occurs. No deallocation of the buffer is done
695 // upon destruction of the assembler.
696 Assembler(void* buffer, int buffer_size);
697 ~Assembler();
698
699 // GetCode emits any pending (non-emitted) code and fills the descriptor
700 // desc. GetCode() is idempotent; it returns the same result if no other
701 // Assembler functions are invoked in between GetCode() calls.
702 void GetCode(CodeDesc* desc);
703
704 // Label operations & relative jumps (PPUM Appendix D)
705 //
706 // Takes a branch opcode (cc) and a label (L) and generates
707 // either a backward branch or a forward branch and links it
708 // to the label fixup chain. Usage:
709 //
710 // Label L; // unbound label
711 // j(cc, &L); // forward branch to unbound label
712 // bind(&L); // bind label to the current pc
713 // j(cc, &L); // backward branch to bound label
714 // bind(&L); // illegal: a label may be bound only once
715 //
716 // Note: The same Label can be used for forward and backward branches
717 // but it may be bound only once.
718
719 void bind(Label* L); // binds an unbound label L to the current code position
720
721 // Returns the branch offset to the given label from the current code position
722 // Links the label to the current position if it is still unbound
723 // Manages the jump elimination optimization if the second parameter is true.
724 int branch_offset(Label* L, bool jump_elimination_allowed);
725
726 // Puts a labels target address at the given position.
727 // The high 8 bits are set to zero.
728 void label_at_put(Label* L, int at_offset);
729
730 // Return the address in the constant pool of the code target address used by
731 // the branch/call instruction at pc.
732 INLINE(static Address target_address_address_at(Address pc));
733
734 // Read/Modify the code target address in the branch/call instruction at pc.
735 INLINE(static Address target_address_at(Address pc));
736 INLINE(static void set_target_address_at(Address pc, Address target));
737
Steve Blockd0582a62009-12-15 09:54:21 +0000738 // This sets the branch destination (which is in the constant pool on ARM).
739 // This is for calls and branches within generated code.
740 inline static void set_target_at(Address constant_pool_entry, Address target);
741
742 // This sets the branch destination (which is in the constant pool on ARM).
743 // This is for calls and branches to runtime code.
744 inline static void set_external_target_at(Address constant_pool_entry,
745 Address target) {
746 set_target_at(constant_pool_entry, target);
747 }
748
749 // Here we are patching the address in the constant pool, not the actual call
750 // instruction. The address in the constant pool is the same size as a
751 // pointer.
752 static const int kCallTargetSize = kPointerSize;
753 static const int kExternalTargetSize = kPointerSize;
754
Steve Blocka7e24c12009-10-30 11:49:00 +0000755 // Size of an instruction.
756 static const int kInstrSize = sizeof(Instr);
757
758 // Distance between the instruction referring to the address of the call
Steve Block6ded16b2010-05-10 14:33:55 +0100759 // target and the return address.
760#ifdef USE_BLX
761 // Call sequence is:
762 // ldr ip, [pc, #...] @ call address
763 // blx ip
764 // @ return address
765 static const int kCallTargetAddressOffset = 2 * kInstrSize;
766#else
767 // Call sequence is:
768 // mov lr, pc
769 // ldr pc, [pc, #...] @ call address
770 // @ return address
Steve Blocka7e24c12009-10-30 11:49:00 +0000771 static const int kCallTargetAddressOffset = kInstrSize;
Steve Block6ded16b2010-05-10 14:33:55 +0100772#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000773
774 // Distance between start of patched return sequence and the emitted address
775 // to jump to.
Steve Block6ded16b2010-05-10 14:33:55 +0100776#ifdef USE_BLX
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100777 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100778 // ldr ip, [pc, #0] @ emited address and start
779 // blx ip
780 static const int kPatchReturnSequenceAddressOffset = 0 * kInstrSize;
781#else
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100782 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100783 // mov lr, pc @ start of sequence
784 // ldr pc, [pc, #-4] @ emited address
785 static const int kPatchReturnSequenceAddressOffset = kInstrSize;
786#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000787
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100788 // Distance between start of patched debug break slot and the emitted address
789 // to jump to.
790#ifdef USE_BLX
791 // Patched debug break slot code is:
792 // ldr ip, [pc, #0] @ emited address and start
793 // blx ip
794 static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
795#else
796 // Patched debug break slot code is:
797 // mov lr, pc @ start of sequence
798 // ldr pc, [pc, #-4] @ emited address
799 static const int kPatchDebugBreakSlotAddressOffset = kInstrSize;
800#endif
801
Steve Blocka7e24c12009-10-30 11:49:00 +0000802 // Difference between address of current opcode and value read from pc
803 // register.
804 static const int kPcLoadDelta = 8;
805
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100806 static const int kJSReturnSequenceInstructions = 4;
807 static const int kDebugBreakSlotInstructions = 3;
808 static const int kDebugBreakSlotLength =
809 kDebugBreakSlotInstructions * kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +0000810
811 // ---------------------------------------------------------------------------
812 // Code generation
813
814 // Insert the smallest number of nop instructions
815 // possible to align the pc offset to a multiple
816 // of m. m must be a power of 2 (>= 4).
817 void Align(int m);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100818 // Aligns code to something that's optimal for a jump target for the platform.
819 void CodeTargetAlign();
Steve Blocka7e24c12009-10-30 11:49:00 +0000820
821 // Branch instructions
822 void b(int branch_offset, Condition cond = al);
823 void bl(int branch_offset, Condition cond = al);
824 void blx(int branch_offset); // v5 and above
825 void blx(Register target, Condition cond = al); // v5 and above
826 void bx(Register target, Condition cond = al); // v5 and above, plus v4t
827
828 // Convenience branch instructions using labels
829 void b(Label* L, Condition cond = al) {
830 b(branch_offset(L, cond == al), cond);
831 }
832 void b(Condition cond, Label* L) { b(branch_offset(L, cond == al), cond); }
833 void bl(Label* L, Condition cond = al) { bl(branch_offset(L, false), cond); }
834 void bl(Condition cond, Label* L) { bl(branch_offset(L, false), cond); }
835 void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above
836
837 // Data-processing instructions
Andrei Popescu31002712010-02-23 13:46:05 +0000838
Steve Blocka7e24c12009-10-30 11:49:00 +0000839 void and_(Register dst, Register src1, const Operand& src2,
840 SBit s = LeaveCC, Condition cond = al);
841
842 void eor(Register dst, Register src1, const Operand& src2,
843 SBit s = LeaveCC, Condition cond = al);
844
845 void sub(Register dst, Register src1, const Operand& src2,
846 SBit s = LeaveCC, Condition cond = al);
847 void sub(Register dst, Register src1, Register src2,
848 SBit s = LeaveCC, Condition cond = al) {
849 sub(dst, src1, Operand(src2), s, cond);
850 }
851
852 void rsb(Register dst, Register src1, const Operand& src2,
853 SBit s = LeaveCC, Condition cond = al);
854
855 void add(Register dst, Register src1, const Operand& src2,
856 SBit s = LeaveCC, Condition cond = al);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100857 void add(Register dst, Register src1, Register src2,
858 SBit s = LeaveCC, Condition cond = al) {
859 add(dst, src1, Operand(src2), s, cond);
860 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000861
862 void adc(Register dst, Register src1, const Operand& src2,
863 SBit s = LeaveCC, Condition cond = al);
864
865 void sbc(Register dst, Register src1, const Operand& src2,
866 SBit s = LeaveCC, Condition cond = al);
867
868 void rsc(Register dst, Register src1, const Operand& src2,
869 SBit s = LeaveCC, Condition cond = al);
870
871 void tst(Register src1, const Operand& src2, Condition cond = al);
872 void tst(Register src1, Register src2, Condition cond = al) {
873 tst(src1, Operand(src2), cond);
874 }
875
876 void teq(Register src1, const Operand& src2, Condition cond = al);
877
878 void cmp(Register src1, const Operand& src2, Condition cond = al);
879 void cmp(Register src1, Register src2, Condition cond = al) {
880 cmp(src1, Operand(src2), cond);
881 }
882
883 void cmn(Register src1, const Operand& src2, Condition cond = al);
884
885 void orr(Register dst, Register src1, const Operand& src2,
886 SBit s = LeaveCC, Condition cond = al);
887 void orr(Register dst, Register src1, Register src2,
888 SBit s = LeaveCC, Condition cond = al) {
889 orr(dst, src1, Operand(src2), s, cond);
890 }
891
892 void mov(Register dst, const Operand& src,
893 SBit s = LeaveCC, Condition cond = al);
894 void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
895 mov(dst, Operand(src), s, cond);
896 }
897
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100898 // ARMv7 instructions for loading a 32 bit immediate in two instructions.
899 // This may actually emit a different mov instruction, but on an ARMv7 it
900 // is guaranteed to only emit one instruction.
901 void movw(Register reg, uint32_t immediate, Condition cond = al);
902 // The constant for movt should be in the range 0-0xffff.
903 void movt(Register reg, uint32_t immediate, Condition cond = al);
904
Steve Blocka7e24c12009-10-30 11:49:00 +0000905 void bic(Register dst, Register src1, const Operand& src2,
906 SBit s = LeaveCC, Condition cond = al);
907
908 void mvn(Register dst, const Operand& src,
909 SBit s = LeaveCC, Condition cond = al);
910
911 // Multiply instructions
912
913 void mla(Register dst, Register src1, Register src2, Register srcA,
914 SBit s = LeaveCC, Condition cond = al);
915
916 void mul(Register dst, Register src1, Register src2,
917 SBit s = LeaveCC, Condition cond = al);
918
919 void smlal(Register dstL, Register dstH, Register src1, Register src2,
920 SBit s = LeaveCC, Condition cond = al);
921
922 void smull(Register dstL, Register dstH, Register src1, Register src2,
923 SBit s = LeaveCC, Condition cond = al);
924
925 void umlal(Register dstL, Register dstH, Register src1, Register src2,
926 SBit s = LeaveCC, Condition cond = al);
927
928 void umull(Register dstL, Register dstH, Register src1, Register src2,
929 SBit s = LeaveCC, Condition cond = al);
930
931 // Miscellaneous arithmetic instructions
932
933 void clz(Register dst, Register src, Condition cond = al); // v5 and above
934
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100935 // Saturating instructions. v6 and above.
936
937 // Unsigned saturate.
938 //
939 // Saturate an optionally shifted signed value to an unsigned range.
940 //
941 // usat dst, #satpos, src
942 // usat dst, #satpos, src, lsl #sh
943 // usat dst, #satpos, src, asr #sh
944 //
945 // Register dst will contain:
946 //
947 // 0, if s < 0
948 // (1 << satpos) - 1, if s > ((1 << satpos) - 1)
949 // s, otherwise
950 //
951 // where s is the contents of src after shifting (if used.)
952 void usat(Register dst, int satpos, const Operand& src, Condition cond = al);
953
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100954 // Bitfield manipulation instructions. v7 and above.
955
956 void ubfx(Register dst, Register src, int lsb, int width,
957 Condition cond = al);
958
959 void sbfx(Register dst, Register src, int lsb, int width,
960 Condition cond = al);
961
962 void bfc(Register dst, int lsb, int width, Condition cond = al);
963
964 void bfi(Register dst, Register src, int lsb, int width,
965 Condition cond = al);
966
Steve Blocka7e24c12009-10-30 11:49:00 +0000967 // Status register access instructions
968
969 void mrs(Register dst, SRegister s, Condition cond = al);
970 void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al);
971
972 // Load/Store instructions
973 void ldr(Register dst, const MemOperand& src, Condition cond = al);
974 void str(Register src, const MemOperand& dst, Condition cond = al);
975 void ldrb(Register dst, const MemOperand& src, Condition cond = al);
976 void strb(Register src, const MemOperand& dst, Condition cond = al);
977 void ldrh(Register dst, const MemOperand& src, Condition cond = al);
978 void strh(Register src, const MemOperand& dst, Condition cond = al);
979 void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
980 void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
Leon Clarkef7060e22010-06-03 12:02:55 +0100981 void ldrd(Register dst1,
982 Register dst2,
983 const MemOperand& src, Condition cond = al);
984 void strd(Register src1,
985 Register src2,
986 const MemOperand& dst, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000987
988 // Load/Store multiple instructions
989 void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
990 void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
991
Steve Blocka7e24c12009-10-30 11:49:00 +0000992 // Exception-generating instructions and debugging support
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800993 static const int kDefaultStopCode = -1;
994 void stop(const char* msg,
995 Condition cond = al,
996 int32_t code = kDefaultStopCode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000997
998 void bkpt(uint32_t imm16); // v5 and above
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800999 void svc(uint32_t imm24, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +00001000
1001 // Coprocessor instructions
1002
1003 void cdp(Coprocessor coproc, int opcode_1,
1004 CRegister crd, CRegister crn, CRegister crm,
1005 int opcode_2, Condition cond = al);
1006
1007 void cdp2(Coprocessor coproc, int opcode_1,
1008 CRegister crd, CRegister crn, CRegister crm,
1009 int opcode_2); // v5 and above
1010
1011 void mcr(Coprocessor coproc, int opcode_1,
1012 Register rd, CRegister crn, CRegister crm,
1013 int opcode_2 = 0, Condition cond = al);
1014
1015 void mcr2(Coprocessor coproc, int opcode_1,
1016 Register rd, CRegister crn, CRegister crm,
1017 int opcode_2 = 0); // v5 and above
1018
1019 void mrc(Coprocessor coproc, int opcode_1,
1020 Register rd, CRegister crn, CRegister crm,
1021 int opcode_2 = 0, Condition cond = al);
1022
1023 void mrc2(Coprocessor coproc, int opcode_1,
1024 Register rd, CRegister crn, CRegister crm,
1025 int opcode_2 = 0); // v5 and above
1026
1027 void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src,
1028 LFlag l = Short, Condition cond = al);
1029 void ldc(Coprocessor coproc, CRegister crd, Register base, int option,
1030 LFlag l = Short, Condition cond = al);
1031
1032 void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
1033 LFlag l = Short); // v5 and above
1034 void ldc2(Coprocessor coproc, CRegister crd, Register base, int option,
1035 LFlag l = Short); // v5 and above
1036
1037 void stc(Coprocessor coproc, CRegister crd, const MemOperand& dst,
1038 LFlag l = Short, Condition cond = al);
1039 void stc(Coprocessor coproc, CRegister crd, Register base, int option,
1040 LFlag l = Short, Condition cond = al);
1041
1042 void stc2(Coprocessor coproc, CRegister crd, const MemOperand& dst,
1043 LFlag l = Short); // v5 and above
1044 void stc2(Coprocessor coproc, CRegister crd, Register base, int option,
1045 LFlag l = Short); // v5 and above
1046
Steve Blockd0582a62009-12-15 09:54:21 +00001047 // Support for VFP.
1048 // All these APIs support S0 to S31 and D0 to D15.
1049 // Currently these APIs do not support extended D registers, i.e, D16 to D31.
1050 // However, some simple modifications can allow
1051 // these APIs to support D16 to D31.
1052
Leon Clarked91b9f72010-01-27 17:25:45 +00001053 void vldr(const DwVfpRegister dst,
1054 const Register base,
1055 int offset, // Offset must be a multiple of 4.
1056 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +01001057
1058 void vldr(const SwVfpRegister dst,
1059 const Register base,
1060 int offset, // Offset must be a multiple of 4.
1061 const Condition cond = al);
1062
Leon Clarked91b9f72010-01-27 17:25:45 +00001063 void vstr(const DwVfpRegister src,
1064 const Register base,
1065 int offset, // Offset must be a multiple of 4.
1066 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +01001067
Iain Merrick75681382010-08-19 15:07:18 +01001068 void vstr(const SwVfpRegister src,
1069 const Register base,
1070 int offset, // Offset must be a multiple of 4.
1071 const Condition cond = al);
1072
Steve Block8defd9f2010-07-08 12:39:36 +01001073 void vmov(const DwVfpRegister dst,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001074 double imm,
1075 const Condition cond = al);
1076 void vmov(const SwVfpRegister dst,
1077 const SwVfpRegister src,
1078 const Condition cond = al);
1079 void vmov(const DwVfpRegister dst,
Steve Block8defd9f2010-07-08 12:39:36 +01001080 const DwVfpRegister src,
1081 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001082 void vmov(const DwVfpRegister dst,
1083 const Register src1,
Steve Blockd0582a62009-12-15 09:54:21 +00001084 const Register src2,
Leon Clarkee46be812010-01-19 14:06:41 +00001085 const Condition cond = al);
1086 void vmov(const Register dst1,
1087 const Register dst2,
1088 const DwVfpRegister src,
1089 const Condition cond = al);
1090 void vmov(const SwVfpRegister dst,
1091 const Register src,
1092 const Condition cond = al);
1093 void vmov(const Register dst,
1094 const SwVfpRegister src,
1095 const Condition cond = al);
Russell Brenner90bac252010-11-18 13:33:46 -08001096 enum ConversionMode {
1097 FPSCRRounding = 0,
1098 RoundToZero = 1
1099 };
Steve Block6ded16b2010-05-10 14:33:55 +01001100 void vcvt_f64_s32(const DwVfpRegister dst,
1101 const SwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001102 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001103 const Condition cond = al);
1104 void vcvt_f32_s32(const SwVfpRegister dst,
1105 const SwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001106 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001107 const Condition cond = al);
1108 void vcvt_f64_u32(const DwVfpRegister dst,
1109 const SwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001110 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001111 const Condition cond = al);
1112 void vcvt_s32_f64(const SwVfpRegister dst,
1113 const DwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001114 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001115 const Condition cond = al);
1116 void vcvt_u32_f64(const SwVfpRegister dst,
1117 const DwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001118 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001119 const Condition cond = al);
1120 void vcvt_f64_f32(const DwVfpRegister dst,
1121 const SwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001122 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001123 const Condition cond = al);
1124 void vcvt_f32_f64(const SwVfpRegister dst,
1125 const DwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001126 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001127 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001128
1129 void vadd(const DwVfpRegister dst,
1130 const DwVfpRegister src1,
1131 const DwVfpRegister src2,
1132 const Condition cond = al);
1133 void vsub(const DwVfpRegister dst,
1134 const DwVfpRegister src1,
1135 const DwVfpRegister src2,
1136 const Condition cond = al);
1137 void vmul(const DwVfpRegister dst,
1138 const DwVfpRegister src1,
1139 const DwVfpRegister src2,
1140 const Condition cond = al);
1141 void vdiv(const DwVfpRegister dst,
1142 const DwVfpRegister src1,
1143 const DwVfpRegister src2,
1144 const Condition cond = al);
1145 void vcmp(const DwVfpRegister src1,
1146 const DwVfpRegister src2,
Steve Blockd0582a62009-12-15 09:54:21 +00001147 const SBit s = LeaveCC,
1148 const Condition cond = al);
Iain Merrick75681382010-08-19 15:07:18 +01001149 void vcmp(const DwVfpRegister src1,
1150 const double src2,
1151 const SBit s = LeaveCC,
1152 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001153 void vmrs(const Register dst,
1154 const Condition cond = al);
Russell Brenner90bac252010-11-18 13:33:46 -08001155 void vmsr(const Register dst,
1156 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +01001157 void vsqrt(const DwVfpRegister dst,
1158 const DwVfpRegister src,
1159 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001160
Steve Blocka7e24c12009-10-30 11:49:00 +00001161 // Pseudo instructions
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001162
1163 // Different nop operations are used by the code generator to detect certain
1164 // states of the generated code.
1165 enum NopMarkerTypes {
1166 NON_MARKING_NOP = 0,
1167 DEBUG_BREAK_NOP,
1168 // IC markers.
1169 PROPERTY_ACCESS_INLINED,
1170 PROPERTY_ACCESS_INLINED_CONTEXT,
1171 PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE,
1172 // Helper values.
1173 LAST_CODE_MARKER,
1174 FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED
1175 };
1176
1177 void nop(int type = 0); // 0 is the default non-marking type.
Steve Blocka7e24c12009-10-30 11:49:00 +00001178
1179 void push(Register src, Condition cond = al) {
1180 str(src, MemOperand(sp, 4, NegPreIndex), cond);
1181 }
1182
1183 void pop(Register dst, Condition cond = al) {
1184 ldr(dst, MemOperand(sp, 4, PostIndex), cond);
1185 }
1186
1187 void pop() {
1188 add(sp, sp, Operand(kPointerSize));
1189 }
1190
Steve Blocka7e24c12009-10-30 11:49:00 +00001191 // Jump unconditionally to given label.
1192 void jmp(Label* L) { b(L, al); }
1193
1194 // Check the code size generated from label to here.
1195 int InstructionsGeneratedSince(Label* l) {
1196 return (pc_offset() - l->pos()) / kInstrSize;
1197 }
1198
Steve Blockd0582a62009-12-15 09:54:21 +00001199 // Check whether an immediate fits an addressing mode 1 instruction.
1200 bool ImmediateFitsAddrMode1Instruction(int32_t imm32);
1201
Steve Block6ded16b2010-05-10 14:33:55 +01001202 // Class for scoping postponing the constant pool generation.
1203 class BlockConstPoolScope {
1204 public:
1205 explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) {
1206 assem_->StartBlockConstPool();
1207 }
1208 ~BlockConstPoolScope() {
1209 assem_->EndBlockConstPool();
1210 }
1211
1212 private:
1213 Assembler* assem_;
1214
1215 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstPoolScope);
1216 };
1217
Steve Blockd0582a62009-12-15 09:54:21 +00001218 // Postpone the generation of the constant pool for the specified number of
1219 // instructions.
1220 void BlockConstPoolFor(int instructions);
1221
Steve Blocka7e24c12009-10-30 11:49:00 +00001222 // Debugging
1223
1224 // Mark address of the ExitJSFrame code.
1225 void RecordJSReturn();
1226
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001227 // Mark address of a debug break slot.
1228 void RecordDebugBreakSlot();
1229
Steve Blocka7e24c12009-10-30 11:49:00 +00001230 // Record a comment relocation entry that can be used by a disassembler.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001231 // Use --code-comments to enable.
Steve Blocka7e24c12009-10-30 11:49:00 +00001232 void RecordComment(const char* msg);
1233
Ben Murdochb0fe1622011-05-05 13:52:32 +01001234 // Writes a single byte or word of data in the code stream. Used for
1235 // inline tables, e.g., jump-tables.
1236 void db(uint8_t data);
1237 void dd(uint32_t data);
1238
Steve Blocka7e24c12009-10-30 11:49:00 +00001239 int pc_offset() const { return pc_ - buffer_; }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001240
1241 PositionsRecorder* positions_recorder() { return &positions_recorder_; }
Steve Block6ded16b2010-05-10 14:33:55 +01001242
Leon Clarkef7060e22010-06-03 12:02:55 +01001243 bool can_peephole_optimize(int instructions) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001244 if (!allow_peephole_optimization_) return false;
Leon Clarkef7060e22010-06-03 12:02:55 +01001245 if (last_bound_pos_ > pc_offset() - instructions * kInstrSize) return false;
1246 return reloc_info_writer.last_pc() <= pc_ - instructions * kInstrSize;
1247 }
1248
Steve Block6ded16b2010-05-10 14:33:55 +01001249 // Read/patch instructions
1250 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
1251 static void instr_at_put(byte* pc, Instr instr) {
1252 *reinterpret_cast<Instr*>(pc) = instr;
1253 }
Steve Block6ded16b2010-05-10 14:33:55 +01001254 static bool IsBranch(Instr instr);
1255 static int GetBranchOffset(Instr instr);
1256 static bool IsLdrRegisterImmediate(Instr instr);
1257 static int GetLdrRegisterImmediateOffset(Instr instr);
1258 static Instr SetLdrRegisterImmediateOffset(Instr instr, int offset);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001259 static bool IsStrRegisterImmediate(Instr instr);
1260 static Instr SetStrRegisterImmediateOffset(Instr instr, int offset);
1261 static bool IsAddRegisterImmediate(Instr instr);
1262 static Instr SetAddRegisterImmediateOffset(Instr instr, int offset);
Leon Clarkef7060e22010-06-03 12:02:55 +01001263 static Register GetRd(Instr instr);
1264 static bool IsPush(Instr instr);
1265 static bool IsPop(Instr instr);
1266 static bool IsStrRegFpOffset(Instr instr);
1267 static bool IsLdrRegFpOffset(Instr instr);
1268 static bool IsStrRegFpNegOffset(Instr instr);
1269 static bool IsLdrRegFpNegOffset(Instr instr);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001270 static bool IsLdrPcImmediateOffset(Instr instr);
1271 static bool IsNop(Instr instr, int type = NON_MARKING_NOP);
Steve Block6ded16b2010-05-10 14:33:55 +01001272
Ben Murdochb0fe1622011-05-05 13:52:32 +01001273 // Check if is time to emit a constant pool for pending reloc info entries
1274 void CheckConstPool(bool force_emit, bool require_jump);
Steve Blocka7e24c12009-10-30 11:49:00 +00001275
1276 protected:
1277 int buffer_space() const { return reloc_info_writer.pos() - pc_; }
1278
1279 // Read/patch instructions
Steve Blocka7e24c12009-10-30 11:49:00 +00001280 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
1281 void instr_at_put(int pos, Instr instr) {
1282 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
1283 }
1284
1285 // Decode branch instruction at pos and return branch target pos
1286 int target_at(int pos);
1287
1288 // Patch branch instruction at pos to branch to given branch target pos
1289 void target_at_put(int pos, int target_pos);
1290
Steve Blocka7e24c12009-10-30 11:49:00 +00001291 // Block the emission of the constant pool before pc_offset
1292 void BlockConstPoolBefore(int pc_offset) {
1293 if (no_const_pool_before_ < pc_offset) no_const_pool_before_ = pc_offset;
1294 }
1295
Steve Block6ded16b2010-05-10 14:33:55 +01001296 void StartBlockConstPool() {
1297 const_pool_blocked_nesting_++;
1298 }
1299 void EndBlockConstPool() {
1300 const_pool_blocked_nesting_--;
1301 }
Steve Block8defd9f2010-07-08 12:39:36 +01001302 bool is_const_pool_blocked() const { return const_pool_blocked_nesting_ > 0; }
Steve Block6ded16b2010-05-10 14:33:55 +01001303
Steve Blocka7e24c12009-10-30 11:49:00 +00001304 private:
1305 // Code buffer:
1306 // The buffer into which code and relocation info are generated.
1307 byte* buffer_;
1308 int buffer_size_;
1309 // True if the assembler owns the buffer, false if buffer is external.
1310 bool own_buffer_;
1311
1312 // Buffer size and constant pool distance are checked together at regular
1313 // intervals of kBufferCheckInterval emitted bytes
1314 static const int kBufferCheckInterval = 1*KB/2;
1315 int next_buffer_check_; // pc offset of next buffer check
1316
1317 // Code generation
1318 // The relocation writer's position is at least kGap bytes below the end of
1319 // the generated instructions. This is so that multi-instruction sequences do
1320 // not have to check for overflow. The same is true for writes of large
1321 // relocation info entries.
1322 static const int kGap = 32;
1323 byte* pc_; // the program counter; moves forward
1324
1325 // Constant pool generation
1326 // Pools are emitted in the instruction stream, preferably after unconditional
1327 // jumps or after returns from functions (in dead code locations).
1328 // If a long code sequence does not contain unconditional jumps, it is
1329 // necessary to emit the constant pool before the pool gets too far from the
1330 // location it is accessed from. In this case, we emit a jump over the emitted
1331 // constant pool.
1332 // Constants in the pool may be addresses of functions that gets relocated;
1333 // if so, a relocation info entry is associated to the constant pool entry.
1334
1335 // Repeated checking whether the constant pool should be emitted is rather
1336 // expensive. By default we only check again once a number of instructions
1337 // has been generated. That also means that the sizing of the buffers is not
1338 // an exact science, and that we rely on some slop to not overrun buffers.
1339 static const int kCheckConstIntervalInst = 32;
1340 static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize;
1341
1342
1343 // Pools are emitted after function return and in dead code at (more or less)
1344 // regular intervals of kDistBetweenPools bytes
1345 static const int kDistBetweenPools = 1*KB;
1346
1347 // Constants in pools are accessed via pc relative addressing, which can
1348 // reach +/-4KB thereby defining a maximum distance between the instruction
1349 // and the accessed constant. We satisfy this constraint by limiting the
1350 // distance between pools.
1351 static const int kMaxDistBetweenPools = 4*KB - 2*kBufferCheckInterval;
1352
Steve Block6ded16b2010-05-10 14:33:55 +01001353 // Emission of the constant pool may be blocked in some code sequences.
1354 int const_pool_blocked_nesting_; // Block emission if this is not zero.
1355 int no_const_pool_before_; // Block emission before this pc offset.
Steve Blocka7e24c12009-10-30 11:49:00 +00001356
1357 // Keep track of the last emitted pool to guarantee a maximal distance
1358 int last_const_pool_end_; // pc offset following the last constant pool
1359
1360 // Relocation info generation
1361 // Each relocation is encoded as a variable size value
1362 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1363 RelocInfoWriter reloc_info_writer;
1364 // Relocation info records are also used during code generation as temporary
1365 // containers for constants and code target addresses until they are emitted
1366 // to the constant pool. These pending relocation info records are temporarily
1367 // stored in a separate buffer until a constant pool is emitted.
1368 // If every instruction in a long sequence is accessing the pool, we need one
1369 // pending relocation entry per instruction.
1370 static const int kMaxNumPRInfo = kMaxDistBetweenPools/kInstrSize;
1371 RelocInfo prinfo_[kMaxNumPRInfo]; // the buffer of pending relocation info
1372 int num_prinfo_; // number of pending reloc info entries in the buffer
1373
1374 // The bound position, before this we cannot do instruction elimination.
1375 int last_bound_pos_;
1376
Steve Blocka7e24c12009-10-30 11:49:00 +00001377 // Code emission
1378 inline void CheckBuffer();
1379 void GrowBuffer();
1380 inline void emit(Instr x);
1381
1382 // Instruction generation
1383 void addrmod1(Instr instr, Register rn, Register rd, const Operand& x);
1384 void addrmod2(Instr instr, Register rd, const MemOperand& x);
1385 void addrmod3(Instr instr, Register rd, const MemOperand& x);
1386 void addrmod4(Instr instr, Register rn, RegList rl);
1387 void addrmod5(Instr instr, CRegister crd, const MemOperand& x);
1388
1389 // Labels
1390 void print(Label* L);
1391 void bind_to(Label* L, int pos);
1392 void link_to(Label* L, Label* appendix);
1393 void next(Label* L);
1394
1395 // Record reloc info for current pc_
1396 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
1397
1398 friend class RegExpMacroAssemblerARM;
1399 friend class RelocInfo;
1400 friend class CodePatcher;
Steve Block6ded16b2010-05-10 14:33:55 +01001401 friend class BlockConstPoolScope;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001402
1403 PositionsRecorder positions_recorder_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001404 bool allow_peephole_optimization_;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001405 friend class PositionsRecorder;
1406 friend class EnsureSpace;
Steve Blocka7e24c12009-10-30 11:49:00 +00001407};
1408
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001409
1410class EnsureSpace BASE_EMBEDDED {
1411 public:
1412 explicit EnsureSpace(Assembler* assembler) {
1413 assembler->CheckBuffer();
1414 }
1415};
1416
1417
Steve Blocka7e24c12009-10-30 11:49:00 +00001418} } // namespace v8::internal
1419
1420#endif // V8_ARM_ASSEMBLER_ARM_H_