blob: cd7f07f0fa3495805dead14779cbf22cc85333a2 [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.
170 static const int kNumRegisters = 16;
171 static const int kNumAllocatableRegisters = 15;
172
173 static int ToAllocationIndex(DwVfpRegister reg) {
174 ASSERT(reg.code() != 0);
175 return reg.code() - 1;
176 }
177
178 static DwVfpRegister FromAllocationIndex(int index) {
179 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
180 return from_code(index + 1);
181 }
182
183 static const char* AllocationIndexToString(int index) {
184 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
185 const char* const names[] = {
186 "d1",
187 "d2",
188 "d3",
189 "d4",
190 "d5",
191 "d6",
192 "d7",
193 "d8",
194 "d9",
195 "d10",
196 "d11",
197 "d12",
198 "d13",
199 "d14",
200 "d15"
201 };
202 return names[index];
203 }
204
205 static DwVfpRegister from_code(int code) {
206 DwVfpRegister r = { code };
207 return r;
208 }
209
Leon Clarkee46be812010-01-19 14:06:41 +0000210 // Supporting d0 to d15, can be later extended to d31.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100211 bool is_valid() const { return 0 <= code_ && code_ < 16; }
212 bool is(DwVfpRegister reg) const { return code_ == reg.code_; }
213 SwVfpRegister low() const {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100214 SwVfpRegister reg;
215 reg.code_ = code_ * 2;
216
217 ASSERT(reg.is_valid());
218 return reg;
219 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100220 SwVfpRegister high() const {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100221 SwVfpRegister reg;
222 reg.code_ = (code_ * 2) + 1;
223
224 ASSERT(reg.is_valid());
225 return reg;
226 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100227 int code() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000228 ASSERT(is_valid());
229 return code_;
230 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100231 int bit() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000232 ASSERT(is_valid());
233 return 1 << code_;
234 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100235 void split_code(int* vm, int* m) const {
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100236 ASSERT(is_valid());
237 *m = (code_ & 0x10) >> 4;
238 *vm = code_ & 0x0F;
239 }
Leon Clarkee46be812010-01-19 14:06:41 +0000240
241 int code_;
242};
243
244
Ben Murdochb0fe1622011-05-05 13:52:32 +0100245typedef DwVfpRegister DoubleRegister;
246
247
Steve Block6ded16b2010-05-10 14:33:55 +0100248// Support for the VFP registers s0 to s31 (d0 to d15).
Leon Clarkee46be812010-01-19 14:06:41 +0000249// Note that "s(N):s(N+1)" is the same as "d(N/2)".
Steve Block6ded16b2010-05-10 14:33:55 +0100250const SwVfpRegister s0 = { 0 };
251const SwVfpRegister s1 = { 1 };
252const SwVfpRegister s2 = { 2 };
253const SwVfpRegister s3 = { 3 };
254const SwVfpRegister s4 = { 4 };
255const SwVfpRegister s5 = { 5 };
256const SwVfpRegister s6 = { 6 };
257const SwVfpRegister s7 = { 7 };
258const SwVfpRegister s8 = { 8 };
259const SwVfpRegister s9 = { 9 };
260const SwVfpRegister s10 = { 10 };
261const SwVfpRegister s11 = { 11 };
262const SwVfpRegister s12 = { 12 };
263const SwVfpRegister s13 = { 13 };
264const SwVfpRegister s14 = { 14 };
265const SwVfpRegister s15 = { 15 };
266const SwVfpRegister s16 = { 16 };
267const SwVfpRegister s17 = { 17 };
268const SwVfpRegister s18 = { 18 };
269const SwVfpRegister s19 = { 19 };
270const SwVfpRegister s20 = { 20 };
271const SwVfpRegister s21 = { 21 };
272const SwVfpRegister s22 = { 22 };
273const SwVfpRegister s23 = { 23 };
274const SwVfpRegister s24 = { 24 };
275const SwVfpRegister s25 = { 25 };
276const SwVfpRegister s26 = { 26 };
277const SwVfpRegister s27 = { 27 };
278const SwVfpRegister s28 = { 28 };
279const SwVfpRegister s29 = { 29 };
280const SwVfpRegister s30 = { 30 };
281const SwVfpRegister s31 = { 31 };
Leon Clarkee46be812010-01-19 14:06:41 +0000282
Steve Block6ded16b2010-05-10 14:33:55 +0100283const DwVfpRegister d0 = { 0 };
284const DwVfpRegister d1 = { 1 };
285const DwVfpRegister d2 = { 2 };
286const DwVfpRegister d3 = { 3 };
287const DwVfpRegister d4 = { 4 };
288const DwVfpRegister d5 = { 5 };
289const DwVfpRegister d6 = { 6 };
290const DwVfpRegister d7 = { 7 };
291const DwVfpRegister d8 = { 8 };
292const DwVfpRegister d9 = { 9 };
293const DwVfpRegister d10 = { 10 };
294const DwVfpRegister d11 = { 11 };
295const DwVfpRegister d12 = { 12 };
296const DwVfpRegister d13 = { 13 };
297const DwVfpRegister d14 = { 14 };
298const DwVfpRegister d15 = { 15 };
Leon Clarkee46be812010-01-19 14:06:41 +0000299
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800300// VFP FPSCR constants.
301static const uint32_t kVFPExceptionMask = 0xf;
302static const uint32_t kVFPRoundingModeMask = 3 << 22;
303static const uint32_t kVFPFlushToZeroMask = 1 << 24;
304static const uint32_t kVFPRoundToMinusInfinityBits = 2 << 22;
Steve Blocka7e24c12009-10-30 11:49:00 +0000305
306// Coprocessor register
307struct CRegister {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100308 bool is_valid() const { return 0 <= code_ && code_ < 16; }
309 bool is(CRegister creg) const { return code_ == creg.code_; }
310 int code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000311 ASSERT(is_valid());
312 return code_;
313 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100314 int bit() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000315 ASSERT(is_valid());
316 return 1 << code_;
317 }
318
Andrei Popescu31002712010-02-23 13:46:05 +0000319 // Unfortunately we can't make this private in a struct.
Steve Blocka7e24c12009-10-30 11:49:00 +0000320 int code_;
321};
322
323
Steve Block6ded16b2010-05-10 14:33:55 +0100324const CRegister no_creg = { -1 };
325
326const CRegister cr0 = { 0 };
327const CRegister cr1 = { 1 };
328const CRegister cr2 = { 2 };
329const CRegister cr3 = { 3 };
330const CRegister cr4 = { 4 };
331const CRegister cr5 = { 5 };
332const CRegister cr6 = { 6 };
333const CRegister cr7 = { 7 };
334const CRegister cr8 = { 8 };
335const CRegister cr9 = { 9 };
336const CRegister cr10 = { 10 };
337const CRegister cr11 = { 11 };
338const CRegister cr12 = { 12 };
339const CRegister cr13 = { 13 };
340const CRegister cr14 = { 14 };
341const CRegister cr15 = { 15 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000342
343
344// Coprocessor number
345enum Coprocessor {
346 p0 = 0,
347 p1 = 1,
348 p2 = 2,
349 p3 = 3,
350 p4 = 4,
351 p5 = 5,
352 p6 = 6,
353 p7 = 7,
354 p8 = 8,
355 p9 = 9,
356 p10 = 10,
357 p11 = 11,
358 p12 = 12,
359 p13 = 13,
360 p14 = 14,
361 p15 = 15
362};
363
364
Andrei Popescu31002712010-02-23 13:46:05 +0000365// Condition field in instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +0000366enum Condition {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100367 // any value < 0 is considered no_condition
368 no_condition = -1,
369
Steve Blocka7e24c12009-10-30 11:49:00 +0000370 eq = 0 << 28, // Z set equal.
371 ne = 1 << 28, // Z clear not equal.
372 nz = 1 << 28, // Z clear not zero.
373 cs = 2 << 28, // C set carry set.
374 hs = 2 << 28, // C set unsigned higher or same.
375 cc = 3 << 28, // C clear carry clear.
376 lo = 3 << 28, // C clear unsigned lower.
377 mi = 4 << 28, // N set negative.
378 pl = 5 << 28, // N clear positive or zero.
379 vs = 6 << 28, // V set overflow.
380 vc = 7 << 28, // V clear no overflow.
381 hi = 8 << 28, // C set, Z clear unsigned higher.
382 ls = 9 << 28, // C clear or Z set unsigned lower or same.
383 ge = 10 << 28, // N == V greater or equal.
384 lt = 11 << 28, // N != V less than.
385 gt = 12 << 28, // Z clear, N == V greater than.
386 le = 13 << 28, // Z set or N != V less then or equal
387 al = 14 << 28 // always.
388};
389
390
391// Returns the equivalent of !cc.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100392inline Condition NegateCondition(Condition cc) {
393 ASSERT(cc != al);
394 return static_cast<Condition>(cc ^ ne);
395}
Steve Blocka7e24c12009-10-30 11:49:00 +0000396
397
398// Corresponds to transposing the operands of a comparison.
399inline Condition ReverseCondition(Condition cc) {
400 switch (cc) {
401 case lo:
402 return hi;
403 case hi:
404 return lo;
405 case hs:
406 return ls;
407 case ls:
408 return hs;
409 case lt:
410 return gt;
411 case gt:
412 return lt;
413 case ge:
414 return le;
415 case le:
416 return ge;
417 default:
418 return cc;
419 };
420}
421
422
423// Branch hints are not used on the ARM. They are defined so that they can
424// appear in shared function signatures, but will be ignored in ARM
425// implementations.
426enum Hint { no_hint };
427
428// Hints are not used on the arm. Negating is trivial.
429inline Hint NegateHint(Hint ignored) { return no_hint; }
430
431
432// -----------------------------------------------------------------------------
433// Addressing modes and instruction variants
434
435// Shifter operand shift operation
436enum ShiftOp {
437 LSL = 0 << 5,
438 LSR = 1 << 5,
439 ASR = 2 << 5,
440 ROR = 3 << 5,
441 RRX = -1
442};
443
444
445// Condition code updating mode
446enum SBit {
447 SetCC = 1 << 20, // set condition code
448 LeaveCC = 0 << 20 // leave condition code unchanged
449};
450
451
452// Status register selection
453enum SRegister {
454 CPSR = 0 << 22,
455 SPSR = 1 << 22
456};
457
458
459// Status register fields
460enum SRegisterField {
461 CPSR_c = CPSR | 1 << 16,
462 CPSR_x = CPSR | 1 << 17,
463 CPSR_s = CPSR | 1 << 18,
464 CPSR_f = CPSR | 1 << 19,
465 SPSR_c = SPSR | 1 << 16,
466 SPSR_x = SPSR | 1 << 17,
467 SPSR_s = SPSR | 1 << 18,
468 SPSR_f = SPSR | 1 << 19
469};
470
471// Status register field mask (or'ed SRegisterField enum values)
472typedef uint32_t SRegisterFieldMask;
473
474
475// Memory operand addressing mode
476enum AddrMode {
477 // bit encoding P U W
478 Offset = (8|4|0) << 21, // offset (without writeback to base)
479 PreIndex = (8|4|1) << 21, // pre-indexed addressing with writeback
480 PostIndex = (0|4|0) << 21, // post-indexed addressing with writeback
481 NegOffset = (8|0|0) << 21, // negative offset (without writeback to base)
482 NegPreIndex = (8|0|1) << 21, // negative pre-indexed with writeback
483 NegPostIndex = (0|0|0) << 21 // negative post-indexed with writeback
484};
485
486
487// Load/store multiple addressing mode
488enum BlockAddrMode {
489 // bit encoding P U W
490 da = (0|0|0) << 21, // decrement after
491 ia = (0|4|0) << 21, // increment after
492 db = (8|0|0) << 21, // decrement before
493 ib = (8|4|0) << 21, // increment before
494 da_w = (0|0|1) << 21, // decrement after with writeback to base
495 ia_w = (0|4|1) << 21, // increment after with writeback to base
496 db_w = (8|0|1) << 21, // decrement before with writeback to base
497 ib_w = (8|4|1) << 21 // increment before with writeback to base
498};
499
500
501// Coprocessor load/store operand size
502enum LFlag {
503 Long = 1 << 22, // long load/store coprocessor
504 Short = 0 << 22 // short load/store coprocessor
505};
506
507
508// -----------------------------------------------------------------------------
509// Machine instruction Operands
510
511// Class Operand represents a shifter operand in data processing instructions
512class Operand BASE_EMBEDDED {
513 public:
514 // immediate
515 INLINE(explicit Operand(int32_t immediate,
516 RelocInfo::Mode rmode = RelocInfo::NONE));
517 INLINE(explicit Operand(const ExternalReference& f));
518 INLINE(explicit Operand(const char* s));
Steve Blocka7e24c12009-10-30 11:49:00 +0000519 explicit Operand(Handle<Object> handle);
520 INLINE(explicit Operand(Smi* value));
521
522 // rm
523 INLINE(explicit Operand(Register rm));
524
525 // rm <shift_op> shift_imm
526 explicit Operand(Register rm, ShiftOp shift_op, int shift_imm);
527
528 // rm <shift_op> rs
529 explicit Operand(Register rm, ShiftOp shift_op, Register rs);
530
531 // Return true if this is a register operand.
532 INLINE(bool is_reg() const);
533
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100534 // Return true of this operand fits in one instruction so that no
535 // 2-instruction solution with a load into the ip register is necessary.
536 bool is_single_instruction() const;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800537 bool must_use_constant_pool() const;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100538
539 inline int32_t immediate() const {
540 ASSERT(!rm_.is_valid());
541 return imm32_;
542 }
543
Steve Blocka7e24c12009-10-30 11:49:00 +0000544 Register rm() const { return rm_; }
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100545 Register rs() const { return rs_; }
546 ShiftOp shift_op() const { return shift_op_; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000547
548 private:
549 Register rm_;
550 Register rs_;
551 ShiftOp shift_op_;
552 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
553 int32_t imm32_; // valid if rm_ == no_reg
554 RelocInfo::Mode rmode_;
555
556 friend class Assembler;
557};
558
559
560// Class MemOperand represents a memory operand in load and store instructions
561class MemOperand BASE_EMBEDDED {
562 public:
563 // [rn +/- offset] Offset/NegOffset
564 // [rn +/- offset]! PreIndex/NegPreIndex
565 // [rn], +/- offset PostIndex/NegPostIndex
566 // offset is any signed 32-bit value; offset is first loaded to register ip if
567 // it does not fit the addressing mode (12-bit unsigned and sign bit)
568 explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset);
569
570 // [rn +/- rm] Offset/NegOffset
571 // [rn +/- rm]! PreIndex/NegPreIndex
572 // [rn], +/- rm PostIndex/NegPostIndex
573 explicit MemOperand(Register rn, Register rm, AddrMode am = Offset);
574
575 // [rn +/- rm <shift_op> shift_imm] Offset/NegOffset
576 // [rn +/- rm <shift_op> shift_imm]! PreIndex/NegPreIndex
577 // [rn], +/- rm <shift_op> shift_imm PostIndex/NegPostIndex
578 explicit MemOperand(Register rn, Register rm,
579 ShiftOp shift_op, int shift_imm, AddrMode am = Offset);
580
Kristian Monsen25f61362010-05-21 11:50:48 +0100581 void set_offset(int32_t offset) {
582 ASSERT(rm_.is(no_reg));
583 offset_ = offset;
584 }
585
586 uint32_t offset() {
587 ASSERT(rm_.is(no_reg));
588 return offset_;
589 }
590
Leon Clarkef7060e22010-06-03 12:02:55 +0100591 Register rn() const { return rn_; }
592 Register rm() const { return rm_; }
Kristian Monsen25f61362010-05-21 11:50:48 +0100593
Steve Blocka7e24c12009-10-30 11:49:00 +0000594 private:
595 Register rn_; // base
596 Register rm_; // register offset
597 int32_t offset_; // valid if rm_ == no_reg
598 ShiftOp shift_op_;
599 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
600 AddrMode am_; // bits P, U, and W
601
602 friend class Assembler;
603};
604
Steve Blockd0582a62009-12-15 09:54:21 +0000605// CpuFeatures keeps track of which features are supported by the target CPU.
606// Supported features must be enabled by a Scope before use.
607class CpuFeatures : public AllStatic {
608 public:
609 // Detect features of the target CPU. Set safe defaults if the serializer
610 // is enabled (snapshots must be portable).
Ben Murdochb0fe1622011-05-05 13:52:32 +0100611 static void Probe(bool portable);
Steve Blockd0582a62009-12-15 09:54:21 +0000612
613 // Check whether a feature is supported by the target CPU.
614 static bool IsSupported(CpuFeature f) {
615 if (f == VFP3 && !FLAG_enable_vfp3) return false;
616 return (supported_ & (1u << f)) != 0;
617 }
618
619 // Check whether a feature is currently enabled.
620 static bool IsEnabled(CpuFeature f) {
621 return (enabled_ & (1u << f)) != 0;
622 }
623
624 // Enable a specified feature within a scope.
625 class Scope BASE_EMBEDDED {
626#ifdef DEBUG
627 public:
628 explicit Scope(CpuFeature f) {
629 ASSERT(CpuFeatures::IsSupported(f));
630 ASSERT(!Serializer::enabled() ||
631 (found_by_runtime_probing_ & (1u << f)) == 0);
632 old_enabled_ = CpuFeatures::enabled_;
633 CpuFeatures::enabled_ |= 1u << f;
634 }
635 ~Scope() { CpuFeatures::enabled_ = old_enabled_; }
636 private:
637 unsigned old_enabled_;
638#else
639 public:
640 explicit Scope(CpuFeature f) {}
641#endif
642 };
643
644 private:
645 static unsigned supported_;
646 static unsigned enabled_;
647 static unsigned found_by_runtime_probing_;
648};
649
Steve Blocka7e24c12009-10-30 11:49:00 +0000650
651typedef int32_t Instr;
652
653
654extern const Instr kMovLrPc;
Steve Block6ded16b2010-05-10 14:33:55 +0100655extern const Instr kLdrPCMask;
Steve Blocka7e24c12009-10-30 11:49:00 +0000656extern const Instr kLdrPCPattern;
Steve Block6ded16b2010-05-10 14:33:55 +0100657extern const Instr kBlxRegMask;
658extern const Instr kBlxRegPattern;
Steve Blocka7e24c12009-10-30 11:49:00 +0000659
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100660extern const Instr kMovMvnMask;
661extern const Instr kMovMvnPattern;
662extern const Instr kMovMvnFlip;
663
664extern const Instr kMovLeaveCCMask;
665extern const Instr kMovLeaveCCPattern;
666extern const Instr kMovwMask;
667extern const Instr kMovwPattern;
668extern const Instr kMovwLeaveCCFlip;
669
670extern const Instr kCmpCmnMask;
671extern const Instr kCmpCmnPattern;
672extern const Instr kCmpCmnFlip;
673
674extern const Instr kALUMask;
675extern const Instr kAddPattern;
676extern const Instr kSubPattern;
677extern const Instr kAndPattern;
678extern const Instr kBicPattern;
679extern const Instr kAddSubFlip;
680extern const Instr kAndBicFlip;
Steve Blocka7e24c12009-10-30 11:49:00 +0000681
682class Assembler : public Malloced {
683 public:
684 // Create an assembler. Instructions and relocation information are emitted
685 // into a buffer, with the instructions starting from the beginning and the
686 // relocation information starting from the end of the buffer. See CodeDesc
687 // for a detailed comment on the layout (globals.h).
688 //
689 // If the provided buffer is NULL, the assembler allocates and grows its own
690 // buffer, and buffer_size determines the initial buffer size. The buffer is
691 // owned by the assembler and deallocated upon destruction of the assembler.
692 //
693 // If the provided buffer is not NULL, the assembler uses the provided buffer
694 // for code generation and assumes its size to be buffer_size. If the buffer
695 // is too small, a fatal error occurs. No deallocation of the buffer is done
696 // upon destruction of the assembler.
697 Assembler(void* buffer, int buffer_size);
698 ~Assembler();
699
700 // GetCode emits any pending (non-emitted) code and fills the descriptor
701 // desc. GetCode() is idempotent; it returns the same result if no other
702 // Assembler functions are invoked in between GetCode() calls.
703 void GetCode(CodeDesc* desc);
704
705 // Label operations & relative jumps (PPUM Appendix D)
706 //
707 // Takes a branch opcode (cc) and a label (L) and generates
708 // either a backward branch or a forward branch and links it
709 // to the label fixup chain. Usage:
710 //
711 // Label L; // unbound label
712 // j(cc, &L); // forward branch to unbound label
713 // bind(&L); // bind label to the current pc
714 // j(cc, &L); // backward branch to bound label
715 // bind(&L); // illegal: a label may be bound only once
716 //
717 // Note: The same Label can be used for forward and backward branches
718 // but it may be bound only once.
719
720 void bind(Label* L); // binds an unbound label L to the current code position
721
722 // Returns the branch offset to the given label from the current code position
723 // Links the label to the current position if it is still unbound
724 // Manages the jump elimination optimization if the second parameter is true.
725 int branch_offset(Label* L, bool jump_elimination_allowed);
726
727 // Puts a labels target address at the given position.
728 // The high 8 bits are set to zero.
729 void label_at_put(Label* L, int at_offset);
730
731 // Return the address in the constant pool of the code target address used by
732 // the branch/call instruction at pc.
733 INLINE(static Address target_address_address_at(Address pc));
734
735 // Read/Modify the code target address in the branch/call instruction at pc.
736 INLINE(static Address target_address_at(Address pc));
737 INLINE(static void set_target_address_at(Address pc, Address target));
738
Steve Blockd0582a62009-12-15 09:54:21 +0000739 // This sets the branch destination (which is in the constant pool on ARM).
740 // This is for calls and branches within generated code.
741 inline static void set_target_at(Address constant_pool_entry, Address target);
742
743 // This sets the branch destination (which is in the constant pool on ARM).
744 // This is for calls and branches to runtime code.
745 inline static void set_external_target_at(Address constant_pool_entry,
746 Address target) {
747 set_target_at(constant_pool_entry, target);
748 }
749
750 // Here we are patching the address in the constant pool, not the actual call
751 // instruction. The address in the constant pool is the same size as a
752 // pointer.
753 static const int kCallTargetSize = kPointerSize;
754 static const int kExternalTargetSize = kPointerSize;
755
Steve Blocka7e24c12009-10-30 11:49:00 +0000756 // Size of an instruction.
757 static const int kInstrSize = sizeof(Instr);
758
759 // Distance between the instruction referring to the address of the call
Steve Block6ded16b2010-05-10 14:33:55 +0100760 // target and the return address.
761#ifdef USE_BLX
762 // Call sequence is:
763 // ldr ip, [pc, #...] @ call address
764 // blx ip
765 // @ return address
766 static const int kCallTargetAddressOffset = 2 * kInstrSize;
767#else
768 // Call sequence is:
769 // mov lr, pc
770 // ldr pc, [pc, #...] @ call address
771 // @ return address
Steve Blocka7e24c12009-10-30 11:49:00 +0000772 static const int kCallTargetAddressOffset = kInstrSize;
Steve Block6ded16b2010-05-10 14:33:55 +0100773#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000774
775 // Distance between start of patched return sequence and the emitted address
776 // to jump to.
Steve Block6ded16b2010-05-10 14:33:55 +0100777#ifdef USE_BLX
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100778 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100779 // ldr ip, [pc, #0] @ emited address and start
780 // blx ip
781 static const int kPatchReturnSequenceAddressOffset = 0 * kInstrSize;
782#else
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100783 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100784 // mov lr, pc @ start of sequence
785 // ldr pc, [pc, #-4] @ emited address
786 static const int kPatchReturnSequenceAddressOffset = kInstrSize;
787#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000788
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100789 // Distance between start of patched debug break slot and the emitted address
790 // to jump to.
791#ifdef USE_BLX
792 // Patched debug break slot code is:
793 // ldr ip, [pc, #0] @ emited address and start
794 // blx ip
795 static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
796#else
797 // Patched debug break slot code is:
798 // mov lr, pc @ start of sequence
799 // ldr pc, [pc, #-4] @ emited address
800 static const int kPatchDebugBreakSlotAddressOffset = kInstrSize;
801#endif
802
Steve Blocka7e24c12009-10-30 11:49:00 +0000803 // Difference between address of current opcode and value read from pc
804 // register.
805 static const int kPcLoadDelta = 8;
806
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100807 static const int kJSReturnSequenceInstructions = 4;
808 static const int kDebugBreakSlotInstructions = 3;
809 static const int kDebugBreakSlotLength =
810 kDebugBreakSlotInstructions * kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +0000811
812 // ---------------------------------------------------------------------------
813 // Code generation
814
815 // Insert the smallest number of nop instructions
816 // possible to align the pc offset to a multiple
817 // of m. m must be a power of 2 (>= 4).
818 void Align(int m);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100819 // Aligns code to something that's optimal for a jump target for the platform.
820 void CodeTargetAlign();
Steve Blocka7e24c12009-10-30 11:49:00 +0000821
822 // Branch instructions
823 void b(int branch_offset, Condition cond = al);
824 void bl(int branch_offset, Condition cond = al);
825 void blx(int branch_offset); // v5 and above
826 void blx(Register target, Condition cond = al); // v5 and above
827 void bx(Register target, Condition cond = al); // v5 and above, plus v4t
828
829 // Convenience branch instructions using labels
830 void b(Label* L, Condition cond = al) {
831 b(branch_offset(L, cond == al), cond);
832 }
833 void b(Condition cond, Label* L) { b(branch_offset(L, cond == al), cond); }
834 void bl(Label* L, Condition cond = al) { bl(branch_offset(L, false), cond); }
835 void bl(Condition cond, Label* L) { bl(branch_offset(L, false), cond); }
836 void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above
837
838 // Data-processing instructions
Andrei Popescu31002712010-02-23 13:46:05 +0000839
Steve Blocka7e24c12009-10-30 11:49:00 +0000840 void and_(Register dst, Register src1, const Operand& src2,
841 SBit s = LeaveCC, Condition cond = al);
842
843 void eor(Register dst, Register src1, const Operand& src2,
844 SBit s = LeaveCC, Condition cond = al);
845
846 void sub(Register dst, Register src1, const Operand& src2,
847 SBit s = LeaveCC, Condition cond = al);
848 void sub(Register dst, Register src1, Register src2,
849 SBit s = LeaveCC, Condition cond = al) {
850 sub(dst, src1, Operand(src2), s, cond);
851 }
852
853 void rsb(Register dst, Register src1, const Operand& src2,
854 SBit s = LeaveCC, Condition cond = al);
855
856 void add(Register dst, Register src1, const Operand& src2,
857 SBit s = LeaveCC, Condition cond = al);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100858 void add(Register dst, Register src1, Register src2,
859 SBit s = LeaveCC, Condition cond = al) {
860 add(dst, src1, Operand(src2), s, cond);
861 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000862
863 void adc(Register dst, Register src1, const Operand& src2,
864 SBit s = LeaveCC, Condition cond = al);
865
866 void sbc(Register dst, Register src1, const Operand& src2,
867 SBit s = LeaveCC, Condition cond = al);
868
869 void rsc(Register dst, Register src1, const Operand& src2,
870 SBit s = LeaveCC, Condition cond = al);
871
872 void tst(Register src1, const Operand& src2, Condition cond = al);
873 void tst(Register src1, Register src2, Condition cond = al) {
874 tst(src1, Operand(src2), cond);
875 }
876
877 void teq(Register src1, const Operand& src2, Condition cond = al);
878
879 void cmp(Register src1, const Operand& src2, Condition cond = al);
880 void cmp(Register src1, Register src2, Condition cond = al) {
881 cmp(src1, Operand(src2), cond);
882 }
883
884 void cmn(Register src1, const Operand& src2, Condition cond = al);
885
886 void orr(Register dst, Register src1, const Operand& src2,
887 SBit s = LeaveCC, Condition cond = al);
888 void orr(Register dst, Register src1, Register src2,
889 SBit s = LeaveCC, Condition cond = al) {
890 orr(dst, src1, Operand(src2), s, cond);
891 }
892
893 void mov(Register dst, const Operand& src,
894 SBit s = LeaveCC, Condition cond = al);
895 void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
896 mov(dst, Operand(src), s, cond);
897 }
898
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100899 // ARMv7 instructions for loading a 32 bit immediate in two instructions.
900 // This may actually emit a different mov instruction, but on an ARMv7 it
901 // is guaranteed to only emit one instruction.
902 void movw(Register reg, uint32_t immediate, Condition cond = al);
903 // The constant for movt should be in the range 0-0xffff.
904 void movt(Register reg, uint32_t immediate, Condition cond = al);
905
Steve Blocka7e24c12009-10-30 11:49:00 +0000906 void bic(Register dst, Register src1, const Operand& src2,
907 SBit s = LeaveCC, Condition cond = al);
908
909 void mvn(Register dst, const Operand& src,
910 SBit s = LeaveCC, Condition cond = al);
911
912 // Multiply instructions
913
914 void mla(Register dst, Register src1, Register src2, Register srcA,
915 SBit s = LeaveCC, Condition cond = al);
916
917 void mul(Register dst, Register src1, Register src2,
918 SBit s = LeaveCC, Condition cond = al);
919
920 void smlal(Register dstL, Register dstH, Register src1, Register src2,
921 SBit s = LeaveCC, Condition cond = al);
922
923 void smull(Register dstL, Register dstH, Register src1, Register src2,
924 SBit s = LeaveCC, Condition cond = al);
925
926 void umlal(Register dstL, Register dstH, Register src1, Register src2,
927 SBit s = LeaveCC, Condition cond = al);
928
929 void umull(Register dstL, Register dstH, Register src1, Register src2,
930 SBit s = LeaveCC, Condition cond = al);
931
932 // Miscellaneous arithmetic instructions
933
934 void clz(Register dst, Register src, Condition cond = al); // v5 and above
935
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100936 // Saturating instructions. v6 and above.
937
938 // Unsigned saturate.
939 //
940 // Saturate an optionally shifted signed value to an unsigned range.
941 //
942 // usat dst, #satpos, src
943 // usat dst, #satpos, src, lsl #sh
944 // usat dst, #satpos, src, asr #sh
945 //
946 // Register dst will contain:
947 //
948 // 0, if s < 0
949 // (1 << satpos) - 1, if s > ((1 << satpos) - 1)
950 // s, otherwise
951 //
952 // where s is the contents of src after shifting (if used.)
953 void usat(Register dst, int satpos, const Operand& src, Condition cond = al);
954
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100955 // Bitfield manipulation instructions. v7 and above.
956
957 void ubfx(Register dst, Register src, int lsb, int width,
958 Condition cond = al);
959
960 void sbfx(Register dst, Register src, int lsb, int width,
961 Condition cond = al);
962
963 void bfc(Register dst, int lsb, int width, Condition cond = al);
964
965 void bfi(Register dst, Register src, int lsb, int width,
966 Condition cond = al);
967
Steve Blocka7e24c12009-10-30 11:49:00 +0000968 // Status register access instructions
969
970 void mrs(Register dst, SRegister s, Condition cond = al);
971 void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al);
972
973 // Load/Store instructions
974 void ldr(Register dst, const MemOperand& src, Condition cond = al);
975 void str(Register src, const MemOperand& dst, Condition cond = al);
976 void ldrb(Register dst, const MemOperand& src, Condition cond = al);
977 void strb(Register src, const MemOperand& dst, Condition cond = al);
978 void ldrh(Register dst, const MemOperand& src, Condition cond = al);
979 void strh(Register src, const MemOperand& dst, Condition cond = al);
980 void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
981 void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
Leon Clarkef7060e22010-06-03 12:02:55 +0100982 void ldrd(Register dst1,
983 Register dst2,
984 const MemOperand& src, Condition cond = al);
985 void strd(Register src1,
986 Register src2,
987 const MemOperand& dst, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000988
989 // Load/Store multiple instructions
990 void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
991 void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
992
Steve Blocka7e24c12009-10-30 11:49:00 +0000993 // Exception-generating instructions and debugging support
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800994 static const int kDefaultStopCode = -1;
995 void stop(const char* msg,
996 Condition cond = al,
997 int32_t code = kDefaultStopCode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000998
999 void bkpt(uint32_t imm16); // v5 and above
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001000 void svc(uint32_t imm24, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +00001001
1002 // Coprocessor instructions
1003
1004 void cdp(Coprocessor coproc, int opcode_1,
1005 CRegister crd, CRegister crn, CRegister crm,
1006 int opcode_2, Condition cond = al);
1007
1008 void cdp2(Coprocessor coproc, int opcode_1,
1009 CRegister crd, CRegister crn, CRegister crm,
1010 int opcode_2); // v5 and above
1011
1012 void mcr(Coprocessor coproc, int opcode_1,
1013 Register rd, CRegister crn, CRegister crm,
1014 int opcode_2 = 0, Condition cond = al);
1015
1016 void mcr2(Coprocessor coproc, int opcode_1,
1017 Register rd, CRegister crn, CRegister crm,
1018 int opcode_2 = 0); // v5 and above
1019
1020 void mrc(Coprocessor coproc, int opcode_1,
1021 Register rd, CRegister crn, CRegister crm,
1022 int opcode_2 = 0, Condition cond = al);
1023
1024 void mrc2(Coprocessor coproc, int opcode_1,
1025 Register rd, CRegister crn, CRegister crm,
1026 int opcode_2 = 0); // v5 and above
1027
1028 void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src,
1029 LFlag l = Short, Condition cond = al);
1030 void ldc(Coprocessor coproc, CRegister crd, Register base, int option,
1031 LFlag l = Short, Condition cond = al);
1032
1033 void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
1034 LFlag l = Short); // v5 and above
1035 void ldc2(Coprocessor coproc, CRegister crd, Register base, int option,
1036 LFlag l = Short); // v5 and above
1037
1038 void stc(Coprocessor coproc, CRegister crd, const MemOperand& dst,
1039 LFlag l = Short, Condition cond = al);
1040 void stc(Coprocessor coproc, CRegister crd, Register base, int option,
1041 LFlag l = Short, Condition cond = al);
1042
1043 void stc2(Coprocessor coproc, CRegister crd, const MemOperand& dst,
1044 LFlag l = Short); // v5 and above
1045 void stc2(Coprocessor coproc, CRegister crd, Register base, int option,
1046 LFlag l = Short); // v5 and above
1047
Steve Blockd0582a62009-12-15 09:54:21 +00001048 // Support for VFP.
1049 // All these APIs support S0 to S31 and D0 to D15.
1050 // Currently these APIs do not support extended D registers, i.e, D16 to D31.
1051 // However, some simple modifications can allow
1052 // these APIs to support D16 to D31.
1053
Leon Clarked91b9f72010-01-27 17:25:45 +00001054 void vldr(const DwVfpRegister dst,
1055 const Register base,
1056 int offset, // Offset must be a multiple of 4.
1057 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +01001058
1059 void vldr(const SwVfpRegister dst,
1060 const Register base,
1061 int offset, // Offset must be a multiple of 4.
1062 const Condition cond = al);
1063
Leon Clarked91b9f72010-01-27 17:25:45 +00001064 void vstr(const DwVfpRegister src,
1065 const Register base,
1066 int offset, // Offset must be a multiple of 4.
1067 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +01001068
Iain Merrick75681382010-08-19 15:07:18 +01001069 void vstr(const SwVfpRegister src,
1070 const Register base,
1071 int offset, // Offset must be a multiple of 4.
1072 const Condition cond = al);
1073
Steve Block8defd9f2010-07-08 12:39:36 +01001074 void vmov(const DwVfpRegister dst,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001075 double imm,
1076 const Condition cond = al);
1077 void vmov(const SwVfpRegister dst,
1078 const SwVfpRegister src,
1079 const Condition cond = al);
1080 void vmov(const DwVfpRegister dst,
Steve Block8defd9f2010-07-08 12:39:36 +01001081 const DwVfpRegister src,
1082 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001083 void vmov(const DwVfpRegister dst,
1084 const Register src1,
Steve Blockd0582a62009-12-15 09:54:21 +00001085 const Register src2,
Leon Clarkee46be812010-01-19 14:06:41 +00001086 const Condition cond = al);
1087 void vmov(const Register dst1,
1088 const Register dst2,
1089 const DwVfpRegister src,
1090 const Condition cond = al);
1091 void vmov(const SwVfpRegister dst,
1092 const Register src,
1093 const Condition cond = al);
1094 void vmov(const Register dst,
1095 const SwVfpRegister src,
1096 const Condition cond = al);
Russell Brenner90bac252010-11-18 13:33:46 -08001097 enum ConversionMode {
1098 FPSCRRounding = 0,
1099 RoundToZero = 1
1100 };
Steve Block6ded16b2010-05-10 14:33:55 +01001101 void vcvt_f64_s32(const DwVfpRegister dst,
1102 const SwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001103 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001104 const Condition cond = al);
1105 void vcvt_f32_s32(const SwVfpRegister dst,
1106 const SwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001107 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001108 const Condition cond = al);
1109 void vcvt_f64_u32(const DwVfpRegister dst,
1110 const SwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001111 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001112 const Condition cond = al);
1113 void vcvt_s32_f64(const SwVfpRegister dst,
1114 const DwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001115 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001116 const Condition cond = al);
1117 void vcvt_u32_f64(const SwVfpRegister dst,
1118 const DwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001119 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001120 const Condition cond = al);
1121 void vcvt_f64_f32(const DwVfpRegister dst,
1122 const SwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001123 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001124 const Condition cond = al);
1125 void vcvt_f32_f64(const SwVfpRegister dst,
1126 const DwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001127 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001128 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001129
1130 void vadd(const DwVfpRegister dst,
1131 const DwVfpRegister src1,
1132 const DwVfpRegister src2,
1133 const Condition cond = al);
1134 void vsub(const DwVfpRegister dst,
1135 const DwVfpRegister src1,
1136 const DwVfpRegister src2,
1137 const Condition cond = al);
1138 void vmul(const DwVfpRegister dst,
1139 const DwVfpRegister src1,
1140 const DwVfpRegister src2,
1141 const Condition cond = al);
1142 void vdiv(const DwVfpRegister dst,
1143 const DwVfpRegister src1,
1144 const DwVfpRegister src2,
1145 const Condition cond = al);
1146 void vcmp(const DwVfpRegister src1,
1147 const DwVfpRegister src2,
Steve Blockd0582a62009-12-15 09:54:21 +00001148 const SBit s = LeaveCC,
1149 const Condition cond = al);
Iain Merrick75681382010-08-19 15:07:18 +01001150 void vcmp(const DwVfpRegister src1,
1151 const double src2,
1152 const SBit s = LeaveCC,
1153 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001154 void vmrs(const Register dst,
1155 const Condition cond = al);
Russell Brenner90bac252010-11-18 13:33:46 -08001156 void vmsr(const Register dst,
1157 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +01001158 void vsqrt(const DwVfpRegister dst,
1159 const DwVfpRegister src,
1160 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001161
Steve Blocka7e24c12009-10-30 11:49:00 +00001162 // Pseudo instructions
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001163
1164 // Different nop operations are used by the code generator to detect certain
1165 // states of the generated code.
1166 enum NopMarkerTypes {
1167 NON_MARKING_NOP = 0,
1168 DEBUG_BREAK_NOP,
1169 // IC markers.
1170 PROPERTY_ACCESS_INLINED,
1171 PROPERTY_ACCESS_INLINED_CONTEXT,
1172 PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE,
1173 // Helper values.
1174 LAST_CODE_MARKER,
1175 FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED
1176 };
1177
1178 void nop(int type = 0); // 0 is the default non-marking type.
Steve Blocka7e24c12009-10-30 11:49:00 +00001179
1180 void push(Register src, Condition cond = al) {
1181 str(src, MemOperand(sp, 4, NegPreIndex), cond);
1182 }
1183
1184 void pop(Register dst, Condition cond = al) {
1185 ldr(dst, MemOperand(sp, 4, PostIndex), cond);
1186 }
1187
1188 void pop() {
1189 add(sp, sp, Operand(kPointerSize));
1190 }
1191
Steve Blocka7e24c12009-10-30 11:49:00 +00001192 // Jump unconditionally to given label.
1193 void jmp(Label* L) { b(L, al); }
1194
1195 // Check the code size generated from label to here.
1196 int InstructionsGeneratedSince(Label* l) {
1197 return (pc_offset() - l->pos()) / kInstrSize;
1198 }
1199
Steve Blockd0582a62009-12-15 09:54:21 +00001200 // Check whether an immediate fits an addressing mode 1 instruction.
1201 bool ImmediateFitsAddrMode1Instruction(int32_t imm32);
1202
Steve Block6ded16b2010-05-10 14:33:55 +01001203 // Class for scoping postponing the constant pool generation.
1204 class BlockConstPoolScope {
1205 public:
1206 explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) {
1207 assem_->StartBlockConstPool();
1208 }
1209 ~BlockConstPoolScope() {
1210 assem_->EndBlockConstPool();
1211 }
1212
1213 private:
1214 Assembler* assem_;
1215
1216 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstPoolScope);
1217 };
1218
Steve Blockd0582a62009-12-15 09:54:21 +00001219 // Postpone the generation of the constant pool for the specified number of
1220 // instructions.
1221 void BlockConstPoolFor(int instructions);
1222
Steve Blocka7e24c12009-10-30 11:49:00 +00001223 // Debugging
1224
1225 // Mark address of the ExitJSFrame code.
1226 void RecordJSReturn();
1227
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001228 // Mark address of a debug break slot.
1229 void RecordDebugBreakSlot();
1230
Steve Blocka7e24c12009-10-30 11:49:00 +00001231 // Record a comment relocation entry that can be used by a disassembler.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001232 // Use --code-comments to enable.
Steve Blocka7e24c12009-10-30 11:49:00 +00001233 void RecordComment(const char* msg);
1234
Ben Murdochb0fe1622011-05-05 13:52:32 +01001235 // Writes a single byte or word of data in the code stream. Used for
1236 // inline tables, e.g., jump-tables.
1237 void db(uint8_t data);
1238 void dd(uint32_t data);
1239
Steve Blocka7e24c12009-10-30 11:49:00 +00001240 int pc_offset() const { return pc_ - buffer_; }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001241
1242 PositionsRecorder* positions_recorder() { return &positions_recorder_; }
Steve Block6ded16b2010-05-10 14:33:55 +01001243
Leon Clarkef7060e22010-06-03 12:02:55 +01001244 bool can_peephole_optimize(int instructions) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001245 if (!allow_peephole_optimization_) return false;
Leon Clarkef7060e22010-06-03 12:02:55 +01001246 if (last_bound_pos_ > pc_offset() - instructions * kInstrSize) return false;
1247 return reloc_info_writer.last_pc() <= pc_ - instructions * kInstrSize;
1248 }
1249
Steve Block6ded16b2010-05-10 14:33:55 +01001250 // Read/patch instructions
1251 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
1252 static void instr_at_put(byte* pc, Instr instr) {
1253 *reinterpret_cast<Instr*>(pc) = instr;
1254 }
Steve Block6ded16b2010-05-10 14:33:55 +01001255 static bool IsBranch(Instr instr);
1256 static int GetBranchOffset(Instr instr);
1257 static bool IsLdrRegisterImmediate(Instr instr);
1258 static int GetLdrRegisterImmediateOffset(Instr instr);
1259 static Instr SetLdrRegisterImmediateOffset(Instr instr, int offset);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001260 static bool IsStrRegisterImmediate(Instr instr);
1261 static Instr SetStrRegisterImmediateOffset(Instr instr, int offset);
1262 static bool IsAddRegisterImmediate(Instr instr);
1263 static Instr SetAddRegisterImmediateOffset(Instr instr, int offset);
Leon Clarkef7060e22010-06-03 12:02:55 +01001264 static Register GetRd(Instr instr);
1265 static bool IsPush(Instr instr);
1266 static bool IsPop(Instr instr);
1267 static bool IsStrRegFpOffset(Instr instr);
1268 static bool IsLdrRegFpOffset(Instr instr);
1269 static bool IsStrRegFpNegOffset(Instr instr);
1270 static bool IsLdrRegFpNegOffset(Instr instr);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001271 static bool IsLdrPcImmediateOffset(Instr instr);
1272 static bool IsNop(Instr instr, int type = NON_MARKING_NOP);
Steve Block6ded16b2010-05-10 14:33:55 +01001273
Ben Murdochb0fe1622011-05-05 13:52:32 +01001274 // Check if is time to emit a constant pool for pending reloc info entries
1275 void CheckConstPool(bool force_emit, bool require_jump);
Steve Blocka7e24c12009-10-30 11:49:00 +00001276
1277 protected:
1278 int buffer_space() const { return reloc_info_writer.pos() - pc_; }
1279
1280 // Read/patch instructions
Steve Blocka7e24c12009-10-30 11:49:00 +00001281 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
1282 void instr_at_put(int pos, Instr instr) {
1283 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
1284 }
1285
1286 // Decode branch instruction at pos and return branch target pos
1287 int target_at(int pos);
1288
1289 // Patch branch instruction at pos to branch to given branch target pos
1290 void target_at_put(int pos, int target_pos);
1291
Steve Blocka7e24c12009-10-30 11:49:00 +00001292 // Block the emission of the constant pool before pc_offset
1293 void BlockConstPoolBefore(int pc_offset) {
1294 if (no_const_pool_before_ < pc_offset) no_const_pool_before_ = pc_offset;
1295 }
1296
Steve Block6ded16b2010-05-10 14:33:55 +01001297 void StartBlockConstPool() {
1298 const_pool_blocked_nesting_++;
1299 }
1300 void EndBlockConstPool() {
1301 const_pool_blocked_nesting_--;
1302 }
Steve Block8defd9f2010-07-08 12:39:36 +01001303 bool is_const_pool_blocked() const { return const_pool_blocked_nesting_ > 0; }
Steve Block6ded16b2010-05-10 14:33:55 +01001304
Steve Blocka7e24c12009-10-30 11:49:00 +00001305 private:
1306 // Code buffer:
1307 // The buffer into which code and relocation info are generated.
1308 byte* buffer_;
1309 int buffer_size_;
1310 // True if the assembler owns the buffer, false if buffer is external.
1311 bool own_buffer_;
1312
1313 // Buffer size and constant pool distance are checked together at regular
1314 // intervals of kBufferCheckInterval emitted bytes
1315 static const int kBufferCheckInterval = 1*KB/2;
1316 int next_buffer_check_; // pc offset of next buffer check
1317
1318 // Code generation
1319 // The relocation writer's position is at least kGap bytes below the end of
1320 // the generated instructions. This is so that multi-instruction sequences do
1321 // not have to check for overflow. The same is true for writes of large
1322 // relocation info entries.
1323 static const int kGap = 32;
1324 byte* pc_; // the program counter; moves forward
1325
1326 // Constant pool generation
1327 // Pools are emitted in the instruction stream, preferably after unconditional
1328 // jumps or after returns from functions (in dead code locations).
1329 // If a long code sequence does not contain unconditional jumps, it is
1330 // necessary to emit the constant pool before the pool gets too far from the
1331 // location it is accessed from. In this case, we emit a jump over the emitted
1332 // constant pool.
1333 // Constants in the pool may be addresses of functions that gets relocated;
1334 // if so, a relocation info entry is associated to the constant pool entry.
1335
1336 // Repeated checking whether the constant pool should be emitted is rather
1337 // expensive. By default we only check again once a number of instructions
1338 // has been generated. That also means that the sizing of the buffers is not
1339 // an exact science, and that we rely on some slop to not overrun buffers.
1340 static const int kCheckConstIntervalInst = 32;
1341 static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize;
1342
1343
1344 // Pools are emitted after function return and in dead code at (more or less)
1345 // regular intervals of kDistBetweenPools bytes
1346 static const int kDistBetweenPools = 1*KB;
1347
1348 // Constants in pools are accessed via pc relative addressing, which can
1349 // reach +/-4KB thereby defining a maximum distance between the instruction
1350 // and the accessed constant. We satisfy this constraint by limiting the
1351 // distance between pools.
1352 static const int kMaxDistBetweenPools = 4*KB - 2*kBufferCheckInterval;
1353
Steve Block6ded16b2010-05-10 14:33:55 +01001354 // Emission of the constant pool may be blocked in some code sequences.
1355 int const_pool_blocked_nesting_; // Block emission if this is not zero.
1356 int no_const_pool_before_; // Block emission before this pc offset.
Steve Blocka7e24c12009-10-30 11:49:00 +00001357
1358 // Keep track of the last emitted pool to guarantee a maximal distance
1359 int last_const_pool_end_; // pc offset following the last constant pool
1360
1361 // Relocation info generation
1362 // Each relocation is encoded as a variable size value
1363 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1364 RelocInfoWriter reloc_info_writer;
1365 // Relocation info records are also used during code generation as temporary
1366 // containers for constants and code target addresses until they are emitted
1367 // to the constant pool. These pending relocation info records are temporarily
1368 // stored in a separate buffer until a constant pool is emitted.
1369 // If every instruction in a long sequence is accessing the pool, we need one
1370 // pending relocation entry per instruction.
1371 static const int kMaxNumPRInfo = kMaxDistBetweenPools/kInstrSize;
1372 RelocInfo prinfo_[kMaxNumPRInfo]; // the buffer of pending relocation info
1373 int num_prinfo_; // number of pending reloc info entries in the buffer
1374
1375 // The bound position, before this we cannot do instruction elimination.
1376 int last_bound_pos_;
1377
Steve Blocka7e24c12009-10-30 11:49:00 +00001378 // Code emission
1379 inline void CheckBuffer();
1380 void GrowBuffer();
1381 inline void emit(Instr x);
1382
1383 // Instruction generation
1384 void addrmod1(Instr instr, Register rn, Register rd, const Operand& x);
1385 void addrmod2(Instr instr, Register rd, const MemOperand& x);
1386 void addrmod3(Instr instr, Register rd, const MemOperand& x);
1387 void addrmod4(Instr instr, Register rn, RegList rl);
1388 void addrmod5(Instr instr, CRegister crd, const MemOperand& x);
1389
1390 // Labels
1391 void print(Label* L);
1392 void bind_to(Label* L, int pos);
1393 void link_to(Label* L, Label* appendix);
1394 void next(Label* L);
1395
1396 // Record reloc info for current pc_
1397 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
1398
1399 friend class RegExpMacroAssemblerARM;
1400 friend class RelocInfo;
1401 friend class CodePatcher;
Steve Block6ded16b2010-05-10 14:33:55 +01001402 friend class BlockConstPoolScope;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001403
1404 PositionsRecorder positions_recorder_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001405 bool allow_peephole_optimization_;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001406 friend class PositionsRecorder;
1407 friend class EnsureSpace;
Steve Blocka7e24c12009-10-30 11:49:00 +00001408};
1409
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001410
1411class EnsureSpace BASE_EMBEDDED {
1412 public:
1413 explicit EnsureSpace(Assembler* assembler) {
1414 assembler->CheckBuffer();
1415 }
1416};
1417
1418
Steve Blocka7e24c12009-10-30 11:49:00 +00001419} } // namespace v8::internal
1420
1421#endif // V8_ARM_ASSEMBLER_ARM_H_