blob: ee4c9aa52bc01925e6c91a41c2100c8cab14d1a7 [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 {
Kristian Monsen0d5e1162010-09-30 15:31:59 +010072 bool is_valid() const { return 0 <= code_ && code_ < 16; }
73 bool is(Register reg) const { return code_ == reg.code_; }
74 int code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +000075 ASSERT(is_valid());
76 return code_;
77 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +010078 int bit() const {
Steve Blocka7e24c12009-10-30 11:49:00 +000079 ASSERT(is_valid());
80 return 1 << code_;
81 }
82
Leon Clarkef7060e22010-06-03 12:02:55 +010083 void set_code(int code) {
84 code_ = code;
85 ASSERT(is_valid());
86 }
87
Andrei Popescu31002712010-02-23 13:46:05 +000088 // Unfortunately we can't make this private in a struct.
Steve Blocka7e24c12009-10-30 11:49:00 +000089 int code_;
90};
91
Steve Block6ded16b2010-05-10 14:33:55 +010092const Register no_reg = { -1 };
Steve Blocka7e24c12009-10-30 11:49:00 +000093
Steve Block6ded16b2010-05-10 14:33:55 +010094const Register r0 = { 0 };
95const Register r1 = { 1 };
96const Register r2 = { 2 };
97const Register r3 = { 3 };
98const Register r4 = { 4 };
99const Register r5 = { 5 };
100const Register r6 = { 6 };
101const Register r7 = { 7 };
102const Register r8 = { 8 }; // Used as context register.
103const Register r9 = { 9 };
104const Register r10 = { 10 }; // Used as roots register.
105const Register fp = { 11 };
106const Register ip = { 12 };
107const Register sp = { 13 };
108const Register lr = { 14 };
109const Register pc = { 15 };
Steve Blockd0582a62009-12-15 09:54:21 +0000110
Leon Clarkee46be812010-01-19 14:06:41 +0000111// Single word VFP register.
112struct SwVfpRegister {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100113 bool is_valid() const { return 0 <= code_ && code_ < 32; }
114 bool is(SwVfpRegister reg) const { return code_ == reg.code_; }
115 int code() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000116 ASSERT(is_valid());
117 return code_;
118 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100119 int bit() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000120 ASSERT(is_valid());
121 return 1 << code_;
122 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100123 void split_code(int* vm, int* m) const {
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100124 ASSERT(is_valid());
125 *m = code_ & 0x1;
126 *vm = code_ >> 1;
127 }
Leon Clarkee46be812010-01-19 14:06:41 +0000128
129 int code_;
130};
131
132
133// Double word VFP register.
134struct DwVfpRegister {
135 // Supporting d0 to d15, can be later extended to d31.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100136 bool is_valid() const { return 0 <= code_ && code_ < 16; }
137 bool is(DwVfpRegister reg) const { return code_ == reg.code_; }
138 SwVfpRegister low() const {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100139 SwVfpRegister reg;
140 reg.code_ = code_ * 2;
141
142 ASSERT(reg.is_valid());
143 return reg;
144 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100145 SwVfpRegister high() const {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100146 SwVfpRegister reg;
147 reg.code_ = (code_ * 2) + 1;
148
149 ASSERT(reg.is_valid());
150 return reg;
151 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100152 int code() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000153 ASSERT(is_valid());
154 return code_;
155 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100156 int bit() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000157 ASSERT(is_valid());
158 return 1 << code_;
159 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100160 void split_code(int* vm, int* m) const {
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100161 ASSERT(is_valid());
162 *m = (code_ & 0x10) >> 4;
163 *vm = code_ & 0x0F;
164 }
Leon Clarkee46be812010-01-19 14:06:41 +0000165
166 int code_;
167};
168
169
Steve Block6ded16b2010-05-10 14:33:55 +0100170// Support for the VFP registers s0 to s31 (d0 to d15).
Leon Clarkee46be812010-01-19 14:06:41 +0000171// Note that "s(N):s(N+1)" is the same as "d(N/2)".
Steve Block6ded16b2010-05-10 14:33:55 +0100172const SwVfpRegister s0 = { 0 };
173const SwVfpRegister s1 = { 1 };
174const SwVfpRegister s2 = { 2 };
175const SwVfpRegister s3 = { 3 };
176const SwVfpRegister s4 = { 4 };
177const SwVfpRegister s5 = { 5 };
178const SwVfpRegister s6 = { 6 };
179const SwVfpRegister s7 = { 7 };
180const SwVfpRegister s8 = { 8 };
181const SwVfpRegister s9 = { 9 };
182const SwVfpRegister s10 = { 10 };
183const SwVfpRegister s11 = { 11 };
184const SwVfpRegister s12 = { 12 };
185const SwVfpRegister s13 = { 13 };
186const SwVfpRegister s14 = { 14 };
187const SwVfpRegister s15 = { 15 };
188const SwVfpRegister s16 = { 16 };
189const SwVfpRegister s17 = { 17 };
190const SwVfpRegister s18 = { 18 };
191const SwVfpRegister s19 = { 19 };
192const SwVfpRegister s20 = { 20 };
193const SwVfpRegister s21 = { 21 };
194const SwVfpRegister s22 = { 22 };
195const SwVfpRegister s23 = { 23 };
196const SwVfpRegister s24 = { 24 };
197const SwVfpRegister s25 = { 25 };
198const SwVfpRegister s26 = { 26 };
199const SwVfpRegister s27 = { 27 };
200const SwVfpRegister s28 = { 28 };
201const SwVfpRegister s29 = { 29 };
202const SwVfpRegister s30 = { 30 };
203const SwVfpRegister s31 = { 31 };
Leon Clarkee46be812010-01-19 14:06:41 +0000204
Steve Block6ded16b2010-05-10 14:33:55 +0100205const DwVfpRegister d0 = { 0 };
206const DwVfpRegister d1 = { 1 };
207const DwVfpRegister d2 = { 2 };
208const DwVfpRegister d3 = { 3 };
209const DwVfpRegister d4 = { 4 };
210const DwVfpRegister d5 = { 5 };
211const DwVfpRegister d6 = { 6 };
212const DwVfpRegister d7 = { 7 };
213const DwVfpRegister d8 = { 8 };
214const DwVfpRegister d9 = { 9 };
215const DwVfpRegister d10 = { 10 };
216const DwVfpRegister d11 = { 11 };
217const DwVfpRegister d12 = { 12 };
218const DwVfpRegister d13 = { 13 };
219const DwVfpRegister d14 = { 14 };
220const DwVfpRegister d15 = { 15 };
Leon Clarkee46be812010-01-19 14:06:41 +0000221
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800222// VFP FPSCR constants.
223static const uint32_t kVFPExceptionMask = 0xf;
224static const uint32_t kVFPRoundingModeMask = 3 << 22;
225static const uint32_t kVFPFlushToZeroMask = 1 << 24;
226static const uint32_t kVFPRoundToMinusInfinityBits = 2 << 22;
Steve Blocka7e24c12009-10-30 11:49:00 +0000227
228// Coprocessor register
229struct CRegister {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100230 bool is_valid() const { return 0 <= code_ && code_ < 16; }
231 bool is(CRegister creg) const { return code_ == creg.code_; }
232 int code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000233 ASSERT(is_valid());
234 return code_;
235 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100236 int bit() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000237 ASSERT(is_valid());
238 return 1 << code_;
239 }
240
Andrei Popescu31002712010-02-23 13:46:05 +0000241 // Unfortunately we can't make this private in a struct.
Steve Blocka7e24c12009-10-30 11:49:00 +0000242 int code_;
243};
244
245
Steve Block6ded16b2010-05-10 14:33:55 +0100246const CRegister no_creg = { -1 };
247
248const CRegister cr0 = { 0 };
249const CRegister cr1 = { 1 };
250const CRegister cr2 = { 2 };
251const CRegister cr3 = { 3 };
252const CRegister cr4 = { 4 };
253const CRegister cr5 = { 5 };
254const CRegister cr6 = { 6 };
255const CRegister cr7 = { 7 };
256const CRegister cr8 = { 8 };
257const CRegister cr9 = { 9 };
258const CRegister cr10 = { 10 };
259const CRegister cr11 = { 11 };
260const CRegister cr12 = { 12 };
261const CRegister cr13 = { 13 };
262const CRegister cr14 = { 14 };
263const CRegister cr15 = { 15 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000264
265
266// Coprocessor number
267enum Coprocessor {
268 p0 = 0,
269 p1 = 1,
270 p2 = 2,
271 p3 = 3,
272 p4 = 4,
273 p5 = 5,
274 p6 = 6,
275 p7 = 7,
276 p8 = 8,
277 p9 = 9,
278 p10 = 10,
279 p11 = 11,
280 p12 = 12,
281 p13 = 13,
282 p14 = 14,
283 p15 = 15
284};
285
286
Andrei Popescu31002712010-02-23 13:46:05 +0000287// Condition field in instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +0000288enum Condition {
289 eq = 0 << 28, // Z set equal.
290 ne = 1 << 28, // Z clear not equal.
291 nz = 1 << 28, // Z clear not zero.
292 cs = 2 << 28, // C set carry set.
293 hs = 2 << 28, // C set unsigned higher or same.
294 cc = 3 << 28, // C clear carry clear.
295 lo = 3 << 28, // C clear unsigned lower.
296 mi = 4 << 28, // N set negative.
297 pl = 5 << 28, // N clear positive or zero.
298 vs = 6 << 28, // V set overflow.
299 vc = 7 << 28, // V clear no overflow.
300 hi = 8 << 28, // C set, Z clear unsigned higher.
301 ls = 9 << 28, // C clear or Z set unsigned lower or same.
302 ge = 10 << 28, // N == V greater or equal.
303 lt = 11 << 28, // N != V less than.
304 gt = 12 << 28, // Z clear, N == V greater than.
305 le = 13 << 28, // Z set or N != V less then or equal
306 al = 14 << 28 // always.
307};
308
309
310// Returns the equivalent of !cc.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100311inline Condition NegateCondition(Condition cc) {
312 ASSERT(cc != al);
313 return static_cast<Condition>(cc ^ ne);
314}
Steve Blocka7e24c12009-10-30 11:49:00 +0000315
316
317// Corresponds to transposing the operands of a comparison.
318inline Condition ReverseCondition(Condition cc) {
319 switch (cc) {
320 case lo:
321 return hi;
322 case hi:
323 return lo;
324 case hs:
325 return ls;
326 case ls:
327 return hs;
328 case lt:
329 return gt;
330 case gt:
331 return lt;
332 case ge:
333 return le;
334 case le:
335 return ge;
336 default:
337 return cc;
338 };
339}
340
341
342// Branch hints are not used on the ARM. They are defined so that they can
343// appear in shared function signatures, but will be ignored in ARM
344// implementations.
345enum Hint { no_hint };
346
347// Hints are not used on the arm. Negating is trivial.
348inline Hint NegateHint(Hint ignored) { return no_hint; }
349
350
351// -----------------------------------------------------------------------------
352// Addressing modes and instruction variants
353
354// Shifter operand shift operation
355enum ShiftOp {
356 LSL = 0 << 5,
357 LSR = 1 << 5,
358 ASR = 2 << 5,
359 ROR = 3 << 5,
360 RRX = -1
361};
362
363
364// Condition code updating mode
365enum SBit {
366 SetCC = 1 << 20, // set condition code
367 LeaveCC = 0 << 20 // leave condition code unchanged
368};
369
370
371// Status register selection
372enum SRegister {
373 CPSR = 0 << 22,
374 SPSR = 1 << 22
375};
376
377
378// Status register fields
379enum SRegisterField {
380 CPSR_c = CPSR | 1 << 16,
381 CPSR_x = CPSR | 1 << 17,
382 CPSR_s = CPSR | 1 << 18,
383 CPSR_f = CPSR | 1 << 19,
384 SPSR_c = SPSR | 1 << 16,
385 SPSR_x = SPSR | 1 << 17,
386 SPSR_s = SPSR | 1 << 18,
387 SPSR_f = SPSR | 1 << 19
388};
389
390// Status register field mask (or'ed SRegisterField enum values)
391typedef uint32_t SRegisterFieldMask;
392
393
394// Memory operand addressing mode
395enum AddrMode {
396 // bit encoding P U W
397 Offset = (8|4|0) << 21, // offset (without writeback to base)
398 PreIndex = (8|4|1) << 21, // pre-indexed addressing with writeback
399 PostIndex = (0|4|0) << 21, // post-indexed addressing with writeback
400 NegOffset = (8|0|0) << 21, // negative offset (without writeback to base)
401 NegPreIndex = (8|0|1) << 21, // negative pre-indexed with writeback
402 NegPostIndex = (0|0|0) << 21 // negative post-indexed with writeback
403};
404
405
406// Load/store multiple addressing mode
407enum BlockAddrMode {
408 // bit encoding P U W
409 da = (0|0|0) << 21, // decrement after
410 ia = (0|4|0) << 21, // increment after
411 db = (8|0|0) << 21, // decrement before
412 ib = (8|4|0) << 21, // increment before
413 da_w = (0|0|1) << 21, // decrement after with writeback to base
414 ia_w = (0|4|1) << 21, // increment after with writeback to base
415 db_w = (8|0|1) << 21, // decrement before with writeback to base
416 ib_w = (8|4|1) << 21 // increment before with writeback to base
417};
418
419
420// Coprocessor load/store operand size
421enum LFlag {
422 Long = 1 << 22, // long load/store coprocessor
423 Short = 0 << 22 // short load/store coprocessor
424};
425
426
427// -----------------------------------------------------------------------------
428// Machine instruction Operands
429
430// Class Operand represents a shifter operand in data processing instructions
431class Operand BASE_EMBEDDED {
432 public:
433 // immediate
434 INLINE(explicit Operand(int32_t immediate,
435 RelocInfo::Mode rmode = RelocInfo::NONE));
436 INLINE(explicit Operand(const ExternalReference& f));
437 INLINE(explicit Operand(const char* s));
Steve Blocka7e24c12009-10-30 11:49:00 +0000438 explicit Operand(Handle<Object> handle);
439 INLINE(explicit Operand(Smi* value));
440
441 // rm
442 INLINE(explicit Operand(Register rm));
443
444 // rm <shift_op> shift_imm
445 explicit Operand(Register rm, ShiftOp shift_op, int shift_imm);
446
447 // rm <shift_op> rs
448 explicit Operand(Register rm, ShiftOp shift_op, Register rs);
449
450 // Return true if this is a register operand.
451 INLINE(bool is_reg() const);
452
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100453 // Return true of this operand fits in one instruction so that no
454 // 2-instruction solution with a load into the ip register is necessary.
455 bool is_single_instruction() const;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800456 bool must_use_constant_pool() const;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100457
458 inline int32_t immediate() const {
459 ASSERT(!rm_.is_valid());
460 return imm32_;
461 }
462
Steve Blocka7e24c12009-10-30 11:49:00 +0000463 Register rm() const { return rm_; }
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100464 Register rs() const { return rs_; }
465 ShiftOp shift_op() const { return shift_op_; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000466
467 private:
468 Register rm_;
469 Register rs_;
470 ShiftOp shift_op_;
471 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
472 int32_t imm32_; // valid if rm_ == no_reg
473 RelocInfo::Mode rmode_;
474
475 friend class Assembler;
476};
477
478
479// Class MemOperand represents a memory operand in load and store instructions
480class MemOperand BASE_EMBEDDED {
481 public:
482 // [rn +/- offset] Offset/NegOffset
483 // [rn +/- offset]! PreIndex/NegPreIndex
484 // [rn], +/- offset PostIndex/NegPostIndex
485 // offset is any signed 32-bit value; offset is first loaded to register ip if
486 // it does not fit the addressing mode (12-bit unsigned and sign bit)
487 explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset);
488
489 // [rn +/- rm] Offset/NegOffset
490 // [rn +/- rm]! PreIndex/NegPreIndex
491 // [rn], +/- rm PostIndex/NegPostIndex
492 explicit MemOperand(Register rn, Register rm, AddrMode am = Offset);
493
494 // [rn +/- rm <shift_op> shift_imm] Offset/NegOffset
495 // [rn +/- rm <shift_op> shift_imm]! PreIndex/NegPreIndex
496 // [rn], +/- rm <shift_op> shift_imm PostIndex/NegPostIndex
497 explicit MemOperand(Register rn, Register rm,
498 ShiftOp shift_op, int shift_imm, AddrMode am = Offset);
499
Kristian Monsen25f61362010-05-21 11:50:48 +0100500 void set_offset(int32_t offset) {
501 ASSERT(rm_.is(no_reg));
502 offset_ = offset;
503 }
504
505 uint32_t offset() {
506 ASSERT(rm_.is(no_reg));
507 return offset_;
508 }
509
Leon Clarkef7060e22010-06-03 12:02:55 +0100510 Register rn() const { return rn_; }
511 Register rm() const { return rm_; }
Kristian Monsen25f61362010-05-21 11:50:48 +0100512
Steve Blocka7e24c12009-10-30 11:49:00 +0000513 private:
514 Register rn_; // base
515 Register rm_; // register offset
516 int32_t offset_; // valid if rm_ == no_reg
517 ShiftOp shift_op_;
518 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
519 AddrMode am_; // bits P, U, and W
520
521 friend class Assembler;
522};
523
Steve Blockd0582a62009-12-15 09:54:21 +0000524// CpuFeatures keeps track of which features are supported by the target CPU.
525// Supported features must be enabled by a Scope before use.
526class CpuFeatures : public AllStatic {
527 public:
528 // Detect features of the target CPU. Set safe defaults if the serializer
529 // is enabled (snapshots must be portable).
530 static void Probe();
531
532 // Check whether a feature is supported by the target CPU.
533 static bool IsSupported(CpuFeature f) {
534 if (f == VFP3 && !FLAG_enable_vfp3) return false;
535 return (supported_ & (1u << f)) != 0;
536 }
537
538 // Check whether a feature is currently enabled.
539 static bool IsEnabled(CpuFeature f) {
540 return (enabled_ & (1u << f)) != 0;
541 }
542
543 // Enable a specified feature within a scope.
544 class Scope BASE_EMBEDDED {
545#ifdef DEBUG
546 public:
547 explicit Scope(CpuFeature f) {
548 ASSERT(CpuFeatures::IsSupported(f));
549 ASSERT(!Serializer::enabled() ||
550 (found_by_runtime_probing_ & (1u << f)) == 0);
551 old_enabled_ = CpuFeatures::enabled_;
552 CpuFeatures::enabled_ |= 1u << f;
553 }
554 ~Scope() { CpuFeatures::enabled_ = old_enabled_; }
555 private:
556 unsigned old_enabled_;
557#else
558 public:
559 explicit Scope(CpuFeature f) {}
560#endif
561 };
562
563 private:
564 static unsigned supported_;
565 static unsigned enabled_;
566 static unsigned found_by_runtime_probing_;
567};
568
Steve Blocka7e24c12009-10-30 11:49:00 +0000569
570typedef int32_t Instr;
571
572
573extern const Instr kMovLrPc;
Steve Block6ded16b2010-05-10 14:33:55 +0100574extern const Instr kLdrPCMask;
Steve Blocka7e24c12009-10-30 11:49:00 +0000575extern const Instr kLdrPCPattern;
Steve Block6ded16b2010-05-10 14:33:55 +0100576extern const Instr kBlxRegMask;
577extern const Instr kBlxRegPattern;
Steve Blocka7e24c12009-10-30 11:49:00 +0000578
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100579extern const Instr kMovMvnMask;
580extern const Instr kMovMvnPattern;
581extern const Instr kMovMvnFlip;
582
583extern const Instr kMovLeaveCCMask;
584extern const Instr kMovLeaveCCPattern;
585extern const Instr kMovwMask;
586extern const Instr kMovwPattern;
587extern const Instr kMovwLeaveCCFlip;
588
589extern const Instr kCmpCmnMask;
590extern const Instr kCmpCmnPattern;
591extern const Instr kCmpCmnFlip;
592
593extern const Instr kALUMask;
594extern const Instr kAddPattern;
595extern const Instr kSubPattern;
596extern const Instr kAndPattern;
597extern const Instr kBicPattern;
598extern const Instr kAddSubFlip;
599extern const Instr kAndBicFlip;
Steve Blocka7e24c12009-10-30 11:49:00 +0000600
601class Assembler : public Malloced {
602 public:
603 // Create an assembler. Instructions and relocation information are emitted
604 // into a buffer, with the instructions starting from the beginning and the
605 // relocation information starting from the end of the buffer. See CodeDesc
606 // for a detailed comment on the layout (globals.h).
607 //
608 // If the provided buffer is NULL, the assembler allocates and grows its own
609 // buffer, and buffer_size determines the initial buffer size. The buffer is
610 // owned by the assembler and deallocated upon destruction of the assembler.
611 //
612 // If the provided buffer is not NULL, the assembler uses the provided buffer
613 // for code generation and assumes its size to be buffer_size. If the buffer
614 // is too small, a fatal error occurs. No deallocation of the buffer is done
615 // upon destruction of the assembler.
616 Assembler(void* buffer, int buffer_size);
617 ~Assembler();
618
619 // GetCode emits any pending (non-emitted) code and fills the descriptor
620 // desc. GetCode() is idempotent; it returns the same result if no other
621 // Assembler functions are invoked in between GetCode() calls.
622 void GetCode(CodeDesc* desc);
623
624 // Label operations & relative jumps (PPUM Appendix D)
625 //
626 // Takes a branch opcode (cc) and a label (L) and generates
627 // either a backward branch or a forward branch and links it
628 // to the label fixup chain. Usage:
629 //
630 // Label L; // unbound label
631 // j(cc, &L); // forward branch to unbound label
632 // bind(&L); // bind label to the current pc
633 // j(cc, &L); // backward branch to bound label
634 // bind(&L); // illegal: a label may be bound only once
635 //
636 // Note: The same Label can be used for forward and backward branches
637 // but it may be bound only once.
638
639 void bind(Label* L); // binds an unbound label L to the current code position
640
641 // Returns the branch offset to the given label from the current code position
642 // Links the label to the current position if it is still unbound
643 // Manages the jump elimination optimization if the second parameter is true.
644 int branch_offset(Label* L, bool jump_elimination_allowed);
645
646 // Puts a labels target address at the given position.
647 // The high 8 bits are set to zero.
648 void label_at_put(Label* L, int at_offset);
649
650 // Return the address in the constant pool of the code target address used by
651 // the branch/call instruction at pc.
652 INLINE(static Address target_address_address_at(Address pc));
653
654 // Read/Modify the code target address in the branch/call instruction at pc.
655 INLINE(static Address target_address_at(Address pc));
656 INLINE(static void set_target_address_at(Address pc, Address target));
657
Steve Blockd0582a62009-12-15 09:54:21 +0000658 // This sets the branch destination (which is in the constant pool on ARM).
659 // This is for calls and branches within generated code.
660 inline static void set_target_at(Address constant_pool_entry, Address target);
661
662 // This sets the branch destination (which is in the constant pool on ARM).
663 // This is for calls and branches to runtime code.
664 inline static void set_external_target_at(Address constant_pool_entry,
665 Address target) {
666 set_target_at(constant_pool_entry, target);
667 }
668
669 // Here we are patching the address in the constant pool, not the actual call
670 // instruction. The address in the constant pool is the same size as a
671 // pointer.
672 static const int kCallTargetSize = kPointerSize;
673 static const int kExternalTargetSize = kPointerSize;
674
Steve Blocka7e24c12009-10-30 11:49:00 +0000675 // Size of an instruction.
676 static const int kInstrSize = sizeof(Instr);
677
678 // Distance between the instruction referring to the address of the call
Steve Block6ded16b2010-05-10 14:33:55 +0100679 // target and the return address.
680#ifdef USE_BLX
681 // Call sequence is:
682 // ldr ip, [pc, #...] @ call address
683 // blx ip
684 // @ return address
685 static const int kCallTargetAddressOffset = 2 * kInstrSize;
686#else
687 // Call sequence is:
688 // mov lr, pc
689 // ldr pc, [pc, #...] @ call address
690 // @ return address
Steve Blocka7e24c12009-10-30 11:49:00 +0000691 static const int kCallTargetAddressOffset = kInstrSize;
Steve Block6ded16b2010-05-10 14:33:55 +0100692#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000693
694 // Distance between start of patched return sequence and the emitted address
695 // to jump to.
Steve Block6ded16b2010-05-10 14:33:55 +0100696#ifdef USE_BLX
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100697 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100698 // ldr ip, [pc, #0] @ emited address and start
699 // blx ip
700 static const int kPatchReturnSequenceAddressOffset = 0 * kInstrSize;
701#else
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100702 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100703 // mov lr, pc @ start of sequence
704 // ldr pc, [pc, #-4] @ emited address
705 static const int kPatchReturnSequenceAddressOffset = kInstrSize;
706#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000707
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100708 // Distance between start of patched debug break slot and the emitted address
709 // to jump to.
710#ifdef USE_BLX
711 // Patched debug break slot code is:
712 // ldr ip, [pc, #0] @ emited address and start
713 // blx ip
714 static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
715#else
716 // Patched debug break slot code is:
717 // mov lr, pc @ start of sequence
718 // ldr pc, [pc, #-4] @ emited address
719 static const int kPatchDebugBreakSlotAddressOffset = kInstrSize;
720#endif
721
Steve Blocka7e24c12009-10-30 11:49:00 +0000722 // Difference between address of current opcode and value read from pc
723 // register.
724 static const int kPcLoadDelta = 8;
725
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100726 static const int kJSReturnSequenceInstructions = 4;
727 static const int kDebugBreakSlotInstructions = 3;
728 static const int kDebugBreakSlotLength =
729 kDebugBreakSlotInstructions * kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +0000730
731 // ---------------------------------------------------------------------------
732 // Code generation
733
734 // Insert the smallest number of nop instructions
735 // possible to align the pc offset to a multiple
736 // of m. m must be a power of 2 (>= 4).
737 void Align(int m);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100738 // Aligns code to something that's optimal for a jump target for the platform.
739 void CodeTargetAlign();
Steve Blocka7e24c12009-10-30 11:49:00 +0000740
741 // Branch instructions
742 void b(int branch_offset, Condition cond = al);
743 void bl(int branch_offset, Condition cond = al);
744 void blx(int branch_offset); // v5 and above
745 void blx(Register target, Condition cond = al); // v5 and above
746 void bx(Register target, Condition cond = al); // v5 and above, plus v4t
747
748 // Convenience branch instructions using labels
749 void b(Label* L, Condition cond = al) {
750 b(branch_offset(L, cond == al), cond);
751 }
752 void b(Condition cond, Label* L) { b(branch_offset(L, cond == al), cond); }
753 void bl(Label* L, Condition cond = al) { bl(branch_offset(L, false), cond); }
754 void bl(Condition cond, Label* L) { bl(branch_offset(L, false), cond); }
755 void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above
756
757 // Data-processing instructions
Andrei Popescu31002712010-02-23 13:46:05 +0000758
Steve Blocka7e24c12009-10-30 11:49:00 +0000759 void and_(Register dst, Register src1, const Operand& src2,
760 SBit s = LeaveCC, Condition cond = al);
761
762 void eor(Register dst, Register src1, const Operand& src2,
763 SBit s = LeaveCC, Condition cond = al);
764
765 void sub(Register dst, Register src1, const Operand& src2,
766 SBit s = LeaveCC, Condition cond = al);
767 void sub(Register dst, Register src1, Register src2,
768 SBit s = LeaveCC, Condition cond = al) {
769 sub(dst, src1, Operand(src2), s, cond);
770 }
771
772 void rsb(Register dst, Register src1, const Operand& src2,
773 SBit s = LeaveCC, Condition cond = al);
774
775 void add(Register dst, Register src1, const Operand& src2,
776 SBit s = LeaveCC, Condition cond = al);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100777 void add(Register dst, Register src1, Register src2,
778 SBit s = LeaveCC, Condition cond = al) {
779 add(dst, src1, Operand(src2), s, cond);
780 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000781
782 void adc(Register dst, Register src1, const Operand& src2,
783 SBit s = LeaveCC, Condition cond = al);
784
785 void sbc(Register dst, Register src1, const Operand& src2,
786 SBit s = LeaveCC, Condition cond = al);
787
788 void rsc(Register dst, Register src1, const Operand& src2,
789 SBit s = LeaveCC, Condition cond = al);
790
791 void tst(Register src1, const Operand& src2, Condition cond = al);
792 void tst(Register src1, Register src2, Condition cond = al) {
793 tst(src1, Operand(src2), cond);
794 }
795
796 void teq(Register src1, const Operand& src2, Condition cond = al);
797
798 void cmp(Register src1, const Operand& src2, Condition cond = al);
799 void cmp(Register src1, Register src2, Condition cond = al) {
800 cmp(src1, Operand(src2), cond);
801 }
802
803 void cmn(Register src1, const Operand& src2, Condition cond = al);
804
805 void orr(Register dst, Register src1, const Operand& src2,
806 SBit s = LeaveCC, Condition cond = al);
807 void orr(Register dst, Register src1, Register src2,
808 SBit s = LeaveCC, Condition cond = al) {
809 orr(dst, src1, Operand(src2), s, cond);
810 }
811
812 void mov(Register dst, const Operand& src,
813 SBit s = LeaveCC, Condition cond = al);
814 void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
815 mov(dst, Operand(src), s, cond);
816 }
817
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100818 // ARMv7 instructions for loading a 32 bit immediate in two instructions.
819 // This may actually emit a different mov instruction, but on an ARMv7 it
820 // is guaranteed to only emit one instruction.
821 void movw(Register reg, uint32_t immediate, Condition cond = al);
822 // The constant for movt should be in the range 0-0xffff.
823 void movt(Register reg, uint32_t immediate, Condition cond = al);
824
Steve Blocka7e24c12009-10-30 11:49:00 +0000825 void bic(Register dst, Register src1, const Operand& src2,
826 SBit s = LeaveCC, Condition cond = al);
827
828 void mvn(Register dst, const Operand& src,
829 SBit s = LeaveCC, Condition cond = al);
830
831 // Multiply instructions
832
833 void mla(Register dst, Register src1, Register src2, Register srcA,
834 SBit s = LeaveCC, Condition cond = al);
835
836 void mul(Register dst, Register src1, Register src2,
837 SBit s = LeaveCC, Condition cond = al);
838
839 void smlal(Register dstL, Register dstH, Register src1, Register src2,
840 SBit s = LeaveCC, Condition cond = al);
841
842 void smull(Register dstL, Register dstH, Register src1, Register src2,
843 SBit s = LeaveCC, Condition cond = al);
844
845 void umlal(Register dstL, Register dstH, Register src1, Register src2,
846 SBit s = LeaveCC, Condition cond = al);
847
848 void umull(Register dstL, Register dstH, Register src1, Register src2,
849 SBit s = LeaveCC, Condition cond = al);
850
851 // Miscellaneous arithmetic instructions
852
853 void clz(Register dst, Register src, Condition cond = al); // v5 and above
854
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100855 // Saturating instructions. v6 and above.
856
857 // Unsigned saturate.
858 //
859 // Saturate an optionally shifted signed value to an unsigned range.
860 //
861 // usat dst, #satpos, src
862 // usat dst, #satpos, src, lsl #sh
863 // usat dst, #satpos, src, asr #sh
864 //
865 // Register dst will contain:
866 //
867 // 0, if s < 0
868 // (1 << satpos) - 1, if s > ((1 << satpos) - 1)
869 // s, otherwise
870 //
871 // where s is the contents of src after shifting (if used.)
872 void usat(Register dst, int satpos, const Operand& src, Condition cond = al);
873
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100874 // Bitfield manipulation instructions. v7 and above.
875
876 void ubfx(Register dst, Register src, int lsb, int width,
877 Condition cond = al);
878
879 void sbfx(Register dst, Register src, int lsb, int width,
880 Condition cond = al);
881
882 void bfc(Register dst, int lsb, int width, Condition cond = al);
883
884 void bfi(Register dst, Register src, int lsb, int width,
885 Condition cond = al);
886
Steve Blocka7e24c12009-10-30 11:49:00 +0000887 // Status register access instructions
888
889 void mrs(Register dst, SRegister s, Condition cond = al);
890 void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al);
891
892 // Load/Store instructions
893 void ldr(Register dst, const MemOperand& src, Condition cond = al);
894 void str(Register src, const MemOperand& dst, Condition cond = al);
895 void ldrb(Register dst, const MemOperand& src, Condition cond = al);
896 void strb(Register src, const MemOperand& dst, Condition cond = al);
897 void ldrh(Register dst, const MemOperand& src, Condition cond = al);
898 void strh(Register src, const MemOperand& dst, Condition cond = al);
899 void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
900 void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
Leon Clarkef7060e22010-06-03 12:02:55 +0100901 void ldrd(Register dst1,
902 Register dst2,
903 const MemOperand& src, Condition cond = al);
904 void strd(Register src1,
905 Register src2,
906 const MemOperand& dst, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000907
908 // Load/Store multiple instructions
909 void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
910 void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
911
Steve Blocka7e24c12009-10-30 11:49:00 +0000912 // Exception-generating instructions and debugging support
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800913 static const int kDefaultStopCode = -1;
914 void stop(const char* msg,
915 Condition cond = al,
916 int32_t code = kDefaultStopCode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000917
918 void bkpt(uint32_t imm16); // v5 and above
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800919 void svc(uint32_t imm24, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000920
921 // Coprocessor instructions
922
923 void cdp(Coprocessor coproc, int opcode_1,
924 CRegister crd, CRegister crn, CRegister crm,
925 int opcode_2, Condition cond = al);
926
927 void cdp2(Coprocessor coproc, int opcode_1,
928 CRegister crd, CRegister crn, CRegister crm,
929 int opcode_2); // v5 and above
930
931 void mcr(Coprocessor coproc, int opcode_1,
932 Register rd, CRegister crn, CRegister crm,
933 int opcode_2 = 0, Condition cond = al);
934
935 void mcr2(Coprocessor coproc, int opcode_1,
936 Register rd, CRegister crn, CRegister crm,
937 int opcode_2 = 0); // v5 and above
938
939 void mrc(Coprocessor coproc, int opcode_1,
940 Register rd, CRegister crn, CRegister crm,
941 int opcode_2 = 0, Condition cond = al);
942
943 void mrc2(Coprocessor coproc, int opcode_1,
944 Register rd, CRegister crn, CRegister crm,
945 int opcode_2 = 0); // v5 and above
946
947 void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src,
948 LFlag l = Short, Condition cond = al);
949 void ldc(Coprocessor coproc, CRegister crd, Register base, int option,
950 LFlag l = Short, Condition cond = al);
951
952 void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
953 LFlag l = Short); // v5 and above
954 void ldc2(Coprocessor coproc, CRegister crd, Register base, int option,
955 LFlag l = Short); // v5 and above
956
957 void stc(Coprocessor coproc, CRegister crd, const MemOperand& dst,
958 LFlag l = Short, Condition cond = al);
959 void stc(Coprocessor coproc, CRegister crd, Register base, int option,
960 LFlag l = Short, Condition cond = al);
961
962 void stc2(Coprocessor coproc, CRegister crd, const MemOperand& dst,
963 LFlag l = Short); // v5 and above
964 void stc2(Coprocessor coproc, CRegister crd, Register base, int option,
965 LFlag l = Short); // v5 and above
966
Steve Blockd0582a62009-12-15 09:54:21 +0000967 // Support for VFP.
968 // All these APIs support S0 to S31 and D0 to D15.
969 // Currently these APIs do not support extended D registers, i.e, D16 to D31.
970 // However, some simple modifications can allow
971 // these APIs to support D16 to D31.
972
Leon Clarked91b9f72010-01-27 17:25:45 +0000973 void vldr(const DwVfpRegister dst,
974 const Register base,
975 int offset, // Offset must be a multiple of 4.
976 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +0100977
978 void vldr(const SwVfpRegister dst,
979 const Register base,
980 int offset, // Offset must be a multiple of 4.
981 const Condition cond = al);
982
Leon Clarked91b9f72010-01-27 17:25:45 +0000983 void vstr(const DwVfpRegister src,
984 const Register base,
985 int offset, // Offset must be a multiple of 4.
986 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +0100987
Iain Merrick75681382010-08-19 15:07:18 +0100988 void vstr(const SwVfpRegister src,
989 const Register base,
990 int offset, // Offset must be a multiple of 4.
991 const Condition cond = al);
992
Steve Block8defd9f2010-07-08 12:39:36 +0100993 void vmov(const DwVfpRegister dst,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100994 double imm,
995 const Condition cond = al);
996 void vmov(const SwVfpRegister dst,
997 const SwVfpRegister src,
998 const Condition cond = al);
999 void vmov(const DwVfpRegister dst,
Steve Block8defd9f2010-07-08 12:39:36 +01001000 const DwVfpRegister src,
1001 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001002 void vmov(const DwVfpRegister dst,
1003 const Register src1,
Steve Blockd0582a62009-12-15 09:54:21 +00001004 const Register src2,
Leon Clarkee46be812010-01-19 14:06:41 +00001005 const Condition cond = al);
1006 void vmov(const Register dst1,
1007 const Register dst2,
1008 const DwVfpRegister src,
1009 const Condition cond = al);
1010 void vmov(const SwVfpRegister dst,
1011 const Register src,
1012 const Condition cond = al);
1013 void vmov(const Register dst,
1014 const SwVfpRegister src,
1015 const Condition cond = al);
Russell Brenner90bac252010-11-18 13:33:46 -08001016 enum ConversionMode {
1017 FPSCRRounding = 0,
1018 RoundToZero = 1
1019 };
Steve Block6ded16b2010-05-10 14:33:55 +01001020 void vcvt_f64_s32(const DwVfpRegister dst,
1021 const SwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001022 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001023 const Condition cond = al);
1024 void vcvt_f32_s32(const SwVfpRegister dst,
1025 const SwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001026 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001027 const Condition cond = al);
1028 void vcvt_f64_u32(const DwVfpRegister dst,
1029 const SwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001030 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001031 const Condition cond = al);
1032 void vcvt_s32_f64(const SwVfpRegister dst,
1033 const DwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001034 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001035 const Condition cond = al);
1036 void vcvt_u32_f64(const SwVfpRegister dst,
1037 const DwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001038 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001039 const Condition cond = al);
1040 void vcvt_f64_f32(const DwVfpRegister dst,
1041 const SwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001042 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001043 const Condition cond = al);
1044 void vcvt_f32_f64(const SwVfpRegister dst,
1045 const DwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001046 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001047 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001048
1049 void vadd(const DwVfpRegister dst,
1050 const DwVfpRegister src1,
1051 const DwVfpRegister src2,
1052 const Condition cond = al);
1053 void vsub(const DwVfpRegister dst,
1054 const DwVfpRegister src1,
1055 const DwVfpRegister src2,
1056 const Condition cond = al);
1057 void vmul(const DwVfpRegister dst,
1058 const DwVfpRegister src1,
1059 const DwVfpRegister src2,
1060 const Condition cond = al);
1061 void vdiv(const DwVfpRegister dst,
1062 const DwVfpRegister src1,
1063 const DwVfpRegister src2,
1064 const Condition cond = al);
1065 void vcmp(const DwVfpRegister src1,
1066 const DwVfpRegister src2,
Steve Blockd0582a62009-12-15 09:54:21 +00001067 const SBit s = LeaveCC,
1068 const Condition cond = al);
Iain Merrick75681382010-08-19 15:07:18 +01001069 void vcmp(const DwVfpRegister src1,
1070 const double src2,
1071 const SBit s = LeaveCC,
1072 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001073 void vmrs(const Register dst,
1074 const Condition cond = al);
Russell Brenner90bac252010-11-18 13:33:46 -08001075 void vmsr(const Register dst,
1076 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +01001077 void vsqrt(const DwVfpRegister dst,
1078 const DwVfpRegister src,
1079 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001080
Steve Blocka7e24c12009-10-30 11:49:00 +00001081 // Pseudo instructions
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001082
1083 // Different nop operations are used by the code generator to detect certain
1084 // states of the generated code.
1085 enum NopMarkerTypes {
1086 NON_MARKING_NOP = 0,
1087 DEBUG_BREAK_NOP,
1088 // IC markers.
1089 PROPERTY_ACCESS_INLINED,
1090 PROPERTY_ACCESS_INLINED_CONTEXT,
1091 PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE,
1092 // Helper values.
1093 LAST_CODE_MARKER,
1094 FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED
1095 };
1096
1097 void nop(int type = 0); // 0 is the default non-marking type.
Steve Blocka7e24c12009-10-30 11:49:00 +00001098
1099 void push(Register src, Condition cond = al) {
1100 str(src, MemOperand(sp, 4, NegPreIndex), cond);
1101 }
1102
1103 void pop(Register dst, Condition cond = al) {
1104 ldr(dst, MemOperand(sp, 4, PostIndex), cond);
1105 }
1106
1107 void pop() {
1108 add(sp, sp, Operand(kPointerSize));
1109 }
1110
Steve Blocka7e24c12009-10-30 11:49:00 +00001111 // Jump unconditionally to given label.
1112 void jmp(Label* L) { b(L, al); }
1113
1114 // Check the code size generated from label to here.
1115 int InstructionsGeneratedSince(Label* l) {
1116 return (pc_offset() - l->pos()) / kInstrSize;
1117 }
1118
Steve Blockd0582a62009-12-15 09:54:21 +00001119 // Check whether an immediate fits an addressing mode 1 instruction.
1120 bool ImmediateFitsAddrMode1Instruction(int32_t imm32);
1121
Steve Block6ded16b2010-05-10 14:33:55 +01001122 // Class for scoping postponing the constant pool generation.
1123 class BlockConstPoolScope {
1124 public:
1125 explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) {
1126 assem_->StartBlockConstPool();
1127 }
1128 ~BlockConstPoolScope() {
1129 assem_->EndBlockConstPool();
1130 }
1131
1132 private:
1133 Assembler* assem_;
1134
1135 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstPoolScope);
1136 };
1137
Steve Blockd0582a62009-12-15 09:54:21 +00001138 // Postpone the generation of the constant pool for the specified number of
1139 // instructions.
1140 void BlockConstPoolFor(int instructions);
1141
Steve Blocka7e24c12009-10-30 11:49:00 +00001142 // Debugging
1143
1144 // Mark address of the ExitJSFrame code.
1145 void RecordJSReturn();
1146
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001147 // Mark address of a debug break slot.
1148 void RecordDebugBreakSlot();
1149
Steve Blocka7e24c12009-10-30 11:49:00 +00001150 // Record a comment relocation entry that can be used by a disassembler.
1151 // Use --debug_code to enable.
1152 void RecordComment(const char* msg);
1153
Steve Blocka7e24c12009-10-30 11:49:00 +00001154 int pc_offset() const { return pc_ - buffer_; }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001155
1156 PositionsRecorder* positions_recorder() { return &positions_recorder_; }
Steve Block6ded16b2010-05-10 14:33:55 +01001157
Leon Clarkef7060e22010-06-03 12:02:55 +01001158 bool can_peephole_optimize(int instructions) {
1159 if (!FLAG_peephole_optimization) return false;
1160 if (last_bound_pos_ > pc_offset() - instructions * kInstrSize) return false;
1161 return reloc_info_writer.last_pc() <= pc_ - instructions * kInstrSize;
1162 }
1163
Steve Block6ded16b2010-05-10 14:33:55 +01001164 // Read/patch instructions
1165 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
1166 static void instr_at_put(byte* pc, Instr instr) {
1167 *reinterpret_cast<Instr*>(pc) = instr;
1168 }
Steve Block6ded16b2010-05-10 14:33:55 +01001169 static bool IsBranch(Instr instr);
1170 static int GetBranchOffset(Instr instr);
1171 static bool IsLdrRegisterImmediate(Instr instr);
1172 static int GetLdrRegisterImmediateOffset(Instr instr);
1173 static Instr SetLdrRegisterImmediateOffset(Instr instr, int offset);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001174 static bool IsStrRegisterImmediate(Instr instr);
1175 static Instr SetStrRegisterImmediateOffset(Instr instr, int offset);
1176 static bool IsAddRegisterImmediate(Instr instr);
1177 static Instr SetAddRegisterImmediateOffset(Instr instr, int offset);
Leon Clarkef7060e22010-06-03 12:02:55 +01001178 static Register GetRd(Instr instr);
1179 static bool IsPush(Instr instr);
1180 static bool IsPop(Instr instr);
1181 static bool IsStrRegFpOffset(Instr instr);
1182 static bool IsLdrRegFpOffset(Instr instr);
1183 static bool IsStrRegFpNegOffset(Instr instr);
1184 static bool IsLdrRegFpNegOffset(Instr instr);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001185 static bool IsLdrPcImmediateOffset(Instr instr);
1186 static bool IsNop(Instr instr, int type = NON_MARKING_NOP);
Steve Block6ded16b2010-05-10 14:33:55 +01001187
Steve Blocka7e24c12009-10-30 11:49:00 +00001188
1189 protected:
1190 int buffer_space() const { return reloc_info_writer.pos() - pc_; }
1191
1192 // Read/patch instructions
Steve Blocka7e24c12009-10-30 11:49:00 +00001193 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
1194 void instr_at_put(int pos, Instr instr) {
1195 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
1196 }
1197
1198 // Decode branch instruction at pos and return branch target pos
1199 int target_at(int pos);
1200
1201 // Patch branch instruction at pos to branch to given branch target pos
1202 void target_at_put(int pos, int target_pos);
1203
1204 // Check if is time to emit a constant pool for pending reloc info entries
1205 void CheckConstPool(bool force_emit, bool require_jump);
1206
1207 // Block the emission of the constant pool before pc_offset
1208 void BlockConstPoolBefore(int pc_offset) {
1209 if (no_const_pool_before_ < pc_offset) no_const_pool_before_ = pc_offset;
1210 }
1211
Steve Block6ded16b2010-05-10 14:33:55 +01001212 void StartBlockConstPool() {
1213 const_pool_blocked_nesting_++;
1214 }
1215 void EndBlockConstPool() {
1216 const_pool_blocked_nesting_--;
1217 }
Steve Block8defd9f2010-07-08 12:39:36 +01001218 bool is_const_pool_blocked() const { return const_pool_blocked_nesting_ > 0; }
Steve Block6ded16b2010-05-10 14:33:55 +01001219
Steve Blocka7e24c12009-10-30 11:49:00 +00001220 private:
1221 // Code buffer:
1222 // The buffer into which code and relocation info are generated.
1223 byte* buffer_;
1224 int buffer_size_;
1225 // True if the assembler owns the buffer, false if buffer is external.
1226 bool own_buffer_;
1227
1228 // Buffer size and constant pool distance are checked together at regular
1229 // intervals of kBufferCheckInterval emitted bytes
1230 static const int kBufferCheckInterval = 1*KB/2;
1231 int next_buffer_check_; // pc offset of next buffer check
1232
1233 // Code generation
1234 // The relocation writer's position is at least kGap bytes below the end of
1235 // the generated instructions. This is so that multi-instruction sequences do
1236 // not have to check for overflow. The same is true for writes of large
1237 // relocation info entries.
1238 static const int kGap = 32;
1239 byte* pc_; // the program counter; moves forward
1240
1241 // Constant pool generation
1242 // Pools are emitted in the instruction stream, preferably after unconditional
1243 // jumps or after returns from functions (in dead code locations).
1244 // If a long code sequence does not contain unconditional jumps, it is
1245 // necessary to emit the constant pool before the pool gets too far from the
1246 // location it is accessed from. In this case, we emit a jump over the emitted
1247 // constant pool.
1248 // Constants in the pool may be addresses of functions that gets relocated;
1249 // if so, a relocation info entry is associated to the constant pool entry.
1250
1251 // Repeated checking whether the constant pool should be emitted is rather
1252 // expensive. By default we only check again once a number of instructions
1253 // has been generated. That also means that the sizing of the buffers is not
1254 // an exact science, and that we rely on some slop to not overrun buffers.
1255 static const int kCheckConstIntervalInst = 32;
1256 static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize;
1257
1258
1259 // Pools are emitted after function return and in dead code at (more or less)
1260 // regular intervals of kDistBetweenPools bytes
1261 static const int kDistBetweenPools = 1*KB;
1262
1263 // Constants in pools are accessed via pc relative addressing, which can
1264 // reach +/-4KB thereby defining a maximum distance between the instruction
1265 // and the accessed constant. We satisfy this constraint by limiting the
1266 // distance between pools.
1267 static const int kMaxDistBetweenPools = 4*KB - 2*kBufferCheckInterval;
1268
Steve Block6ded16b2010-05-10 14:33:55 +01001269 // Emission of the constant pool may be blocked in some code sequences.
1270 int const_pool_blocked_nesting_; // Block emission if this is not zero.
1271 int no_const_pool_before_; // Block emission before this pc offset.
Steve Blocka7e24c12009-10-30 11:49:00 +00001272
1273 // Keep track of the last emitted pool to guarantee a maximal distance
1274 int last_const_pool_end_; // pc offset following the last constant pool
1275
1276 // Relocation info generation
1277 // Each relocation is encoded as a variable size value
1278 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1279 RelocInfoWriter reloc_info_writer;
1280 // Relocation info records are also used during code generation as temporary
1281 // containers for constants and code target addresses until they are emitted
1282 // to the constant pool. These pending relocation info records are temporarily
1283 // stored in a separate buffer until a constant pool is emitted.
1284 // If every instruction in a long sequence is accessing the pool, we need one
1285 // pending relocation entry per instruction.
1286 static const int kMaxNumPRInfo = kMaxDistBetweenPools/kInstrSize;
1287 RelocInfo prinfo_[kMaxNumPRInfo]; // the buffer of pending relocation info
1288 int num_prinfo_; // number of pending reloc info entries in the buffer
1289
1290 // The bound position, before this we cannot do instruction elimination.
1291 int last_bound_pos_;
1292
Steve Blocka7e24c12009-10-30 11:49:00 +00001293 // Code emission
1294 inline void CheckBuffer();
1295 void GrowBuffer();
1296 inline void emit(Instr x);
1297
1298 // Instruction generation
1299 void addrmod1(Instr instr, Register rn, Register rd, const Operand& x);
1300 void addrmod2(Instr instr, Register rd, const MemOperand& x);
1301 void addrmod3(Instr instr, Register rd, const MemOperand& x);
1302 void addrmod4(Instr instr, Register rn, RegList rl);
1303 void addrmod5(Instr instr, CRegister crd, const MemOperand& x);
1304
1305 // Labels
1306 void print(Label* L);
1307 void bind_to(Label* L, int pos);
1308 void link_to(Label* L, Label* appendix);
1309 void next(Label* L);
1310
1311 // Record reloc info for current pc_
1312 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
1313
1314 friend class RegExpMacroAssemblerARM;
1315 friend class RelocInfo;
1316 friend class CodePatcher;
Steve Block6ded16b2010-05-10 14:33:55 +01001317 friend class BlockConstPoolScope;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001318
1319 PositionsRecorder positions_recorder_;
1320 friend class PositionsRecorder;
1321 friend class EnsureSpace;
Steve Blocka7e24c12009-10-30 11:49:00 +00001322};
1323
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001324
1325class EnsureSpace BASE_EMBEDDED {
1326 public:
1327 explicit EnsureSpace(Assembler* assembler) {
1328 assembler->CheckBuffer();
1329 }
1330};
1331
1332
Steve Blocka7e24c12009-10-30 11:49:00 +00001333} } // namespace v8::internal
1334
1335#endif // V8_ARM_ASSEMBLER_ARM_H_