blob: de3931c2cf9285cd6ec548436f2df2a9b8fe016d [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
Steve Blocka7e24c12009-10-30 11:49:00 +0000222
223// Coprocessor register
224struct CRegister {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100225 bool is_valid() const { return 0 <= code_ && code_ < 16; }
226 bool is(CRegister creg) const { return code_ == creg.code_; }
227 int code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000228 ASSERT(is_valid());
229 return code_;
230 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100231 int bit() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000232 ASSERT(is_valid());
233 return 1 << code_;
234 }
235
Andrei Popescu31002712010-02-23 13:46:05 +0000236 // Unfortunately we can't make this private in a struct.
Steve Blocka7e24c12009-10-30 11:49:00 +0000237 int code_;
238};
239
240
Steve Block6ded16b2010-05-10 14:33:55 +0100241const CRegister no_creg = { -1 };
242
243const CRegister cr0 = { 0 };
244const CRegister cr1 = { 1 };
245const CRegister cr2 = { 2 };
246const CRegister cr3 = { 3 };
247const CRegister cr4 = { 4 };
248const CRegister cr5 = { 5 };
249const CRegister cr6 = { 6 };
250const CRegister cr7 = { 7 };
251const CRegister cr8 = { 8 };
252const CRegister cr9 = { 9 };
253const CRegister cr10 = { 10 };
254const CRegister cr11 = { 11 };
255const CRegister cr12 = { 12 };
256const CRegister cr13 = { 13 };
257const CRegister cr14 = { 14 };
258const CRegister cr15 = { 15 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000259
260
261// Coprocessor number
262enum Coprocessor {
263 p0 = 0,
264 p1 = 1,
265 p2 = 2,
266 p3 = 3,
267 p4 = 4,
268 p5 = 5,
269 p6 = 6,
270 p7 = 7,
271 p8 = 8,
272 p9 = 9,
273 p10 = 10,
274 p11 = 11,
275 p12 = 12,
276 p13 = 13,
277 p14 = 14,
278 p15 = 15
279};
280
281
Andrei Popescu31002712010-02-23 13:46:05 +0000282// Condition field in instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +0000283enum Condition {
284 eq = 0 << 28, // Z set equal.
285 ne = 1 << 28, // Z clear not equal.
286 nz = 1 << 28, // Z clear not zero.
287 cs = 2 << 28, // C set carry set.
288 hs = 2 << 28, // C set unsigned higher or same.
289 cc = 3 << 28, // C clear carry clear.
290 lo = 3 << 28, // C clear unsigned lower.
291 mi = 4 << 28, // N set negative.
292 pl = 5 << 28, // N clear positive or zero.
293 vs = 6 << 28, // V set overflow.
294 vc = 7 << 28, // V clear no overflow.
295 hi = 8 << 28, // C set, Z clear unsigned higher.
296 ls = 9 << 28, // C clear or Z set unsigned lower or same.
297 ge = 10 << 28, // N == V greater or equal.
298 lt = 11 << 28, // N != V less than.
299 gt = 12 << 28, // Z clear, N == V greater than.
300 le = 13 << 28, // Z set or N != V less then or equal
301 al = 14 << 28 // always.
302};
303
304
305// Returns the equivalent of !cc.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100306inline Condition NegateCondition(Condition cc) {
307 ASSERT(cc != al);
308 return static_cast<Condition>(cc ^ ne);
309}
Steve Blocka7e24c12009-10-30 11:49:00 +0000310
311
312// Corresponds to transposing the operands of a comparison.
313inline Condition ReverseCondition(Condition cc) {
314 switch (cc) {
315 case lo:
316 return hi;
317 case hi:
318 return lo;
319 case hs:
320 return ls;
321 case ls:
322 return hs;
323 case lt:
324 return gt;
325 case gt:
326 return lt;
327 case ge:
328 return le;
329 case le:
330 return ge;
331 default:
332 return cc;
333 };
334}
335
336
337// Branch hints are not used on the ARM. They are defined so that they can
338// appear in shared function signatures, but will be ignored in ARM
339// implementations.
340enum Hint { no_hint };
341
342// Hints are not used on the arm. Negating is trivial.
343inline Hint NegateHint(Hint ignored) { return no_hint; }
344
345
346// -----------------------------------------------------------------------------
347// Addressing modes and instruction variants
348
349// Shifter operand shift operation
350enum ShiftOp {
351 LSL = 0 << 5,
352 LSR = 1 << 5,
353 ASR = 2 << 5,
354 ROR = 3 << 5,
355 RRX = -1
356};
357
358
359// Condition code updating mode
360enum SBit {
361 SetCC = 1 << 20, // set condition code
362 LeaveCC = 0 << 20 // leave condition code unchanged
363};
364
365
366// Status register selection
367enum SRegister {
368 CPSR = 0 << 22,
369 SPSR = 1 << 22
370};
371
372
373// Status register fields
374enum SRegisterField {
375 CPSR_c = CPSR | 1 << 16,
376 CPSR_x = CPSR | 1 << 17,
377 CPSR_s = CPSR | 1 << 18,
378 CPSR_f = CPSR | 1 << 19,
379 SPSR_c = SPSR | 1 << 16,
380 SPSR_x = SPSR | 1 << 17,
381 SPSR_s = SPSR | 1 << 18,
382 SPSR_f = SPSR | 1 << 19
383};
384
385// Status register field mask (or'ed SRegisterField enum values)
386typedef uint32_t SRegisterFieldMask;
387
388
389// Memory operand addressing mode
390enum AddrMode {
391 // bit encoding P U W
392 Offset = (8|4|0) << 21, // offset (without writeback to base)
393 PreIndex = (8|4|1) << 21, // pre-indexed addressing with writeback
394 PostIndex = (0|4|0) << 21, // post-indexed addressing with writeback
395 NegOffset = (8|0|0) << 21, // negative offset (without writeback to base)
396 NegPreIndex = (8|0|1) << 21, // negative pre-indexed with writeback
397 NegPostIndex = (0|0|0) << 21 // negative post-indexed with writeback
398};
399
400
401// Load/store multiple addressing mode
402enum BlockAddrMode {
403 // bit encoding P U W
404 da = (0|0|0) << 21, // decrement after
405 ia = (0|4|0) << 21, // increment after
406 db = (8|0|0) << 21, // decrement before
407 ib = (8|4|0) << 21, // increment before
408 da_w = (0|0|1) << 21, // decrement after with writeback to base
409 ia_w = (0|4|1) << 21, // increment after with writeback to base
410 db_w = (8|0|1) << 21, // decrement before with writeback to base
411 ib_w = (8|4|1) << 21 // increment before with writeback to base
412};
413
414
415// Coprocessor load/store operand size
416enum LFlag {
417 Long = 1 << 22, // long load/store coprocessor
418 Short = 0 << 22 // short load/store coprocessor
419};
420
421
422// -----------------------------------------------------------------------------
423// Machine instruction Operands
424
425// Class Operand represents a shifter operand in data processing instructions
426class Operand BASE_EMBEDDED {
427 public:
428 // immediate
429 INLINE(explicit Operand(int32_t immediate,
430 RelocInfo::Mode rmode = RelocInfo::NONE));
431 INLINE(explicit Operand(const ExternalReference& f));
432 INLINE(explicit Operand(const char* s));
Steve Blocka7e24c12009-10-30 11:49:00 +0000433 explicit Operand(Handle<Object> handle);
434 INLINE(explicit Operand(Smi* value));
435
436 // rm
437 INLINE(explicit Operand(Register rm));
438
439 // rm <shift_op> shift_imm
440 explicit Operand(Register rm, ShiftOp shift_op, int shift_imm);
441
442 // rm <shift_op> rs
443 explicit Operand(Register rm, ShiftOp shift_op, Register rs);
444
445 // Return true if this is a register operand.
446 INLINE(bool is_reg() const);
447
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100448 // Return true of this operand fits in one instruction so that no
449 // 2-instruction solution with a load into the ip register is necessary.
450 bool is_single_instruction() const;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800451 bool must_use_constant_pool() const;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100452
453 inline int32_t immediate() const {
454 ASSERT(!rm_.is_valid());
455 return imm32_;
456 }
457
Steve Blocka7e24c12009-10-30 11:49:00 +0000458 Register rm() const { return rm_; }
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100459 Register rs() const { return rs_; }
460 ShiftOp shift_op() const { return shift_op_; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000461
462 private:
463 Register rm_;
464 Register rs_;
465 ShiftOp shift_op_;
466 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
467 int32_t imm32_; // valid if rm_ == no_reg
468 RelocInfo::Mode rmode_;
469
470 friend class Assembler;
471};
472
473
474// Class MemOperand represents a memory operand in load and store instructions
475class MemOperand BASE_EMBEDDED {
476 public:
477 // [rn +/- offset] Offset/NegOffset
478 // [rn +/- offset]! PreIndex/NegPreIndex
479 // [rn], +/- offset PostIndex/NegPostIndex
480 // offset is any signed 32-bit value; offset is first loaded to register ip if
481 // it does not fit the addressing mode (12-bit unsigned and sign bit)
482 explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset);
483
484 // [rn +/- rm] Offset/NegOffset
485 // [rn +/- rm]! PreIndex/NegPreIndex
486 // [rn], +/- rm PostIndex/NegPostIndex
487 explicit MemOperand(Register rn, Register rm, AddrMode am = Offset);
488
489 // [rn +/- rm <shift_op> shift_imm] Offset/NegOffset
490 // [rn +/- rm <shift_op> shift_imm]! PreIndex/NegPreIndex
491 // [rn], +/- rm <shift_op> shift_imm PostIndex/NegPostIndex
492 explicit MemOperand(Register rn, Register rm,
493 ShiftOp shift_op, int shift_imm, AddrMode am = Offset);
494
Kristian Monsen25f61362010-05-21 11:50:48 +0100495 void set_offset(int32_t offset) {
496 ASSERT(rm_.is(no_reg));
497 offset_ = offset;
498 }
499
500 uint32_t offset() {
501 ASSERT(rm_.is(no_reg));
502 return offset_;
503 }
504
Leon Clarkef7060e22010-06-03 12:02:55 +0100505 Register rn() const { return rn_; }
506 Register rm() const { return rm_; }
Kristian Monsen25f61362010-05-21 11:50:48 +0100507
Steve Blocka7e24c12009-10-30 11:49:00 +0000508 private:
509 Register rn_; // base
510 Register rm_; // register offset
511 int32_t offset_; // valid if rm_ == no_reg
512 ShiftOp shift_op_;
513 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
514 AddrMode am_; // bits P, U, and W
515
516 friend class Assembler;
517};
518
Steve Blockd0582a62009-12-15 09:54:21 +0000519// CpuFeatures keeps track of which features are supported by the target CPU.
520// Supported features must be enabled by a Scope before use.
521class CpuFeatures : public AllStatic {
522 public:
523 // Detect features of the target CPU. Set safe defaults if the serializer
524 // is enabled (snapshots must be portable).
525 static void Probe();
526
527 // Check whether a feature is supported by the target CPU.
528 static bool IsSupported(CpuFeature f) {
529 if (f == VFP3 && !FLAG_enable_vfp3) return false;
530 return (supported_ & (1u << f)) != 0;
531 }
532
533 // Check whether a feature is currently enabled.
534 static bool IsEnabled(CpuFeature f) {
535 return (enabled_ & (1u << f)) != 0;
536 }
537
538 // Enable a specified feature within a scope.
539 class Scope BASE_EMBEDDED {
540#ifdef DEBUG
541 public:
542 explicit Scope(CpuFeature f) {
543 ASSERT(CpuFeatures::IsSupported(f));
544 ASSERT(!Serializer::enabled() ||
545 (found_by_runtime_probing_ & (1u << f)) == 0);
546 old_enabled_ = CpuFeatures::enabled_;
547 CpuFeatures::enabled_ |= 1u << f;
548 }
549 ~Scope() { CpuFeatures::enabled_ = old_enabled_; }
550 private:
551 unsigned old_enabled_;
552#else
553 public:
554 explicit Scope(CpuFeature f) {}
555#endif
556 };
557
558 private:
559 static unsigned supported_;
560 static unsigned enabled_;
561 static unsigned found_by_runtime_probing_;
562};
563
Steve Blocka7e24c12009-10-30 11:49:00 +0000564
565typedef int32_t Instr;
566
567
568extern const Instr kMovLrPc;
Steve Block6ded16b2010-05-10 14:33:55 +0100569extern const Instr kLdrPCMask;
Steve Blocka7e24c12009-10-30 11:49:00 +0000570extern const Instr kLdrPCPattern;
Steve Block6ded16b2010-05-10 14:33:55 +0100571extern const Instr kBlxRegMask;
572extern const Instr kBlxRegPattern;
Steve Blocka7e24c12009-10-30 11:49:00 +0000573
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100574extern const Instr kMovMvnMask;
575extern const Instr kMovMvnPattern;
576extern const Instr kMovMvnFlip;
577
578extern const Instr kMovLeaveCCMask;
579extern const Instr kMovLeaveCCPattern;
580extern const Instr kMovwMask;
581extern const Instr kMovwPattern;
582extern const Instr kMovwLeaveCCFlip;
583
584extern const Instr kCmpCmnMask;
585extern const Instr kCmpCmnPattern;
586extern const Instr kCmpCmnFlip;
587
588extern const Instr kALUMask;
589extern const Instr kAddPattern;
590extern const Instr kSubPattern;
591extern const Instr kAndPattern;
592extern const Instr kBicPattern;
593extern const Instr kAddSubFlip;
594extern const Instr kAndBicFlip;
Steve Blocka7e24c12009-10-30 11:49:00 +0000595
596class Assembler : public Malloced {
597 public:
598 // Create an assembler. Instructions and relocation information are emitted
599 // into a buffer, with the instructions starting from the beginning and the
600 // relocation information starting from the end of the buffer. See CodeDesc
601 // for a detailed comment on the layout (globals.h).
602 //
603 // If the provided buffer is NULL, the assembler allocates and grows its own
604 // buffer, and buffer_size determines the initial buffer size. The buffer is
605 // owned by the assembler and deallocated upon destruction of the assembler.
606 //
607 // If the provided buffer is not NULL, the assembler uses the provided buffer
608 // for code generation and assumes its size to be buffer_size. If the buffer
609 // is too small, a fatal error occurs. No deallocation of the buffer is done
610 // upon destruction of the assembler.
611 Assembler(void* buffer, int buffer_size);
612 ~Assembler();
613
614 // GetCode emits any pending (non-emitted) code and fills the descriptor
615 // desc. GetCode() is idempotent; it returns the same result if no other
616 // Assembler functions are invoked in between GetCode() calls.
617 void GetCode(CodeDesc* desc);
618
619 // Label operations & relative jumps (PPUM Appendix D)
620 //
621 // Takes a branch opcode (cc) and a label (L) and generates
622 // either a backward branch or a forward branch and links it
623 // to the label fixup chain. Usage:
624 //
625 // Label L; // unbound label
626 // j(cc, &L); // forward branch to unbound label
627 // bind(&L); // bind label to the current pc
628 // j(cc, &L); // backward branch to bound label
629 // bind(&L); // illegal: a label may be bound only once
630 //
631 // Note: The same Label can be used for forward and backward branches
632 // but it may be bound only once.
633
634 void bind(Label* L); // binds an unbound label L to the current code position
635
636 // Returns the branch offset to the given label from the current code position
637 // Links the label to the current position if it is still unbound
638 // Manages the jump elimination optimization if the second parameter is true.
639 int branch_offset(Label* L, bool jump_elimination_allowed);
640
641 // Puts a labels target address at the given position.
642 // The high 8 bits are set to zero.
643 void label_at_put(Label* L, int at_offset);
644
645 // Return the address in the constant pool of the code target address used by
646 // the branch/call instruction at pc.
647 INLINE(static Address target_address_address_at(Address pc));
648
649 // Read/Modify the code target address in the branch/call instruction at pc.
650 INLINE(static Address target_address_at(Address pc));
651 INLINE(static void set_target_address_at(Address pc, Address target));
652
Steve Blockd0582a62009-12-15 09:54:21 +0000653 // This sets the branch destination (which is in the constant pool on ARM).
654 // This is for calls and branches within generated code.
655 inline static void set_target_at(Address constant_pool_entry, Address target);
656
657 // This sets the branch destination (which is in the constant pool on ARM).
658 // This is for calls and branches to runtime code.
659 inline static void set_external_target_at(Address constant_pool_entry,
660 Address target) {
661 set_target_at(constant_pool_entry, target);
662 }
663
664 // Here we are patching the address in the constant pool, not the actual call
665 // instruction. The address in the constant pool is the same size as a
666 // pointer.
667 static const int kCallTargetSize = kPointerSize;
668 static const int kExternalTargetSize = kPointerSize;
669
Steve Blocka7e24c12009-10-30 11:49:00 +0000670 // Size of an instruction.
671 static const int kInstrSize = sizeof(Instr);
672
673 // Distance between the instruction referring to the address of the call
Steve Block6ded16b2010-05-10 14:33:55 +0100674 // target and the return address.
675#ifdef USE_BLX
676 // Call sequence is:
677 // ldr ip, [pc, #...] @ call address
678 // blx ip
679 // @ return address
680 static const int kCallTargetAddressOffset = 2 * kInstrSize;
681#else
682 // Call sequence is:
683 // mov lr, pc
684 // ldr pc, [pc, #...] @ call address
685 // @ return address
Steve Blocka7e24c12009-10-30 11:49:00 +0000686 static const int kCallTargetAddressOffset = kInstrSize;
Steve Block6ded16b2010-05-10 14:33:55 +0100687#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000688
689 // Distance between start of patched return sequence and the emitted address
690 // to jump to.
Steve Block6ded16b2010-05-10 14:33:55 +0100691#ifdef USE_BLX
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100692 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100693 // ldr ip, [pc, #0] @ emited address and start
694 // blx ip
695 static const int kPatchReturnSequenceAddressOffset = 0 * kInstrSize;
696#else
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100697 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100698 // mov lr, pc @ start of sequence
699 // ldr pc, [pc, #-4] @ emited address
700 static const int kPatchReturnSequenceAddressOffset = kInstrSize;
701#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000702
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100703 // Distance between start of patched debug break slot and the emitted address
704 // to jump to.
705#ifdef USE_BLX
706 // Patched debug break slot code is:
707 // ldr ip, [pc, #0] @ emited address and start
708 // blx ip
709 static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
710#else
711 // Patched debug break slot code is:
712 // mov lr, pc @ start of sequence
713 // ldr pc, [pc, #-4] @ emited address
714 static const int kPatchDebugBreakSlotAddressOffset = kInstrSize;
715#endif
716
Steve Blocka7e24c12009-10-30 11:49:00 +0000717 // Difference between address of current opcode and value read from pc
718 // register.
719 static const int kPcLoadDelta = 8;
720
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100721 static const int kJSReturnSequenceInstructions = 4;
722 static const int kDebugBreakSlotInstructions = 3;
723 static const int kDebugBreakSlotLength =
724 kDebugBreakSlotInstructions * kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +0000725
726 // ---------------------------------------------------------------------------
727 // Code generation
728
729 // Insert the smallest number of nop instructions
730 // possible to align the pc offset to a multiple
731 // of m. m must be a power of 2 (>= 4).
732 void Align(int m);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100733 // Aligns code to something that's optimal for a jump target for the platform.
734 void CodeTargetAlign();
Steve Blocka7e24c12009-10-30 11:49:00 +0000735
736 // Branch instructions
737 void b(int branch_offset, Condition cond = al);
738 void bl(int branch_offset, Condition cond = al);
739 void blx(int branch_offset); // v5 and above
740 void blx(Register target, Condition cond = al); // v5 and above
741 void bx(Register target, Condition cond = al); // v5 and above, plus v4t
742
743 // Convenience branch instructions using labels
744 void b(Label* L, Condition cond = al) {
745 b(branch_offset(L, cond == al), cond);
746 }
747 void b(Condition cond, Label* L) { b(branch_offset(L, cond == al), cond); }
748 void bl(Label* L, Condition cond = al) { bl(branch_offset(L, false), cond); }
749 void bl(Condition cond, Label* L) { bl(branch_offset(L, false), cond); }
750 void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above
751
752 // Data-processing instructions
Andrei Popescu31002712010-02-23 13:46:05 +0000753
Steve Blocka7e24c12009-10-30 11:49:00 +0000754 void and_(Register dst, Register src1, const Operand& src2,
755 SBit s = LeaveCC, Condition cond = al);
756
757 void eor(Register dst, Register src1, const Operand& src2,
758 SBit s = LeaveCC, Condition cond = al);
759
760 void sub(Register dst, Register src1, const Operand& src2,
761 SBit s = LeaveCC, Condition cond = al);
762 void sub(Register dst, Register src1, Register src2,
763 SBit s = LeaveCC, Condition cond = al) {
764 sub(dst, src1, Operand(src2), s, cond);
765 }
766
767 void rsb(Register dst, Register src1, const Operand& src2,
768 SBit s = LeaveCC, Condition cond = al);
769
770 void add(Register dst, Register src1, const Operand& src2,
771 SBit s = LeaveCC, Condition cond = al);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100772 void add(Register dst, Register src1, Register src2,
773 SBit s = LeaveCC, Condition cond = al) {
774 add(dst, src1, Operand(src2), s, cond);
775 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000776
777 void adc(Register dst, Register src1, const Operand& src2,
778 SBit s = LeaveCC, Condition cond = al);
779
780 void sbc(Register dst, Register src1, const Operand& src2,
781 SBit s = LeaveCC, Condition cond = al);
782
783 void rsc(Register dst, Register src1, const Operand& src2,
784 SBit s = LeaveCC, Condition cond = al);
785
786 void tst(Register src1, const Operand& src2, Condition cond = al);
787 void tst(Register src1, Register src2, Condition cond = al) {
788 tst(src1, Operand(src2), cond);
789 }
790
791 void teq(Register src1, const Operand& src2, Condition cond = al);
792
793 void cmp(Register src1, const Operand& src2, Condition cond = al);
794 void cmp(Register src1, Register src2, Condition cond = al) {
795 cmp(src1, Operand(src2), cond);
796 }
797
798 void cmn(Register src1, const Operand& src2, Condition cond = al);
799
800 void orr(Register dst, Register src1, const Operand& src2,
801 SBit s = LeaveCC, Condition cond = al);
802 void orr(Register dst, Register src1, Register src2,
803 SBit s = LeaveCC, Condition cond = al) {
804 orr(dst, src1, Operand(src2), s, cond);
805 }
806
807 void mov(Register dst, const Operand& src,
808 SBit s = LeaveCC, Condition cond = al);
809 void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
810 mov(dst, Operand(src), s, cond);
811 }
812
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100813 // ARMv7 instructions for loading a 32 bit immediate in two instructions.
814 // This may actually emit a different mov instruction, but on an ARMv7 it
815 // is guaranteed to only emit one instruction.
816 void movw(Register reg, uint32_t immediate, Condition cond = al);
817 // The constant for movt should be in the range 0-0xffff.
818 void movt(Register reg, uint32_t immediate, Condition cond = al);
819
Steve Blocka7e24c12009-10-30 11:49:00 +0000820 void bic(Register dst, Register src1, const Operand& src2,
821 SBit s = LeaveCC, Condition cond = al);
822
823 void mvn(Register dst, const Operand& src,
824 SBit s = LeaveCC, Condition cond = al);
825
826 // Multiply instructions
827
828 void mla(Register dst, Register src1, Register src2, Register srcA,
829 SBit s = LeaveCC, Condition cond = al);
830
831 void mul(Register dst, Register src1, Register src2,
832 SBit s = LeaveCC, Condition cond = al);
833
834 void smlal(Register dstL, Register dstH, Register src1, Register src2,
835 SBit s = LeaveCC, Condition cond = al);
836
837 void smull(Register dstL, Register dstH, Register src1, Register src2,
838 SBit s = LeaveCC, Condition cond = al);
839
840 void umlal(Register dstL, Register dstH, Register src1, Register src2,
841 SBit s = LeaveCC, Condition cond = al);
842
843 void umull(Register dstL, Register dstH, Register src1, Register src2,
844 SBit s = LeaveCC, Condition cond = al);
845
846 // Miscellaneous arithmetic instructions
847
848 void clz(Register dst, Register src, Condition cond = al); // v5 and above
849
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100850 // Saturating instructions. v6 and above.
851
852 // Unsigned saturate.
853 //
854 // Saturate an optionally shifted signed value to an unsigned range.
855 //
856 // usat dst, #satpos, src
857 // usat dst, #satpos, src, lsl #sh
858 // usat dst, #satpos, src, asr #sh
859 //
860 // Register dst will contain:
861 //
862 // 0, if s < 0
863 // (1 << satpos) - 1, if s > ((1 << satpos) - 1)
864 // s, otherwise
865 //
866 // where s is the contents of src after shifting (if used.)
867 void usat(Register dst, int satpos, const Operand& src, Condition cond = al);
868
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100869 // Bitfield manipulation instructions. v7 and above.
870
871 void ubfx(Register dst, Register src, int lsb, int width,
872 Condition cond = al);
873
874 void sbfx(Register dst, Register src, int lsb, int width,
875 Condition cond = al);
876
877 void bfc(Register dst, int lsb, int width, Condition cond = al);
878
879 void bfi(Register dst, Register src, int lsb, int width,
880 Condition cond = al);
881
Steve Blocka7e24c12009-10-30 11:49:00 +0000882 // Status register access instructions
883
884 void mrs(Register dst, SRegister s, Condition cond = al);
885 void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al);
886
887 // Load/Store instructions
888 void ldr(Register dst, const MemOperand& src, Condition cond = al);
889 void str(Register src, const MemOperand& dst, Condition cond = al);
890 void ldrb(Register dst, const MemOperand& src, Condition cond = al);
891 void strb(Register src, const MemOperand& dst, Condition cond = al);
892 void ldrh(Register dst, const MemOperand& src, Condition cond = al);
893 void strh(Register src, const MemOperand& dst, Condition cond = al);
894 void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
895 void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
Leon Clarkef7060e22010-06-03 12:02:55 +0100896 void ldrd(Register dst1,
897 Register dst2,
898 const MemOperand& src, Condition cond = al);
899 void strd(Register src1,
900 Register src2,
901 const MemOperand& dst, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000902
903 // Load/Store multiple instructions
904 void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
905 void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
906
Steve Blocka7e24c12009-10-30 11:49:00 +0000907 // Exception-generating instructions and debugging support
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800908 static const int kDefaultStopCode = -1;
909 void stop(const char* msg,
910 Condition cond = al,
911 int32_t code = kDefaultStopCode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000912
913 void bkpt(uint32_t imm16); // v5 and above
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800914 void svc(uint32_t imm24, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000915
916 // Coprocessor instructions
917
918 void cdp(Coprocessor coproc, int opcode_1,
919 CRegister crd, CRegister crn, CRegister crm,
920 int opcode_2, Condition cond = al);
921
922 void cdp2(Coprocessor coproc, int opcode_1,
923 CRegister crd, CRegister crn, CRegister crm,
924 int opcode_2); // v5 and above
925
926 void mcr(Coprocessor coproc, int opcode_1,
927 Register rd, CRegister crn, CRegister crm,
928 int opcode_2 = 0, Condition cond = al);
929
930 void mcr2(Coprocessor coproc, int opcode_1,
931 Register rd, CRegister crn, CRegister crm,
932 int opcode_2 = 0); // v5 and above
933
934 void mrc(Coprocessor coproc, int opcode_1,
935 Register rd, CRegister crn, CRegister crm,
936 int opcode_2 = 0, Condition cond = al);
937
938 void mrc2(Coprocessor coproc, int opcode_1,
939 Register rd, CRegister crn, CRegister crm,
940 int opcode_2 = 0); // v5 and above
941
942 void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src,
943 LFlag l = Short, Condition cond = al);
944 void ldc(Coprocessor coproc, CRegister crd, Register base, int option,
945 LFlag l = Short, Condition cond = al);
946
947 void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
948 LFlag l = Short); // v5 and above
949 void ldc2(Coprocessor coproc, CRegister crd, Register base, int option,
950 LFlag l = Short); // v5 and above
951
952 void stc(Coprocessor coproc, CRegister crd, const MemOperand& dst,
953 LFlag l = Short, Condition cond = al);
954 void stc(Coprocessor coproc, CRegister crd, Register base, int option,
955 LFlag l = Short, Condition cond = al);
956
957 void stc2(Coprocessor coproc, CRegister crd, const MemOperand& dst,
958 LFlag l = Short); // v5 and above
959 void stc2(Coprocessor coproc, CRegister crd, Register base, int option,
960 LFlag l = Short); // v5 and above
961
Steve Blockd0582a62009-12-15 09:54:21 +0000962 // Support for VFP.
963 // All these APIs support S0 to S31 and D0 to D15.
964 // Currently these APIs do not support extended D registers, i.e, D16 to D31.
965 // However, some simple modifications can allow
966 // these APIs to support D16 to D31.
967
Leon Clarked91b9f72010-01-27 17:25:45 +0000968 void vldr(const DwVfpRegister dst,
969 const Register base,
970 int offset, // Offset must be a multiple of 4.
971 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +0100972
973 void vldr(const SwVfpRegister dst,
974 const Register base,
975 int offset, // Offset must be a multiple of 4.
976 const Condition cond = al);
977
Leon Clarked91b9f72010-01-27 17:25:45 +0000978 void vstr(const DwVfpRegister src,
979 const Register base,
980 int offset, // Offset must be a multiple of 4.
981 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +0100982
Iain Merrick75681382010-08-19 15:07:18 +0100983 void vstr(const SwVfpRegister src,
984 const Register base,
985 int offset, // Offset must be a multiple of 4.
986 const Condition cond = al);
987
Steve Block8defd9f2010-07-08 12:39:36 +0100988 void vmov(const DwVfpRegister dst,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100989 double imm,
990 const Condition cond = al);
991 void vmov(const SwVfpRegister dst,
992 const SwVfpRegister src,
993 const Condition cond = al);
994 void vmov(const DwVfpRegister dst,
Steve Block8defd9f2010-07-08 12:39:36 +0100995 const DwVfpRegister src,
996 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +0000997 void vmov(const DwVfpRegister dst,
998 const Register src1,
Steve Blockd0582a62009-12-15 09:54:21 +0000999 const Register src2,
Leon Clarkee46be812010-01-19 14:06:41 +00001000 const Condition cond = al);
1001 void vmov(const Register dst1,
1002 const Register dst2,
1003 const DwVfpRegister src,
1004 const Condition cond = al);
1005 void vmov(const SwVfpRegister dst,
1006 const Register src,
1007 const Condition cond = al);
1008 void vmov(const Register dst,
1009 const SwVfpRegister src,
1010 const Condition cond = al);
Russell Brenner90bac252010-11-18 13:33:46 -08001011 enum ConversionMode {
1012 FPSCRRounding = 0,
1013 RoundToZero = 1
1014 };
Steve Block6ded16b2010-05-10 14:33:55 +01001015 void vcvt_f64_s32(const DwVfpRegister dst,
1016 const SwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001017 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001018 const Condition cond = al);
1019 void vcvt_f32_s32(const SwVfpRegister dst,
1020 const SwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001021 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001022 const Condition cond = al);
1023 void vcvt_f64_u32(const DwVfpRegister dst,
1024 const SwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001025 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001026 const Condition cond = al);
1027 void vcvt_s32_f64(const SwVfpRegister dst,
1028 const DwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001029 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001030 const Condition cond = al);
1031 void vcvt_u32_f64(const SwVfpRegister dst,
1032 const DwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001033 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001034 const Condition cond = al);
1035 void vcvt_f64_f32(const DwVfpRegister dst,
1036 const SwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001037 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001038 const Condition cond = al);
1039 void vcvt_f32_f64(const SwVfpRegister dst,
1040 const DwVfpRegister src,
Russell Brenner90bac252010-11-18 13:33:46 -08001041 ConversionMode mode = RoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +01001042 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001043
1044 void vadd(const DwVfpRegister dst,
1045 const DwVfpRegister src1,
1046 const DwVfpRegister src2,
1047 const Condition cond = al);
1048 void vsub(const DwVfpRegister dst,
1049 const DwVfpRegister src1,
1050 const DwVfpRegister src2,
1051 const Condition cond = al);
1052 void vmul(const DwVfpRegister dst,
1053 const DwVfpRegister src1,
1054 const DwVfpRegister src2,
1055 const Condition cond = al);
1056 void vdiv(const DwVfpRegister dst,
1057 const DwVfpRegister src1,
1058 const DwVfpRegister src2,
1059 const Condition cond = al);
1060 void vcmp(const DwVfpRegister src1,
1061 const DwVfpRegister src2,
Steve Blockd0582a62009-12-15 09:54:21 +00001062 const SBit s = LeaveCC,
1063 const Condition cond = al);
Iain Merrick75681382010-08-19 15:07:18 +01001064 void vcmp(const DwVfpRegister src1,
1065 const double src2,
1066 const SBit s = LeaveCC,
1067 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001068 void vmrs(const Register dst,
1069 const Condition cond = al);
Russell Brenner90bac252010-11-18 13:33:46 -08001070 void vmsr(const Register dst,
1071 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +01001072 void vsqrt(const DwVfpRegister dst,
1073 const DwVfpRegister src,
1074 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001075
Steve Blocka7e24c12009-10-30 11:49:00 +00001076 // Pseudo instructions
Steve Block6ded16b2010-05-10 14:33:55 +01001077 void nop(int type = 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001078
1079 void push(Register src, Condition cond = al) {
1080 str(src, MemOperand(sp, 4, NegPreIndex), cond);
1081 }
1082
1083 void pop(Register dst, Condition cond = al) {
1084 ldr(dst, MemOperand(sp, 4, PostIndex), cond);
1085 }
1086
1087 void pop() {
1088 add(sp, sp, Operand(kPointerSize));
1089 }
1090
Steve Blocka7e24c12009-10-30 11:49:00 +00001091 // Jump unconditionally to given label.
1092 void jmp(Label* L) { b(L, al); }
1093
1094 // Check the code size generated from label to here.
1095 int InstructionsGeneratedSince(Label* l) {
1096 return (pc_offset() - l->pos()) / kInstrSize;
1097 }
1098
Steve Blockd0582a62009-12-15 09:54:21 +00001099 // Check whether an immediate fits an addressing mode 1 instruction.
1100 bool ImmediateFitsAddrMode1Instruction(int32_t imm32);
1101
Steve Block6ded16b2010-05-10 14:33:55 +01001102 // Class for scoping postponing the constant pool generation.
1103 class BlockConstPoolScope {
1104 public:
1105 explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) {
1106 assem_->StartBlockConstPool();
1107 }
1108 ~BlockConstPoolScope() {
1109 assem_->EndBlockConstPool();
1110 }
1111
1112 private:
1113 Assembler* assem_;
1114
1115 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstPoolScope);
1116 };
1117
Steve Blockd0582a62009-12-15 09:54:21 +00001118 // Postpone the generation of the constant pool for the specified number of
1119 // instructions.
1120 void BlockConstPoolFor(int instructions);
1121
Steve Blocka7e24c12009-10-30 11:49:00 +00001122 // Debugging
1123
1124 // Mark address of the ExitJSFrame code.
1125 void RecordJSReturn();
1126
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001127 // Mark address of a debug break slot.
1128 void RecordDebugBreakSlot();
1129
Steve Blocka7e24c12009-10-30 11:49:00 +00001130 // Record a comment relocation entry that can be used by a disassembler.
1131 // Use --debug_code to enable.
1132 void RecordComment(const char* msg);
1133
Steve Blocka7e24c12009-10-30 11:49:00 +00001134 int pc_offset() const { return pc_ - buffer_; }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001135
1136 PositionsRecorder* positions_recorder() { return &positions_recorder_; }
Steve Block6ded16b2010-05-10 14:33:55 +01001137
Leon Clarkef7060e22010-06-03 12:02:55 +01001138 bool can_peephole_optimize(int instructions) {
1139 if (!FLAG_peephole_optimization) return false;
1140 if (last_bound_pos_ > pc_offset() - instructions * kInstrSize) return false;
1141 return reloc_info_writer.last_pc() <= pc_ - instructions * kInstrSize;
1142 }
1143
Steve Block6ded16b2010-05-10 14:33:55 +01001144 // Read/patch instructions
1145 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
1146 static void instr_at_put(byte* pc, Instr instr) {
1147 *reinterpret_cast<Instr*>(pc) = instr;
1148 }
1149 static bool IsNop(Instr instr, int type = 0);
1150 static bool IsBranch(Instr instr);
1151 static int GetBranchOffset(Instr instr);
1152 static bool IsLdrRegisterImmediate(Instr instr);
1153 static int GetLdrRegisterImmediateOffset(Instr instr);
1154 static Instr SetLdrRegisterImmediateOffset(Instr instr, int offset);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001155 static bool IsStrRegisterImmediate(Instr instr);
1156 static Instr SetStrRegisterImmediateOffset(Instr instr, int offset);
1157 static bool IsAddRegisterImmediate(Instr instr);
1158 static Instr SetAddRegisterImmediateOffset(Instr instr, int offset);
Leon Clarkef7060e22010-06-03 12:02:55 +01001159 static Register GetRd(Instr instr);
1160 static bool IsPush(Instr instr);
1161 static bool IsPop(Instr instr);
1162 static bool IsStrRegFpOffset(Instr instr);
1163 static bool IsLdrRegFpOffset(Instr instr);
1164 static bool IsStrRegFpNegOffset(Instr instr);
1165 static bool IsLdrRegFpNegOffset(Instr instr);
Steve Block6ded16b2010-05-10 14:33:55 +01001166
Steve Blocka7e24c12009-10-30 11:49:00 +00001167
1168 protected:
1169 int buffer_space() const { return reloc_info_writer.pos() - pc_; }
1170
1171 // Read/patch instructions
Steve Blocka7e24c12009-10-30 11:49:00 +00001172 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
1173 void instr_at_put(int pos, Instr instr) {
1174 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
1175 }
1176
1177 // Decode branch instruction at pos and return branch target pos
1178 int target_at(int pos);
1179
1180 // Patch branch instruction at pos to branch to given branch target pos
1181 void target_at_put(int pos, int target_pos);
1182
1183 // Check if is time to emit a constant pool for pending reloc info entries
1184 void CheckConstPool(bool force_emit, bool require_jump);
1185
1186 // Block the emission of the constant pool before pc_offset
1187 void BlockConstPoolBefore(int pc_offset) {
1188 if (no_const_pool_before_ < pc_offset) no_const_pool_before_ = pc_offset;
1189 }
1190
Steve Block6ded16b2010-05-10 14:33:55 +01001191 void StartBlockConstPool() {
1192 const_pool_blocked_nesting_++;
1193 }
1194 void EndBlockConstPool() {
1195 const_pool_blocked_nesting_--;
1196 }
Steve Block8defd9f2010-07-08 12:39:36 +01001197 bool is_const_pool_blocked() const { return const_pool_blocked_nesting_ > 0; }
Steve Block6ded16b2010-05-10 14:33:55 +01001198
Steve Blocka7e24c12009-10-30 11:49:00 +00001199 private:
1200 // Code buffer:
1201 // The buffer into which code and relocation info are generated.
1202 byte* buffer_;
1203 int buffer_size_;
1204 // True if the assembler owns the buffer, false if buffer is external.
1205 bool own_buffer_;
1206
1207 // Buffer size and constant pool distance are checked together at regular
1208 // intervals of kBufferCheckInterval emitted bytes
1209 static const int kBufferCheckInterval = 1*KB/2;
1210 int next_buffer_check_; // pc offset of next buffer check
1211
1212 // Code generation
1213 // The relocation writer's position is at least kGap bytes below the end of
1214 // the generated instructions. This is so that multi-instruction sequences do
1215 // not have to check for overflow. The same is true for writes of large
1216 // relocation info entries.
1217 static const int kGap = 32;
1218 byte* pc_; // the program counter; moves forward
1219
1220 // Constant pool generation
1221 // Pools are emitted in the instruction stream, preferably after unconditional
1222 // jumps or after returns from functions (in dead code locations).
1223 // If a long code sequence does not contain unconditional jumps, it is
1224 // necessary to emit the constant pool before the pool gets too far from the
1225 // location it is accessed from. In this case, we emit a jump over the emitted
1226 // constant pool.
1227 // Constants in the pool may be addresses of functions that gets relocated;
1228 // if so, a relocation info entry is associated to the constant pool entry.
1229
1230 // Repeated checking whether the constant pool should be emitted is rather
1231 // expensive. By default we only check again once a number of instructions
1232 // has been generated. That also means that the sizing of the buffers is not
1233 // an exact science, and that we rely on some slop to not overrun buffers.
1234 static const int kCheckConstIntervalInst = 32;
1235 static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize;
1236
1237
1238 // Pools are emitted after function return and in dead code at (more or less)
1239 // regular intervals of kDistBetweenPools bytes
1240 static const int kDistBetweenPools = 1*KB;
1241
1242 // Constants in pools are accessed via pc relative addressing, which can
1243 // reach +/-4KB thereby defining a maximum distance between the instruction
1244 // and the accessed constant. We satisfy this constraint by limiting the
1245 // distance between pools.
1246 static const int kMaxDistBetweenPools = 4*KB - 2*kBufferCheckInterval;
1247
Steve Block6ded16b2010-05-10 14:33:55 +01001248 // Emission of the constant pool may be blocked in some code sequences.
1249 int const_pool_blocked_nesting_; // Block emission if this is not zero.
1250 int no_const_pool_before_; // Block emission before this pc offset.
Steve Blocka7e24c12009-10-30 11:49:00 +00001251
1252 // Keep track of the last emitted pool to guarantee a maximal distance
1253 int last_const_pool_end_; // pc offset following the last constant pool
1254
1255 // Relocation info generation
1256 // Each relocation is encoded as a variable size value
1257 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1258 RelocInfoWriter reloc_info_writer;
1259 // Relocation info records are also used during code generation as temporary
1260 // containers for constants and code target addresses until they are emitted
1261 // to the constant pool. These pending relocation info records are temporarily
1262 // stored in a separate buffer until a constant pool is emitted.
1263 // If every instruction in a long sequence is accessing the pool, we need one
1264 // pending relocation entry per instruction.
1265 static const int kMaxNumPRInfo = kMaxDistBetweenPools/kInstrSize;
1266 RelocInfo prinfo_[kMaxNumPRInfo]; // the buffer of pending relocation info
1267 int num_prinfo_; // number of pending reloc info entries in the buffer
1268
1269 // The bound position, before this we cannot do instruction elimination.
1270 int last_bound_pos_;
1271
Steve Blocka7e24c12009-10-30 11:49:00 +00001272 // Code emission
1273 inline void CheckBuffer();
1274 void GrowBuffer();
1275 inline void emit(Instr x);
1276
1277 // Instruction generation
1278 void addrmod1(Instr instr, Register rn, Register rd, const Operand& x);
1279 void addrmod2(Instr instr, Register rd, const MemOperand& x);
1280 void addrmod3(Instr instr, Register rd, const MemOperand& x);
1281 void addrmod4(Instr instr, Register rn, RegList rl);
1282 void addrmod5(Instr instr, CRegister crd, const MemOperand& x);
1283
1284 // Labels
1285 void print(Label* L);
1286 void bind_to(Label* L, int pos);
1287 void link_to(Label* L, Label* appendix);
1288 void next(Label* L);
1289
1290 // Record reloc info for current pc_
1291 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
1292
1293 friend class RegExpMacroAssemblerARM;
1294 friend class RelocInfo;
1295 friend class CodePatcher;
Steve Block6ded16b2010-05-10 14:33:55 +01001296 friend class BlockConstPoolScope;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001297
1298 PositionsRecorder positions_recorder_;
1299 friend class PositionsRecorder;
1300 friend class EnsureSpace;
Steve Blocka7e24c12009-10-30 11:49:00 +00001301};
1302
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001303
1304class EnsureSpace BASE_EMBEDDED {
1305 public:
1306 explicit EnsureSpace(Assembler* assembler) {
1307 assembler->CheckBuffer();
1308 }
1309};
1310
1311
Steve Blocka7e24c12009-10-30 11:49:00 +00001312} } // namespace v8::internal
1313
1314#endif // V8_ARM_ASSEMBLER_ARM_H_