blob: 869227a7a8e2c850fff94cf98dc987ae008f691a [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 {
72 bool is_valid() const { return 0 <= code_ && code_ < 16; }
73 bool is(Register reg) const { return code_ == reg.code_; }
74 int code() const {
75 ASSERT(is_valid());
76 return code_;
77 }
78 int bit() const {
79 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 {
113 bool is_valid() const { return 0 <= code_ && code_ < 32; }
114 bool is(SwVfpRegister reg) const { return code_ == reg.code_; }
115 int code() const {
116 ASSERT(is_valid());
117 return code_;
118 }
119 int bit() const {
120 ASSERT(is_valid());
121 return 1 << code_;
122 }
123
124 int code_;
125};
126
127
128// Double word VFP register.
129struct DwVfpRegister {
130 // Supporting d0 to d15, can be later extended to d31.
131 bool is_valid() const { return 0 <= code_ && code_ < 16; }
132 bool is(DwVfpRegister reg) const { return code_ == reg.code_; }
133 int code() const {
134 ASSERT(is_valid());
135 return code_;
136 }
137 int bit() const {
138 ASSERT(is_valid());
139 return 1 << code_;
140 }
141
142 int code_;
143};
144
145
Steve Block6ded16b2010-05-10 14:33:55 +0100146// Support for the VFP registers s0 to s31 (d0 to d15).
Leon Clarkee46be812010-01-19 14:06:41 +0000147// Note that "s(N):s(N+1)" is the same as "d(N/2)".
Steve Block6ded16b2010-05-10 14:33:55 +0100148const SwVfpRegister s0 = { 0 };
149const SwVfpRegister s1 = { 1 };
150const SwVfpRegister s2 = { 2 };
151const SwVfpRegister s3 = { 3 };
152const SwVfpRegister s4 = { 4 };
153const SwVfpRegister s5 = { 5 };
154const SwVfpRegister s6 = { 6 };
155const SwVfpRegister s7 = { 7 };
156const SwVfpRegister s8 = { 8 };
157const SwVfpRegister s9 = { 9 };
158const SwVfpRegister s10 = { 10 };
159const SwVfpRegister s11 = { 11 };
160const SwVfpRegister s12 = { 12 };
161const SwVfpRegister s13 = { 13 };
162const SwVfpRegister s14 = { 14 };
163const SwVfpRegister s15 = { 15 };
164const SwVfpRegister s16 = { 16 };
165const SwVfpRegister s17 = { 17 };
166const SwVfpRegister s18 = { 18 };
167const SwVfpRegister s19 = { 19 };
168const SwVfpRegister s20 = { 20 };
169const SwVfpRegister s21 = { 21 };
170const SwVfpRegister s22 = { 22 };
171const SwVfpRegister s23 = { 23 };
172const SwVfpRegister s24 = { 24 };
173const SwVfpRegister s25 = { 25 };
174const SwVfpRegister s26 = { 26 };
175const SwVfpRegister s27 = { 27 };
176const SwVfpRegister s28 = { 28 };
177const SwVfpRegister s29 = { 29 };
178const SwVfpRegister s30 = { 30 };
179const SwVfpRegister s31 = { 31 };
Leon Clarkee46be812010-01-19 14:06:41 +0000180
Steve Block6ded16b2010-05-10 14:33:55 +0100181const DwVfpRegister d0 = { 0 };
182const DwVfpRegister d1 = { 1 };
183const DwVfpRegister d2 = { 2 };
184const DwVfpRegister d3 = { 3 };
185const DwVfpRegister d4 = { 4 };
186const DwVfpRegister d5 = { 5 };
187const DwVfpRegister d6 = { 6 };
188const DwVfpRegister d7 = { 7 };
189const DwVfpRegister d8 = { 8 };
190const DwVfpRegister d9 = { 9 };
191const DwVfpRegister d10 = { 10 };
192const DwVfpRegister d11 = { 11 };
193const DwVfpRegister d12 = { 12 };
194const DwVfpRegister d13 = { 13 };
195const DwVfpRegister d14 = { 14 };
196const DwVfpRegister d15 = { 15 };
Leon Clarkee46be812010-01-19 14:06:41 +0000197
Steve Blocka7e24c12009-10-30 11:49:00 +0000198
199// Coprocessor register
200struct CRegister {
201 bool is_valid() const { return 0 <= code_ && code_ < 16; }
202 bool is(CRegister creg) const { return code_ == creg.code_; }
203 int code() const {
204 ASSERT(is_valid());
205 return code_;
206 }
207 int bit() const {
208 ASSERT(is_valid());
209 return 1 << code_;
210 }
211
Andrei Popescu31002712010-02-23 13:46:05 +0000212 // Unfortunately we can't make this private in a struct.
Steve Blocka7e24c12009-10-30 11:49:00 +0000213 int code_;
214};
215
216
Steve Block6ded16b2010-05-10 14:33:55 +0100217const CRegister no_creg = { -1 };
218
219const CRegister cr0 = { 0 };
220const CRegister cr1 = { 1 };
221const CRegister cr2 = { 2 };
222const CRegister cr3 = { 3 };
223const CRegister cr4 = { 4 };
224const CRegister cr5 = { 5 };
225const CRegister cr6 = { 6 };
226const CRegister cr7 = { 7 };
227const CRegister cr8 = { 8 };
228const CRegister cr9 = { 9 };
229const CRegister cr10 = { 10 };
230const CRegister cr11 = { 11 };
231const CRegister cr12 = { 12 };
232const CRegister cr13 = { 13 };
233const CRegister cr14 = { 14 };
234const CRegister cr15 = { 15 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000235
236
237// Coprocessor number
238enum Coprocessor {
239 p0 = 0,
240 p1 = 1,
241 p2 = 2,
242 p3 = 3,
243 p4 = 4,
244 p5 = 5,
245 p6 = 6,
246 p7 = 7,
247 p8 = 8,
248 p9 = 9,
249 p10 = 10,
250 p11 = 11,
251 p12 = 12,
252 p13 = 13,
253 p14 = 14,
254 p15 = 15
255};
256
257
Andrei Popescu31002712010-02-23 13:46:05 +0000258// Condition field in instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +0000259enum Condition {
260 eq = 0 << 28, // Z set equal.
261 ne = 1 << 28, // Z clear not equal.
262 nz = 1 << 28, // Z clear not zero.
263 cs = 2 << 28, // C set carry set.
264 hs = 2 << 28, // C set unsigned higher or same.
265 cc = 3 << 28, // C clear carry clear.
266 lo = 3 << 28, // C clear unsigned lower.
267 mi = 4 << 28, // N set negative.
268 pl = 5 << 28, // N clear positive or zero.
269 vs = 6 << 28, // V set overflow.
270 vc = 7 << 28, // V clear no overflow.
271 hi = 8 << 28, // C set, Z clear unsigned higher.
272 ls = 9 << 28, // C clear or Z set unsigned lower or same.
273 ge = 10 << 28, // N == V greater or equal.
274 lt = 11 << 28, // N != V less than.
275 gt = 12 << 28, // Z clear, N == V greater than.
276 le = 13 << 28, // Z set or N != V less then or equal
277 al = 14 << 28 // always.
278};
279
280
281// Returns the equivalent of !cc.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100282inline Condition NegateCondition(Condition cc) {
283 ASSERT(cc != al);
284 return static_cast<Condition>(cc ^ ne);
285}
Steve Blocka7e24c12009-10-30 11:49:00 +0000286
287
288// Corresponds to transposing the operands of a comparison.
289inline Condition ReverseCondition(Condition cc) {
290 switch (cc) {
291 case lo:
292 return hi;
293 case hi:
294 return lo;
295 case hs:
296 return ls;
297 case ls:
298 return hs;
299 case lt:
300 return gt;
301 case gt:
302 return lt;
303 case ge:
304 return le;
305 case le:
306 return ge;
307 default:
308 return cc;
309 };
310}
311
312
313// Branch hints are not used on the ARM. They are defined so that they can
314// appear in shared function signatures, but will be ignored in ARM
315// implementations.
316enum Hint { no_hint };
317
318// Hints are not used on the arm. Negating is trivial.
319inline Hint NegateHint(Hint ignored) { return no_hint; }
320
321
322// -----------------------------------------------------------------------------
323// Addressing modes and instruction variants
324
325// Shifter operand shift operation
326enum ShiftOp {
327 LSL = 0 << 5,
328 LSR = 1 << 5,
329 ASR = 2 << 5,
330 ROR = 3 << 5,
331 RRX = -1
332};
333
334
335// Condition code updating mode
336enum SBit {
337 SetCC = 1 << 20, // set condition code
338 LeaveCC = 0 << 20 // leave condition code unchanged
339};
340
341
342// Status register selection
343enum SRegister {
344 CPSR = 0 << 22,
345 SPSR = 1 << 22
346};
347
348
349// Status register fields
350enum SRegisterField {
351 CPSR_c = CPSR | 1 << 16,
352 CPSR_x = CPSR | 1 << 17,
353 CPSR_s = CPSR | 1 << 18,
354 CPSR_f = CPSR | 1 << 19,
355 SPSR_c = SPSR | 1 << 16,
356 SPSR_x = SPSR | 1 << 17,
357 SPSR_s = SPSR | 1 << 18,
358 SPSR_f = SPSR | 1 << 19
359};
360
361// Status register field mask (or'ed SRegisterField enum values)
362typedef uint32_t SRegisterFieldMask;
363
364
365// Memory operand addressing mode
366enum AddrMode {
367 // bit encoding P U W
368 Offset = (8|4|0) << 21, // offset (without writeback to base)
369 PreIndex = (8|4|1) << 21, // pre-indexed addressing with writeback
370 PostIndex = (0|4|0) << 21, // post-indexed addressing with writeback
371 NegOffset = (8|0|0) << 21, // negative offset (without writeback to base)
372 NegPreIndex = (8|0|1) << 21, // negative pre-indexed with writeback
373 NegPostIndex = (0|0|0) << 21 // negative post-indexed with writeback
374};
375
376
377// Load/store multiple addressing mode
378enum BlockAddrMode {
379 // bit encoding P U W
380 da = (0|0|0) << 21, // decrement after
381 ia = (0|4|0) << 21, // increment after
382 db = (8|0|0) << 21, // decrement before
383 ib = (8|4|0) << 21, // increment before
384 da_w = (0|0|1) << 21, // decrement after with writeback to base
385 ia_w = (0|4|1) << 21, // increment after with writeback to base
386 db_w = (8|0|1) << 21, // decrement before with writeback to base
387 ib_w = (8|4|1) << 21 // increment before with writeback to base
388};
389
390
391// Coprocessor load/store operand size
392enum LFlag {
393 Long = 1 << 22, // long load/store coprocessor
394 Short = 0 << 22 // short load/store coprocessor
395};
396
397
398// -----------------------------------------------------------------------------
399// Machine instruction Operands
400
401// Class Operand represents a shifter operand in data processing instructions
402class Operand BASE_EMBEDDED {
403 public:
404 // immediate
405 INLINE(explicit Operand(int32_t immediate,
406 RelocInfo::Mode rmode = RelocInfo::NONE));
407 INLINE(explicit Operand(const ExternalReference& f));
408 INLINE(explicit Operand(const char* s));
Steve Blocka7e24c12009-10-30 11:49:00 +0000409 explicit Operand(Handle<Object> handle);
410 INLINE(explicit Operand(Smi* value));
411
412 // rm
413 INLINE(explicit Operand(Register rm));
414
415 // rm <shift_op> shift_imm
416 explicit Operand(Register rm, ShiftOp shift_op, int shift_imm);
417
418 // rm <shift_op> rs
419 explicit Operand(Register rm, ShiftOp shift_op, Register rs);
420
421 // Return true if this is a register operand.
422 INLINE(bool is_reg() const);
423
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100424 // Return true of this operand fits in one instruction so that no
425 // 2-instruction solution with a load into the ip register is necessary.
426 bool is_single_instruction() const;
427
428 inline int32_t immediate() const {
429 ASSERT(!rm_.is_valid());
430 return imm32_;
431 }
432
Steve Blocka7e24c12009-10-30 11:49:00 +0000433 Register rm() const { return rm_; }
434
435 private:
436 Register rm_;
437 Register rs_;
438 ShiftOp shift_op_;
439 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
440 int32_t imm32_; // valid if rm_ == no_reg
441 RelocInfo::Mode rmode_;
442
443 friend class Assembler;
444};
445
446
447// Class MemOperand represents a memory operand in load and store instructions
448class MemOperand BASE_EMBEDDED {
449 public:
450 // [rn +/- offset] Offset/NegOffset
451 // [rn +/- offset]! PreIndex/NegPreIndex
452 // [rn], +/- offset PostIndex/NegPostIndex
453 // offset is any signed 32-bit value; offset is first loaded to register ip if
454 // it does not fit the addressing mode (12-bit unsigned and sign bit)
455 explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset);
456
457 // [rn +/- rm] Offset/NegOffset
458 // [rn +/- rm]! PreIndex/NegPreIndex
459 // [rn], +/- rm PostIndex/NegPostIndex
460 explicit MemOperand(Register rn, Register rm, AddrMode am = Offset);
461
462 // [rn +/- rm <shift_op> shift_imm] Offset/NegOffset
463 // [rn +/- rm <shift_op> shift_imm]! PreIndex/NegPreIndex
464 // [rn], +/- rm <shift_op> shift_imm PostIndex/NegPostIndex
465 explicit MemOperand(Register rn, Register rm,
466 ShiftOp shift_op, int shift_imm, AddrMode am = Offset);
467
Kristian Monsen25f61362010-05-21 11:50:48 +0100468 void set_offset(int32_t offset) {
469 ASSERT(rm_.is(no_reg));
470 offset_ = offset;
471 }
472
473 uint32_t offset() {
474 ASSERT(rm_.is(no_reg));
475 return offset_;
476 }
477
Leon Clarkef7060e22010-06-03 12:02:55 +0100478 Register rn() const { return rn_; }
479 Register rm() const { return rm_; }
Kristian Monsen25f61362010-05-21 11:50:48 +0100480
Steve Blocka7e24c12009-10-30 11:49:00 +0000481 private:
482 Register rn_; // base
483 Register rm_; // register offset
484 int32_t offset_; // valid if rm_ == no_reg
485 ShiftOp shift_op_;
486 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
487 AddrMode am_; // bits P, U, and W
488
489 friend class Assembler;
490};
491
Steve Blockd0582a62009-12-15 09:54:21 +0000492// CpuFeatures keeps track of which features are supported by the target CPU.
493// Supported features must be enabled by a Scope before use.
494class CpuFeatures : public AllStatic {
495 public:
496 // Detect features of the target CPU. Set safe defaults if the serializer
497 // is enabled (snapshots must be portable).
498 static void Probe();
499
500 // Check whether a feature is supported by the target CPU.
501 static bool IsSupported(CpuFeature f) {
502 if (f == VFP3 && !FLAG_enable_vfp3) return false;
503 return (supported_ & (1u << f)) != 0;
504 }
505
506 // Check whether a feature is currently enabled.
507 static bool IsEnabled(CpuFeature f) {
508 return (enabled_ & (1u << f)) != 0;
509 }
510
511 // Enable a specified feature within a scope.
512 class Scope BASE_EMBEDDED {
513#ifdef DEBUG
514 public:
515 explicit Scope(CpuFeature f) {
516 ASSERT(CpuFeatures::IsSupported(f));
517 ASSERT(!Serializer::enabled() ||
518 (found_by_runtime_probing_ & (1u << f)) == 0);
519 old_enabled_ = CpuFeatures::enabled_;
520 CpuFeatures::enabled_ |= 1u << f;
521 }
522 ~Scope() { CpuFeatures::enabled_ = old_enabled_; }
523 private:
524 unsigned old_enabled_;
525#else
526 public:
527 explicit Scope(CpuFeature f) {}
528#endif
529 };
530
531 private:
532 static unsigned supported_;
533 static unsigned enabled_;
534 static unsigned found_by_runtime_probing_;
535};
536
Steve Blocka7e24c12009-10-30 11:49:00 +0000537
538typedef int32_t Instr;
539
540
541extern const Instr kMovLrPc;
Steve Block6ded16b2010-05-10 14:33:55 +0100542extern const Instr kLdrPCMask;
Steve Blocka7e24c12009-10-30 11:49:00 +0000543extern const Instr kLdrPCPattern;
Steve Block6ded16b2010-05-10 14:33:55 +0100544extern const Instr kBlxRegMask;
545extern const Instr kBlxRegPattern;
Steve Blocka7e24c12009-10-30 11:49:00 +0000546
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100547extern const Instr kMovMvnMask;
548extern const Instr kMovMvnPattern;
549extern const Instr kMovMvnFlip;
550
551extern const Instr kMovLeaveCCMask;
552extern const Instr kMovLeaveCCPattern;
553extern const Instr kMovwMask;
554extern const Instr kMovwPattern;
555extern const Instr kMovwLeaveCCFlip;
556
557extern const Instr kCmpCmnMask;
558extern const Instr kCmpCmnPattern;
559extern const Instr kCmpCmnFlip;
560
561extern const Instr kALUMask;
562extern const Instr kAddPattern;
563extern const Instr kSubPattern;
564extern const Instr kAndPattern;
565extern const Instr kBicPattern;
566extern const Instr kAddSubFlip;
567extern const Instr kAndBicFlip;
Steve Blocka7e24c12009-10-30 11:49:00 +0000568
569class Assembler : public Malloced {
570 public:
571 // Create an assembler. Instructions and relocation information are emitted
572 // into a buffer, with the instructions starting from the beginning and the
573 // relocation information starting from the end of the buffer. See CodeDesc
574 // for a detailed comment on the layout (globals.h).
575 //
576 // If the provided buffer is NULL, the assembler allocates and grows its own
577 // buffer, and buffer_size determines the initial buffer size. The buffer is
578 // owned by the assembler and deallocated upon destruction of the assembler.
579 //
580 // If the provided buffer is not NULL, the assembler uses the provided buffer
581 // for code generation and assumes its size to be buffer_size. If the buffer
582 // is too small, a fatal error occurs. No deallocation of the buffer is done
583 // upon destruction of the assembler.
584 Assembler(void* buffer, int buffer_size);
585 ~Assembler();
586
587 // GetCode emits any pending (non-emitted) code and fills the descriptor
588 // desc. GetCode() is idempotent; it returns the same result if no other
589 // Assembler functions are invoked in between GetCode() calls.
590 void GetCode(CodeDesc* desc);
591
592 // Label operations & relative jumps (PPUM Appendix D)
593 //
594 // Takes a branch opcode (cc) and a label (L) and generates
595 // either a backward branch or a forward branch and links it
596 // to the label fixup chain. Usage:
597 //
598 // Label L; // unbound label
599 // j(cc, &L); // forward branch to unbound label
600 // bind(&L); // bind label to the current pc
601 // j(cc, &L); // backward branch to bound label
602 // bind(&L); // illegal: a label may be bound only once
603 //
604 // Note: The same Label can be used for forward and backward branches
605 // but it may be bound only once.
606
607 void bind(Label* L); // binds an unbound label L to the current code position
608
609 // Returns the branch offset to the given label from the current code position
610 // Links the label to the current position if it is still unbound
611 // Manages the jump elimination optimization if the second parameter is true.
612 int branch_offset(Label* L, bool jump_elimination_allowed);
613
614 // Puts a labels target address at the given position.
615 // The high 8 bits are set to zero.
616 void label_at_put(Label* L, int at_offset);
617
618 // Return the address in the constant pool of the code target address used by
619 // the branch/call instruction at pc.
620 INLINE(static Address target_address_address_at(Address pc));
621
622 // Read/Modify the code target address in the branch/call instruction at pc.
623 INLINE(static Address target_address_at(Address pc));
624 INLINE(static void set_target_address_at(Address pc, Address target));
625
Steve Blockd0582a62009-12-15 09:54:21 +0000626 // This sets the branch destination (which is in the constant pool on ARM).
627 // This is for calls and branches within generated code.
628 inline static void set_target_at(Address constant_pool_entry, Address target);
629
630 // This sets the branch destination (which is in the constant pool on ARM).
631 // This is for calls and branches to runtime code.
632 inline static void set_external_target_at(Address constant_pool_entry,
633 Address target) {
634 set_target_at(constant_pool_entry, target);
635 }
636
637 // Here we are patching the address in the constant pool, not the actual call
638 // instruction. The address in the constant pool is the same size as a
639 // pointer.
640 static const int kCallTargetSize = kPointerSize;
641 static const int kExternalTargetSize = kPointerSize;
642
Steve Blocka7e24c12009-10-30 11:49:00 +0000643 // Size of an instruction.
644 static const int kInstrSize = sizeof(Instr);
645
646 // Distance between the instruction referring to the address of the call
Steve Block6ded16b2010-05-10 14:33:55 +0100647 // target and the return address.
648#ifdef USE_BLX
649 // Call sequence is:
650 // ldr ip, [pc, #...] @ call address
651 // blx ip
652 // @ return address
653 static const int kCallTargetAddressOffset = 2 * kInstrSize;
654#else
655 // Call sequence is:
656 // mov lr, pc
657 // ldr pc, [pc, #...] @ call address
658 // @ return address
Steve Blocka7e24c12009-10-30 11:49:00 +0000659 static const int kCallTargetAddressOffset = kInstrSize;
Steve Block6ded16b2010-05-10 14:33:55 +0100660#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000661
662 // Distance between start of patched return sequence and the emitted address
663 // to jump to.
Steve Block6ded16b2010-05-10 14:33:55 +0100664#ifdef USE_BLX
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100665 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100666 // ldr ip, [pc, #0] @ emited address and start
667 // blx ip
668 static const int kPatchReturnSequenceAddressOffset = 0 * kInstrSize;
669#else
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100670 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100671 // mov lr, pc @ start of sequence
672 // ldr pc, [pc, #-4] @ emited address
673 static const int kPatchReturnSequenceAddressOffset = kInstrSize;
674#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000675
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100676 // Distance between start of patched debug break slot and the emitted address
677 // to jump to.
678#ifdef USE_BLX
679 // Patched debug break slot code is:
680 // ldr ip, [pc, #0] @ emited address and start
681 // blx ip
682 static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
683#else
684 // Patched debug break slot code is:
685 // mov lr, pc @ start of sequence
686 // ldr pc, [pc, #-4] @ emited address
687 static const int kPatchDebugBreakSlotAddressOffset = kInstrSize;
688#endif
689
Steve Blocka7e24c12009-10-30 11:49:00 +0000690 // Difference between address of current opcode and value read from pc
691 // register.
692 static const int kPcLoadDelta = 8;
693
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100694 static const int kJSReturnSequenceInstructions = 4;
695 static const int kDebugBreakSlotInstructions = 3;
696 static const int kDebugBreakSlotLength =
697 kDebugBreakSlotInstructions * kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +0000698
699 // ---------------------------------------------------------------------------
700 // Code generation
701
702 // Insert the smallest number of nop instructions
703 // possible to align the pc offset to a multiple
704 // of m. m must be a power of 2 (>= 4).
705 void Align(int m);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100706 // Aligns code to something that's optimal for a jump target for the platform.
707 void CodeTargetAlign();
Steve Blocka7e24c12009-10-30 11:49:00 +0000708
709 // Branch instructions
710 void b(int branch_offset, Condition cond = al);
711 void bl(int branch_offset, Condition cond = al);
712 void blx(int branch_offset); // v5 and above
713 void blx(Register target, Condition cond = al); // v5 and above
714 void bx(Register target, Condition cond = al); // v5 and above, plus v4t
715
716 // Convenience branch instructions using labels
717 void b(Label* L, Condition cond = al) {
718 b(branch_offset(L, cond == al), cond);
719 }
720 void b(Condition cond, Label* L) { b(branch_offset(L, cond == al), cond); }
721 void bl(Label* L, Condition cond = al) { bl(branch_offset(L, false), cond); }
722 void bl(Condition cond, Label* L) { bl(branch_offset(L, false), cond); }
723 void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above
724
725 // Data-processing instructions
Andrei Popescu31002712010-02-23 13:46:05 +0000726
Steve Blocka7e24c12009-10-30 11:49:00 +0000727 void and_(Register dst, Register src1, const Operand& src2,
728 SBit s = LeaveCC, Condition cond = al);
729
730 void eor(Register dst, Register src1, const Operand& src2,
731 SBit s = LeaveCC, Condition cond = al);
732
733 void sub(Register dst, Register src1, const Operand& src2,
734 SBit s = LeaveCC, Condition cond = al);
735 void sub(Register dst, Register src1, Register src2,
736 SBit s = LeaveCC, Condition cond = al) {
737 sub(dst, src1, Operand(src2), s, cond);
738 }
739
740 void rsb(Register dst, Register src1, const Operand& src2,
741 SBit s = LeaveCC, Condition cond = al);
742
743 void add(Register dst, Register src1, const Operand& src2,
744 SBit s = LeaveCC, Condition cond = al);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100745 void add(Register dst, Register src1, Register src2,
746 SBit s = LeaveCC, Condition cond = al) {
747 add(dst, src1, Operand(src2), s, cond);
748 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000749
750 void adc(Register dst, Register src1, const Operand& src2,
751 SBit s = LeaveCC, Condition cond = al);
752
753 void sbc(Register dst, Register src1, const Operand& src2,
754 SBit s = LeaveCC, Condition cond = al);
755
756 void rsc(Register dst, Register src1, const Operand& src2,
757 SBit s = LeaveCC, Condition cond = al);
758
759 void tst(Register src1, const Operand& src2, Condition cond = al);
760 void tst(Register src1, Register src2, Condition cond = al) {
761 tst(src1, Operand(src2), cond);
762 }
763
764 void teq(Register src1, const Operand& src2, Condition cond = al);
765
766 void cmp(Register src1, const Operand& src2, Condition cond = al);
767 void cmp(Register src1, Register src2, Condition cond = al) {
768 cmp(src1, Operand(src2), cond);
769 }
770
771 void cmn(Register src1, const Operand& src2, Condition cond = al);
772
773 void orr(Register dst, Register src1, const Operand& src2,
774 SBit s = LeaveCC, Condition cond = al);
775 void orr(Register dst, Register src1, Register src2,
776 SBit s = LeaveCC, Condition cond = al) {
777 orr(dst, src1, Operand(src2), s, cond);
778 }
779
780 void mov(Register dst, const Operand& src,
781 SBit s = LeaveCC, Condition cond = al);
782 void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
783 mov(dst, Operand(src), s, cond);
784 }
785
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100786 // ARMv7 instructions for loading a 32 bit immediate in two instructions.
787 // This may actually emit a different mov instruction, but on an ARMv7 it
788 // is guaranteed to only emit one instruction.
789 void movw(Register reg, uint32_t immediate, Condition cond = al);
790 // The constant for movt should be in the range 0-0xffff.
791 void movt(Register reg, uint32_t immediate, Condition cond = al);
792
Steve Blocka7e24c12009-10-30 11:49:00 +0000793 void bic(Register dst, Register src1, const Operand& src2,
794 SBit s = LeaveCC, Condition cond = al);
795
796 void mvn(Register dst, const Operand& src,
797 SBit s = LeaveCC, Condition cond = al);
798
799 // Multiply instructions
800
801 void mla(Register dst, Register src1, Register src2, Register srcA,
802 SBit s = LeaveCC, Condition cond = al);
803
804 void mul(Register dst, Register src1, Register src2,
805 SBit s = LeaveCC, Condition cond = al);
806
807 void smlal(Register dstL, Register dstH, Register src1, Register src2,
808 SBit s = LeaveCC, Condition cond = al);
809
810 void smull(Register dstL, Register dstH, Register src1, Register src2,
811 SBit s = LeaveCC, Condition cond = al);
812
813 void umlal(Register dstL, Register dstH, Register src1, Register src2,
814 SBit s = LeaveCC, Condition cond = al);
815
816 void umull(Register dstL, Register dstH, Register src1, Register src2,
817 SBit s = LeaveCC, Condition cond = al);
818
819 // Miscellaneous arithmetic instructions
820
821 void clz(Register dst, Register src, Condition cond = al); // v5 and above
822
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100823 // Bitfield manipulation instructions. v7 and above.
824
825 void ubfx(Register dst, Register src, int lsb, int width,
826 Condition cond = al);
827
828 void sbfx(Register dst, Register src, int lsb, int width,
829 Condition cond = al);
830
831 void bfc(Register dst, int lsb, int width, Condition cond = al);
832
833 void bfi(Register dst, Register src, int lsb, int width,
834 Condition cond = al);
835
Steve Blocka7e24c12009-10-30 11:49:00 +0000836 // Status register access instructions
837
838 void mrs(Register dst, SRegister s, Condition cond = al);
839 void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al);
840
841 // Load/Store instructions
842 void ldr(Register dst, const MemOperand& src, Condition cond = al);
843 void str(Register src, const MemOperand& dst, Condition cond = al);
844 void ldrb(Register dst, const MemOperand& src, Condition cond = al);
845 void strb(Register src, const MemOperand& dst, Condition cond = al);
846 void ldrh(Register dst, const MemOperand& src, Condition cond = al);
847 void strh(Register src, const MemOperand& dst, Condition cond = al);
848 void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
849 void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
Leon Clarkef7060e22010-06-03 12:02:55 +0100850 void ldrd(Register dst1,
851 Register dst2,
852 const MemOperand& src, Condition cond = al);
853 void strd(Register src1,
854 Register src2,
855 const MemOperand& dst, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000856
857 // Load/Store multiple instructions
858 void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
859 void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
860
Steve Blocka7e24c12009-10-30 11:49:00 +0000861 // Exception-generating instructions and debugging support
862 void stop(const char* msg);
863
864 void bkpt(uint32_t imm16); // v5 and above
865 void swi(uint32_t imm24, Condition cond = al);
866
867 // Coprocessor instructions
868
869 void cdp(Coprocessor coproc, int opcode_1,
870 CRegister crd, CRegister crn, CRegister crm,
871 int opcode_2, Condition cond = al);
872
873 void cdp2(Coprocessor coproc, int opcode_1,
874 CRegister crd, CRegister crn, CRegister crm,
875 int opcode_2); // v5 and above
876
877 void mcr(Coprocessor coproc, int opcode_1,
878 Register rd, CRegister crn, CRegister crm,
879 int opcode_2 = 0, Condition cond = al);
880
881 void mcr2(Coprocessor coproc, int opcode_1,
882 Register rd, CRegister crn, CRegister crm,
883 int opcode_2 = 0); // v5 and above
884
885 void mrc(Coprocessor coproc, int opcode_1,
886 Register rd, CRegister crn, CRegister crm,
887 int opcode_2 = 0, Condition cond = al);
888
889 void mrc2(Coprocessor coproc, int opcode_1,
890 Register rd, CRegister crn, CRegister crm,
891 int opcode_2 = 0); // v5 and above
892
893 void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src,
894 LFlag l = Short, Condition cond = al);
895 void ldc(Coprocessor coproc, CRegister crd, Register base, int option,
896 LFlag l = Short, Condition cond = al);
897
898 void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
899 LFlag l = Short); // v5 and above
900 void ldc2(Coprocessor coproc, CRegister crd, Register base, int option,
901 LFlag l = Short); // v5 and above
902
903 void stc(Coprocessor coproc, CRegister crd, const MemOperand& dst,
904 LFlag l = Short, Condition cond = al);
905 void stc(Coprocessor coproc, CRegister crd, Register base, int option,
906 LFlag l = Short, Condition cond = al);
907
908 void stc2(Coprocessor coproc, CRegister crd, const MemOperand& dst,
909 LFlag l = Short); // v5 and above
910 void stc2(Coprocessor coproc, CRegister crd, Register base, int option,
911 LFlag l = Short); // v5 and above
912
Steve Blockd0582a62009-12-15 09:54:21 +0000913 // Support for VFP.
914 // All these APIs support S0 to S31 and D0 to D15.
915 // Currently these APIs do not support extended D registers, i.e, D16 to D31.
916 // However, some simple modifications can allow
917 // these APIs to support D16 to D31.
918
Leon Clarked91b9f72010-01-27 17:25:45 +0000919 void vldr(const DwVfpRegister dst,
920 const Register base,
921 int offset, // Offset must be a multiple of 4.
922 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +0100923
924 void vldr(const SwVfpRegister dst,
925 const Register base,
926 int offset, // Offset must be a multiple of 4.
927 const Condition cond = al);
928
Leon Clarked91b9f72010-01-27 17:25:45 +0000929 void vstr(const DwVfpRegister src,
930 const Register base,
931 int offset, // Offset must be a multiple of 4.
932 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +0000933 void vmov(const DwVfpRegister dst,
934 const Register src1,
Steve Blockd0582a62009-12-15 09:54:21 +0000935 const Register src2,
Leon Clarkee46be812010-01-19 14:06:41 +0000936 const Condition cond = al);
937 void vmov(const Register dst1,
938 const Register dst2,
939 const DwVfpRegister src,
940 const Condition cond = al);
941 void vmov(const SwVfpRegister dst,
942 const Register src,
943 const Condition cond = al);
944 void vmov(const Register dst,
945 const SwVfpRegister src,
946 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +0100947 void vcvt_f64_s32(const DwVfpRegister dst,
948 const SwVfpRegister src,
949 const Condition cond = al);
950 void vcvt_f32_s32(const SwVfpRegister dst,
951 const SwVfpRegister src,
952 const Condition cond = al);
953 void vcvt_f64_u32(const DwVfpRegister dst,
954 const SwVfpRegister src,
955 const Condition cond = al);
956 void vcvt_s32_f64(const SwVfpRegister dst,
957 const DwVfpRegister src,
958 const Condition cond = al);
959 void vcvt_u32_f64(const SwVfpRegister dst,
960 const DwVfpRegister src,
961 const Condition cond = al);
962 void vcvt_f64_f32(const DwVfpRegister dst,
963 const SwVfpRegister src,
964 const Condition cond = al);
965 void vcvt_f32_f64(const SwVfpRegister dst,
966 const DwVfpRegister src,
967 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +0000968
969 void vadd(const DwVfpRegister dst,
970 const DwVfpRegister src1,
971 const DwVfpRegister src2,
972 const Condition cond = al);
973 void vsub(const DwVfpRegister dst,
974 const DwVfpRegister src1,
975 const DwVfpRegister src2,
976 const Condition cond = al);
977 void vmul(const DwVfpRegister dst,
978 const DwVfpRegister src1,
979 const DwVfpRegister src2,
980 const Condition cond = al);
981 void vdiv(const DwVfpRegister dst,
982 const DwVfpRegister src1,
983 const DwVfpRegister src2,
984 const Condition cond = al);
985 void vcmp(const DwVfpRegister src1,
986 const DwVfpRegister src2,
Steve Blockd0582a62009-12-15 09:54:21 +0000987 const SBit s = LeaveCC,
988 const Condition cond = al);
989 void vmrs(const Register dst,
990 const Condition cond = al);
991
Steve Blocka7e24c12009-10-30 11:49:00 +0000992 // Pseudo instructions
Steve Block6ded16b2010-05-10 14:33:55 +0100993 void nop(int type = 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000994
995 void push(Register src, Condition cond = al) {
996 str(src, MemOperand(sp, 4, NegPreIndex), cond);
997 }
998
999 void pop(Register dst, Condition cond = al) {
1000 ldr(dst, MemOperand(sp, 4, PostIndex), cond);
1001 }
1002
1003 void pop() {
1004 add(sp, sp, Operand(kPointerSize));
1005 }
1006
Steve Blocka7e24c12009-10-30 11:49:00 +00001007 // Jump unconditionally to given label.
1008 void jmp(Label* L) { b(L, al); }
1009
1010 // Check the code size generated from label to here.
1011 int InstructionsGeneratedSince(Label* l) {
1012 return (pc_offset() - l->pos()) / kInstrSize;
1013 }
1014
Steve Blockd0582a62009-12-15 09:54:21 +00001015 // Check whether an immediate fits an addressing mode 1 instruction.
1016 bool ImmediateFitsAddrMode1Instruction(int32_t imm32);
1017
Steve Block6ded16b2010-05-10 14:33:55 +01001018 // Class for scoping postponing the constant pool generation.
1019 class BlockConstPoolScope {
1020 public:
1021 explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) {
1022 assem_->StartBlockConstPool();
1023 }
1024 ~BlockConstPoolScope() {
1025 assem_->EndBlockConstPool();
1026 }
1027
1028 private:
1029 Assembler* assem_;
1030
1031 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstPoolScope);
1032 };
1033
Steve Blockd0582a62009-12-15 09:54:21 +00001034 // Postpone the generation of the constant pool for the specified number of
1035 // instructions.
1036 void BlockConstPoolFor(int instructions);
1037
Steve Blocka7e24c12009-10-30 11:49:00 +00001038 // Debugging
1039
1040 // Mark address of the ExitJSFrame code.
1041 void RecordJSReturn();
1042
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001043 // Mark address of a debug break slot.
1044 void RecordDebugBreakSlot();
1045
Steve Blocka7e24c12009-10-30 11:49:00 +00001046 // Record a comment relocation entry that can be used by a disassembler.
1047 // Use --debug_code to enable.
1048 void RecordComment(const char* msg);
1049
1050 void RecordPosition(int pos);
1051 void RecordStatementPosition(int pos);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001052 bool WriteRecordedPositions();
Steve Blocka7e24c12009-10-30 11:49:00 +00001053
1054 int pc_offset() const { return pc_ - buffer_; }
1055 int current_position() const { return current_position_; }
Steve Block6ded16b2010-05-10 14:33:55 +01001056 int current_statement_position() const { return current_statement_position_; }
1057
Leon Clarkef7060e22010-06-03 12:02:55 +01001058 bool can_peephole_optimize(int instructions) {
1059 if (!FLAG_peephole_optimization) return false;
1060 if (last_bound_pos_ > pc_offset() - instructions * kInstrSize) return false;
1061 return reloc_info_writer.last_pc() <= pc_ - instructions * kInstrSize;
1062 }
1063
Steve Block6ded16b2010-05-10 14:33:55 +01001064 // Read/patch instructions
1065 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
1066 static void instr_at_put(byte* pc, Instr instr) {
1067 *reinterpret_cast<Instr*>(pc) = instr;
1068 }
1069 static bool IsNop(Instr instr, int type = 0);
1070 static bool IsBranch(Instr instr);
1071 static int GetBranchOffset(Instr instr);
1072 static bool IsLdrRegisterImmediate(Instr instr);
1073 static int GetLdrRegisterImmediateOffset(Instr instr);
1074 static Instr SetLdrRegisterImmediateOffset(Instr instr, int offset);
Leon Clarkef7060e22010-06-03 12:02:55 +01001075 static Register GetRd(Instr instr);
1076 static bool IsPush(Instr instr);
1077 static bool IsPop(Instr instr);
1078 static bool IsStrRegFpOffset(Instr instr);
1079 static bool IsLdrRegFpOffset(Instr instr);
1080 static bool IsStrRegFpNegOffset(Instr instr);
1081 static bool IsLdrRegFpNegOffset(Instr instr);
Steve Block6ded16b2010-05-10 14:33:55 +01001082
Steve Blocka7e24c12009-10-30 11:49:00 +00001083
1084 protected:
1085 int buffer_space() const { return reloc_info_writer.pos() - pc_; }
1086
1087 // Read/patch instructions
Steve Blocka7e24c12009-10-30 11:49:00 +00001088 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
1089 void instr_at_put(int pos, Instr instr) {
1090 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
1091 }
1092
1093 // Decode branch instruction at pos and return branch target pos
1094 int target_at(int pos);
1095
1096 // Patch branch instruction at pos to branch to given branch target pos
1097 void target_at_put(int pos, int target_pos);
1098
1099 // Check if is time to emit a constant pool for pending reloc info entries
1100 void CheckConstPool(bool force_emit, bool require_jump);
1101
1102 // Block the emission of the constant pool before pc_offset
1103 void BlockConstPoolBefore(int pc_offset) {
1104 if (no_const_pool_before_ < pc_offset) no_const_pool_before_ = pc_offset;
1105 }
1106
Steve Block6ded16b2010-05-10 14:33:55 +01001107 void StartBlockConstPool() {
1108 const_pool_blocked_nesting_++;
1109 }
1110 void EndBlockConstPool() {
1111 const_pool_blocked_nesting_--;
1112 }
1113
Steve Blocka7e24c12009-10-30 11:49:00 +00001114 private:
1115 // Code buffer:
1116 // The buffer into which code and relocation info are generated.
1117 byte* buffer_;
1118 int buffer_size_;
1119 // True if the assembler owns the buffer, false if buffer is external.
1120 bool own_buffer_;
1121
1122 // Buffer size and constant pool distance are checked together at regular
1123 // intervals of kBufferCheckInterval emitted bytes
1124 static const int kBufferCheckInterval = 1*KB/2;
1125 int next_buffer_check_; // pc offset of next buffer check
1126
1127 // Code generation
1128 // The relocation writer's position is at least kGap bytes below the end of
1129 // the generated instructions. This is so that multi-instruction sequences do
1130 // not have to check for overflow. The same is true for writes of large
1131 // relocation info entries.
1132 static const int kGap = 32;
1133 byte* pc_; // the program counter; moves forward
1134
1135 // Constant pool generation
1136 // Pools are emitted in the instruction stream, preferably after unconditional
1137 // jumps or after returns from functions (in dead code locations).
1138 // If a long code sequence does not contain unconditional jumps, it is
1139 // necessary to emit the constant pool before the pool gets too far from the
1140 // location it is accessed from. In this case, we emit a jump over the emitted
1141 // constant pool.
1142 // Constants in the pool may be addresses of functions that gets relocated;
1143 // if so, a relocation info entry is associated to the constant pool entry.
1144
1145 // Repeated checking whether the constant pool should be emitted is rather
1146 // expensive. By default we only check again once a number of instructions
1147 // has been generated. That also means that the sizing of the buffers is not
1148 // an exact science, and that we rely on some slop to not overrun buffers.
1149 static const int kCheckConstIntervalInst = 32;
1150 static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize;
1151
1152
1153 // Pools are emitted after function return and in dead code at (more or less)
1154 // regular intervals of kDistBetweenPools bytes
1155 static const int kDistBetweenPools = 1*KB;
1156
1157 // Constants in pools are accessed via pc relative addressing, which can
1158 // reach +/-4KB thereby defining a maximum distance between the instruction
1159 // and the accessed constant. We satisfy this constraint by limiting the
1160 // distance between pools.
1161 static const int kMaxDistBetweenPools = 4*KB - 2*kBufferCheckInterval;
1162
Steve Block6ded16b2010-05-10 14:33:55 +01001163 // Emission of the constant pool may be blocked in some code sequences.
1164 int const_pool_blocked_nesting_; // Block emission if this is not zero.
1165 int no_const_pool_before_; // Block emission before this pc offset.
Steve Blocka7e24c12009-10-30 11:49:00 +00001166
1167 // Keep track of the last emitted pool to guarantee a maximal distance
1168 int last_const_pool_end_; // pc offset following the last constant pool
1169
1170 // Relocation info generation
1171 // Each relocation is encoded as a variable size value
1172 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1173 RelocInfoWriter reloc_info_writer;
1174 // Relocation info records are also used during code generation as temporary
1175 // containers for constants and code target addresses until they are emitted
1176 // to the constant pool. These pending relocation info records are temporarily
1177 // stored in a separate buffer until a constant pool is emitted.
1178 // If every instruction in a long sequence is accessing the pool, we need one
1179 // pending relocation entry per instruction.
1180 static const int kMaxNumPRInfo = kMaxDistBetweenPools/kInstrSize;
1181 RelocInfo prinfo_[kMaxNumPRInfo]; // the buffer of pending relocation info
1182 int num_prinfo_; // number of pending reloc info entries in the buffer
1183
1184 // The bound position, before this we cannot do instruction elimination.
1185 int last_bound_pos_;
1186
1187 // source position information
1188 int current_position_;
1189 int current_statement_position_;
1190 int written_position_;
1191 int written_statement_position_;
1192
1193 // Code emission
1194 inline void CheckBuffer();
1195 void GrowBuffer();
1196 inline void emit(Instr x);
1197
1198 // Instruction generation
1199 void addrmod1(Instr instr, Register rn, Register rd, const Operand& x);
1200 void addrmod2(Instr instr, Register rd, const MemOperand& x);
1201 void addrmod3(Instr instr, Register rd, const MemOperand& x);
1202 void addrmod4(Instr instr, Register rn, RegList rl);
1203 void addrmod5(Instr instr, CRegister crd, const MemOperand& x);
1204
1205 // Labels
1206 void print(Label* L);
1207 void bind_to(Label* L, int pos);
1208 void link_to(Label* L, Label* appendix);
1209 void next(Label* L);
1210
1211 // Record reloc info for current pc_
1212 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
1213
1214 friend class RegExpMacroAssemblerARM;
1215 friend class RelocInfo;
1216 friend class CodePatcher;
Steve Block6ded16b2010-05-10 14:33:55 +01001217 friend class BlockConstPoolScope;
Steve Blocka7e24c12009-10-30 11:49:00 +00001218};
1219
1220} } // namespace v8::internal
1221
1222#endif // V8_ARM_ASSEMBLER_ARM_H_