blob: cc6ec05429f14f2249821e9c42f46ebacd5d7ae4 [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_; }
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100133 SwVfpRegister low() const {
134 SwVfpRegister reg;
135 reg.code_ = code_ * 2;
136
137 ASSERT(reg.is_valid());
138 return reg;
139 }
140 SwVfpRegister high() const {
141 SwVfpRegister reg;
142 reg.code_ = (code_ * 2) + 1;
143
144 ASSERT(reg.is_valid());
145 return reg;
146 }
Leon Clarkee46be812010-01-19 14:06:41 +0000147 int code() const {
148 ASSERT(is_valid());
149 return code_;
150 }
151 int bit() const {
152 ASSERT(is_valid());
153 return 1 << code_;
154 }
155
156 int code_;
157};
158
159
Steve Block6ded16b2010-05-10 14:33:55 +0100160// Support for the VFP registers s0 to s31 (d0 to d15).
Leon Clarkee46be812010-01-19 14:06:41 +0000161// Note that "s(N):s(N+1)" is the same as "d(N/2)".
Steve Block6ded16b2010-05-10 14:33:55 +0100162const SwVfpRegister s0 = { 0 };
163const SwVfpRegister s1 = { 1 };
164const SwVfpRegister s2 = { 2 };
165const SwVfpRegister s3 = { 3 };
166const SwVfpRegister s4 = { 4 };
167const SwVfpRegister s5 = { 5 };
168const SwVfpRegister s6 = { 6 };
169const SwVfpRegister s7 = { 7 };
170const SwVfpRegister s8 = { 8 };
171const SwVfpRegister s9 = { 9 };
172const SwVfpRegister s10 = { 10 };
173const SwVfpRegister s11 = { 11 };
174const SwVfpRegister s12 = { 12 };
175const SwVfpRegister s13 = { 13 };
176const SwVfpRegister s14 = { 14 };
177const SwVfpRegister s15 = { 15 };
178const SwVfpRegister s16 = { 16 };
179const SwVfpRegister s17 = { 17 };
180const SwVfpRegister s18 = { 18 };
181const SwVfpRegister s19 = { 19 };
182const SwVfpRegister s20 = { 20 };
183const SwVfpRegister s21 = { 21 };
184const SwVfpRegister s22 = { 22 };
185const SwVfpRegister s23 = { 23 };
186const SwVfpRegister s24 = { 24 };
187const SwVfpRegister s25 = { 25 };
188const SwVfpRegister s26 = { 26 };
189const SwVfpRegister s27 = { 27 };
190const SwVfpRegister s28 = { 28 };
191const SwVfpRegister s29 = { 29 };
192const SwVfpRegister s30 = { 30 };
193const SwVfpRegister s31 = { 31 };
Leon Clarkee46be812010-01-19 14:06:41 +0000194
Steve Block6ded16b2010-05-10 14:33:55 +0100195const DwVfpRegister d0 = { 0 };
196const DwVfpRegister d1 = { 1 };
197const DwVfpRegister d2 = { 2 };
198const DwVfpRegister d3 = { 3 };
199const DwVfpRegister d4 = { 4 };
200const DwVfpRegister d5 = { 5 };
201const DwVfpRegister d6 = { 6 };
202const DwVfpRegister d7 = { 7 };
203const DwVfpRegister d8 = { 8 };
204const DwVfpRegister d9 = { 9 };
205const DwVfpRegister d10 = { 10 };
206const DwVfpRegister d11 = { 11 };
207const DwVfpRegister d12 = { 12 };
208const DwVfpRegister d13 = { 13 };
209const DwVfpRegister d14 = { 14 };
210const DwVfpRegister d15 = { 15 };
Leon Clarkee46be812010-01-19 14:06:41 +0000211
Steve Blocka7e24c12009-10-30 11:49:00 +0000212
213// Coprocessor register
214struct CRegister {
215 bool is_valid() const { return 0 <= code_ && code_ < 16; }
216 bool is(CRegister creg) const { return code_ == creg.code_; }
217 int code() const {
218 ASSERT(is_valid());
219 return code_;
220 }
221 int bit() const {
222 ASSERT(is_valid());
223 return 1 << code_;
224 }
225
Andrei Popescu31002712010-02-23 13:46:05 +0000226 // Unfortunately we can't make this private in a struct.
Steve Blocka7e24c12009-10-30 11:49:00 +0000227 int code_;
228};
229
230
Steve Block6ded16b2010-05-10 14:33:55 +0100231const CRegister no_creg = { -1 };
232
233const CRegister cr0 = { 0 };
234const CRegister cr1 = { 1 };
235const CRegister cr2 = { 2 };
236const CRegister cr3 = { 3 };
237const CRegister cr4 = { 4 };
238const CRegister cr5 = { 5 };
239const CRegister cr6 = { 6 };
240const CRegister cr7 = { 7 };
241const CRegister cr8 = { 8 };
242const CRegister cr9 = { 9 };
243const CRegister cr10 = { 10 };
244const CRegister cr11 = { 11 };
245const CRegister cr12 = { 12 };
246const CRegister cr13 = { 13 };
247const CRegister cr14 = { 14 };
248const CRegister cr15 = { 15 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000249
250
251// Coprocessor number
252enum Coprocessor {
253 p0 = 0,
254 p1 = 1,
255 p2 = 2,
256 p3 = 3,
257 p4 = 4,
258 p5 = 5,
259 p6 = 6,
260 p7 = 7,
261 p8 = 8,
262 p9 = 9,
263 p10 = 10,
264 p11 = 11,
265 p12 = 12,
266 p13 = 13,
267 p14 = 14,
268 p15 = 15
269};
270
271
Andrei Popescu31002712010-02-23 13:46:05 +0000272// Condition field in instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +0000273enum Condition {
274 eq = 0 << 28, // Z set equal.
275 ne = 1 << 28, // Z clear not equal.
276 nz = 1 << 28, // Z clear not zero.
277 cs = 2 << 28, // C set carry set.
278 hs = 2 << 28, // C set unsigned higher or same.
279 cc = 3 << 28, // C clear carry clear.
280 lo = 3 << 28, // C clear unsigned lower.
281 mi = 4 << 28, // N set negative.
282 pl = 5 << 28, // N clear positive or zero.
283 vs = 6 << 28, // V set overflow.
284 vc = 7 << 28, // V clear no overflow.
285 hi = 8 << 28, // C set, Z clear unsigned higher.
286 ls = 9 << 28, // C clear or Z set unsigned lower or same.
287 ge = 10 << 28, // N == V greater or equal.
288 lt = 11 << 28, // N != V less than.
289 gt = 12 << 28, // Z clear, N == V greater than.
290 le = 13 << 28, // Z set or N != V less then or equal
291 al = 14 << 28 // always.
292};
293
294
295// Returns the equivalent of !cc.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100296inline Condition NegateCondition(Condition cc) {
297 ASSERT(cc != al);
298 return static_cast<Condition>(cc ^ ne);
299}
Steve Blocka7e24c12009-10-30 11:49:00 +0000300
301
302// Corresponds to transposing the operands of a comparison.
303inline Condition ReverseCondition(Condition cc) {
304 switch (cc) {
305 case lo:
306 return hi;
307 case hi:
308 return lo;
309 case hs:
310 return ls;
311 case ls:
312 return hs;
313 case lt:
314 return gt;
315 case gt:
316 return lt;
317 case ge:
318 return le;
319 case le:
320 return ge;
321 default:
322 return cc;
323 };
324}
325
326
327// Branch hints are not used on the ARM. They are defined so that they can
328// appear in shared function signatures, but will be ignored in ARM
329// implementations.
330enum Hint { no_hint };
331
332// Hints are not used on the arm. Negating is trivial.
333inline Hint NegateHint(Hint ignored) { return no_hint; }
334
335
336// -----------------------------------------------------------------------------
337// Addressing modes and instruction variants
338
339// Shifter operand shift operation
340enum ShiftOp {
341 LSL = 0 << 5,
342 LSR = 1 << 5,
343 ASR = 2 << 5,
344 ROR = 3 << 5,
345 RRX = -1
346};
347
348
349// Condition code updating mode
350enum SBit {
351 SetCC = 1 << 20, // set condition code
352 LeaveCC = 0 << 20 // leave condition code unchanged
353};
354
355
356// Status register selection
357enum SRegister {
358 CPSR = 0 << 22,
359 SPSR = 1 << 22
360};
361
362
363// Status register fields
364enum SRegisterField {
365 CPSR_c = CPSR | 1 << 16,
366 CPSR_x = CPSR | 1 << 17,
367 CPSR_s = CPSR | 1 << 18,
368 CPSR_f = CPSR | 1 << 19,
369 SPSR_c = SPSR | 1 << 16,
370 SPSR_x = SPSR | 1 << 17,
371 SPSR_s = SPSR | 1 << 18,
372 SPSR_f = SPSR | 1 << 19
373};
374
375// Status register field mask (or'ed SRegisterField enum values)
376typedef uint32_t SRegisterFieldMask;
377
378
379// Memory operand addressing mode
380enum AddrMode {
381 // bit encoding P U W
382 Offset = (8|4|0) << 21, // offset (without writeback to base)
383 PreIndex = (8|4|1) << 21, // pre-indexed addressing with writeback
384 PostIndex = (0|4|0) << 21, // post-indexed addressing with writeback
385 NegOffset = (8|0|0) << 21, // negative offset (without writeback to base)
386 NegPreIndex = (8|0|1) << 21, // negative pre-indexed with writeback
387 NegPostIndex = (0|0|0) << 21 // negative post-indexed with writeback
388};
389
390
391// Load/store multiple addressing mode
392enum BlockAddrMode {
393 // bit encoding P U W
394 da = (0|0|0) << 21, // decrement after
395 ia = (0|4|0) << 21, // increment after
396 db = (8|0|0) << 21, // decrement before
397 ib = (8|4|0) << 21, // increment before
398 da_w = (0|0|1) << 21, // decrement after with writeback to base
399 ia_w = (0|4|1) << 21, // increment after with writeback to base
400 db_w = (8|0|1) << 21, // decrement before with writeback to base
401 ib_w = (8|4|1) << 21 // increment before with writeback to base
402};
403
404
405// Coprocessor load/store operand size
406enum LFlag {
407 Long = 1 << 22, // long load/store coprocessor
408 Short = 0 << 22 // short load/store coprocessor
409};
410
411
412// -----------------------------------------------------------------------------
413// Machine instruction Operands
414
415// Class Operand represents a shifter operand in data processing instructions
416class Operand BASE_EMBEDDED {
417 public:
418 // immediate
419 INLINE(explicit Operand(int32_t immediate,
420 RelocInfo::Mode rmode = RelocInfo::NONE));
421 INLINE(explicit Operand(const ExternalReference& f));
422 INLINE(explicit Operand(const char* s));
Steve Blocka7e24c12009-10-30 11:49:00 +0000423 explicit Operand(Handle<Object> handle);
424 INLINE(explicit Operand(Smi* value));
425
426 // rm
427 INLINE(explicit Operand(Register rm));
428
429 // rm <shift_op> shift_imm
430 explicit Operand(Register rm, ShiftOp shift_op, int shift_imm);
431
432 // rm <shift_op> rs
433 explicit Operand(Register rm, ShiftOp shift_op, Register rs);
434
435 // Return true if this is a register operand.
436 INLINE(bool is_reg() const);
437
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100438 // Return true of this operand fits in one instruction so that no
439 // 2-instruction solution with a load into the ip register is necessary.
440 bool is_single_instruction() const;
441
442 inline int32_t immediate() const {
443 ASSERT(!rm_.is_valid());
444 return imm32_;
445 }
446
Steve Blocka7e24c12009-10-30 11:49:00 +0000447 Register rm() const { return rm_; }
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100448 Register rs() const { return rs_; }
449 ShiftOp shift_op() const { return shift_op_; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000450
451 private:
452 Register rm_;
453 Register rs_;
454 ShiftOp shift_op_;
455 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
456 int32_t imm32_; // valid if rm_ == no_reg
457 RelocInfo::Mode rmode_;
458
459 friend class Assembler;
460};
461
462
463// Class MemOperand represents a memory operand in load and store instructions
464class MemOperand BASE_EMBEDDED {
465 public:
466 // [rn +/- offset] Offset/NegOffset
467 // [rn +/- offset]! PreIndex/NegPreIndex
468 // [rn], +/- offset PostIndex/NegPostIndex
469 // offset is any signed 32-bit value; offset is first loaded to register ip if
470 // it does not fit the addressing mode (12-bit unsigned and sign bit)
471 explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset);
472
473 // [rn +/- rm] Offset/NegOffset
474 // [rn +/- rm]! PreIndex/NegPreIndex
475 // [rn], +/- rm PostIndex/NegPostIndex
476 explicit MemOperand(Register rn, Register rm, AddrMode am = Offset);
477
478 // [rn +/- rm <shift_op> shift_imm] Offset/NegOffset
479 // [rn +/- rm <shift_op> shift_imm]! PreIndex/NegPreIndex
480 // [rn], +/- rm <shift_op> shift_imm PostIndex/NegPostIndex
481 explicit MemOperand(Register rn, Register rm,
482 ShiftOp shift_op, int shift_imm, AddrMode am = Offset);
483
Kristian Monsen25f61362010-05-21 11:50:48 +0100484 void set_offset(int32_t offset) {
485 ASSERT(rm_.is(no_reg));
486 offset_ = offset;
487 }
488
489 uint32_t offset() {
490 ASSERT(rm_.is(no_reg));
491 return offset_;
492 }
493
Leon Clarkef7060e22010-06-03 12:02:55 +0100494 Register rn() const { return rn_; }
495 Register rm() const { return rm_; }
Kristian Monsen25f61362010-05-21 11:50:48 +0100496
Steve Blocka7e24c12009-10-30 11:49:00 +0000497 private:
498 Register rn_; // base
499 Register rm_; // register offset
500 int32_t offset_; // valid if rm_ == no_reg
501 ShiftOp shift_op_;
502 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
503 AddrMode am_; // bits P, U, and W
504
505 friend class Assembler;
506};
507
Steve Blockd0582a62009-12-15 09:54:21 +0000508// CpuFeatures keeps track of which features are supported by the target CPU.
509// Supported features must be enabled by a Scope before use.
510class CpuFeatures : public AllStatic {
511 public:
512 // Detect features of the target CPU. Set safe defaults if the serializer
513 // is enabled (snapshots must be portable).
514 static void Probe();
515
516 // Check whether a feature is supported by the target CPU.
517 static bool IsSupported(CpuFeature f) {
518 if (f == VFP3 && !FLAG_enable_vfp3) return false;
519 return (supported_ & (1u << f)) != 0;
520 }
521
522 // Check whether a feature is currently enabled.
523 static bool IsEnabled(CpuFeature f) {
524 return (enabled_ & (1u << f)) != 0;
525 }
526
527 // Enable a specified feature within a scope.
528 class Scope BASE_EMBEDDED {
529#ifdef DEBUG
530 public:
531 explicit Scope(CpuFeature f) {
532 ASSERT(CpuFeatures::IsSupported(f));
533 ASSERT(!Serializer::enabled() ||
534 (found_by_runtime_probing_ & (1u << f)) == 0);
535 old_enabled_ = CpuFeatures::enabled_;
536 CpuFeatures::enabled_ |= 1u << f;
537 }
538 ~Scope() { CpuFeatures::enabled_ = old_enabled_; }
539 private:
540 unsigned old_enabled_;
541#else
542 public:
543 explicit Scope(CpuFeature f) {}
544#endif
545 };
546
547 private:
548 static unsigned supported_;
549 static unsigned enabled_;
550 static unsigned found_by_runtime_probing_;
551};
552
Steve Blocka7e24c12009-10-30 11:49:00 +0000553
554typedef int32_t Instr;
555
556
557extern const Instr kMovLrPc;
Steve Block6ded16b2010-05-10 14:33:55 +0100558extern const Instr kLdrPCMask;
Steve Blocka7e24c12009-10-30 11:49:00 +0000559extern const Instr kLdrPCPattern;
Steve Block6ded16b2010-05-10 14:33:55 +0100560extern const Instr kBlxRegMask;
561extern const Instr kBlxRegPattern;
Steve Blocka7e24c12009-10-30 11:49:00 +0000562
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100563extern const Instr kMovMvnMask;
564extern const Instr kMovMvnPattern;
565extern const Instr kMovMvnFlip;
566
567extern const Instr kMovLeaveCCMask;
568extern const Instr kMovLeaveCCPattern;
569extern const Instr kMovwMask;
570extern const Instr kMovwPattern;
571extern const Instr kMovwLeaveCCFlip;
572
573extern const Instr kCmpCmnMask;
574extern const Instr kCmpCmnPattern;
575extern const Instr kCmpCmnFlip;
576
577extern const Instr kALUMask;
578extern const Instr kAddPattern;
579extern const Instr kSubPattern;
580extern const Instr kAndPattern;
581extern const Instr kBicPattern;
582extern const Instr kAddSubFlip;
583extern const Instr kAndBicFlip;
Steve Blocka7e24c12009-10-30 11:49:00 +0000584
585class Assembler : public Malloced {
586 public:
587 // Create an assembler. Instructions and relocation information are emitted
588 // into a buffer, with the instructions starting from the beginning and the
589 // relocation information starting from the end of the buffer. See CodeDesc
590 // for a detailed comment on the layout (globals.h).
591 //
592 // If the provided buffer is NULL, the assembler allocates and grows its own
593 // buffer, and buffer_size determines the initial buffer size. The buffer is
594 // owned by the assembler and deallocated upon destruction of the assembler.
595 //
596 // If the provided buffer is not NULL, the assembler uses the provided buffer
597 // for code generation and assumes its size to be buffer_size. If the buffer
598 // is too small, a fatal error occurs. No deallocation of the buffer is done
599 // upon destruction of the assembler.
600 Assembler(void* buffer, int buffer_size);
601 ~Assembler();
602
603 // GetCode emits any pending (non-emitted) code and fills the descriptor
604 // desc. GetCode() is idempotent; it returns the same result if no other
605 // Assembler functions are invoked in between GetCode() calls.
606 void GetCode(CodeDesc* desc);
607
608 // Label operations & relative jumps (PPUM Appendix D)
609 //
610 // Takes a branch opcode (cc) and a label (L) and generates
611 // either a backward branch or a forward branch and links it
612 // to the label fixup chain. Usage:
613 //
614 // Label L; // unbound label
615 // j(cc, &L); // forward branch to unbound label
616 // bind(&L); // bind label to the current pc
617 // j(cc, &L); // backward branch to bound label
618 // bind(&L); // illegal: a label may be bound only once
619 //
620 // Note: The same Label can be used for forward and backward branches
621 // but it may be bound only once.
622
623 void bind(Label* L); // binds an unbound label L to the current code position
624
625 // Returns the branch offset to the given label from the current code position
626 // Links the label to the current position if it is still unbound
627 // Manages the jump elimination optimization if the second parameter is true.
628 int branch_offset(Label* L, bool jump_elimination_allowed);
629
630 // Puts a labels target address at the given position.
631 // The high 8 bits are set to zero.
632 void label_at_put(Label* L, int at_offset);
633
634 // Return the address in the constant pool of the code target address used by
635 // the branch/call instruction at pc.
636 INLINE(static Address target_address_address_at(Address pc));
637
638 // Read/Modify the code target address in the branch/call instruction at pc.
639 INLINE(static Address target_address_at(Address pc));
640 INLINE(static void set_target_address_at(Address pc, Address target));
641
Steve Blockd0582a62009-12-15 09:54:21 +0000642 // This sets the branch destination (which is in the constant pool on ARM).
643 // This is for calls and branches within generated code.
644 inline static void set_target_at(Address constant_pool_entry, Address target);
645
646 // This sets the branch destination (which is in the constant pool on ARM).
647 // This is for calls and branches to runtime code.
648 inline static void set_external_target_at(Address constant_pool_entry,
649 Address target) {
650 set_target_at(constant_pool_entry, target);
651 }
652
653 // Here we are patching the address in the constant pool, not the actual call
654 // instruction. The address in the constant pool is the same size as a
655 // pointer.
656 static const int kCallTargetSize = kPointerSize;
657 static const int kExternalTargetSize = kPointerSize;
658
Steve Blocka7e24c12009-10-30 11:49:00 +0000659 // Size of an instruction.
660 static const int kInstrSize = sizeof(Instr);
661
662 // Distance between the instruction referring to the address of the call
Steve Block6ded16b2010-05-10 14:33:55 +0100663 // target and the return address.
664#ifdef USE_BLX
665 // Call sequence is:
666 // ldr ip, [pc, #...] @ call address
667 // blx ip
668 // @ return address
669 static const int kCallTargetAddressOffset = 2 * kInstrSize;
670#else
671 // Call sequence is:
672 // mov lr, pc
673 // ldr pc, [pc, #...] @ call address
674 // @ return address
Steve Blocka7e24c12009-10-30 11:49:00 +0000675 static const int kCallTargetAddressOffset = kInstrSize;
Steve Block6ded16b2010-05-10 14:33:55 +0100676#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000677
678 // Distance between start of patched return sequence and the emitted address
679 // to jump to.
Steve Block6ded16b2010-05-10 14:33:55 +0100680#ifdef USE_BLX
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100681 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100682 // ldr ip, [pc, #0] @ emited address and start
683 // blx ip
684 static const int kPatchReturnSequenceAddressOffset = 0 * kInstrSize;
685#else
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100686 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100687 // mov lr, pc @ start of sequence
688 // ldr pc, [pc, #-4] @ emited address
689 static const int kPatchReturnSequenceAddressOffset = kInstrSize;
690#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000691
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100692 // Distance between start of patched debug break slot and the emitted address
693 // to jump to.
694#ifdef USE_BLX
695 // Patched debug break slot code is:
696 // ldr ip, [pc, #0] @ emited address and start
697 // blx ip
698 static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
699#else
700 // Patched debug break slot code is:
701 // mov lr, pc @ start of sequence
702 // ldr pc, [pc, #-4] @ emited address
703 static const int kPatchDebugBreakSlotAddressOffset = kInstrSize;
704#endif
705
Steve Blocka7e24c12009-10-30 11:49:00 +0000706 // Difference between address of current opcode and value read from pc
707 // register.
708 static const int kPcLoadDelta = 8;
709
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100710 static const int kJSReturnSequenceInstructions = 4;
711 static const int kDebugBreakSlotInstructions = 3;
712 static const int kDebugBreakSlotLength =
713 kDebugBreakSlotInstructions * kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +0000714
715 // ---------------------------------------------------------------------------
716 // Code generation
717
718 // Insert the smallest number of nop instructions
719 // possible to align the pc offset to a multiple
720 // of m. m must be a power of 2 (>= 4).
721 void Align(int m);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100722 // Aligns code to something that's optimal for a jump target for the platform.
723 void CodeTargetAlign();
Steve Blocka7e24c12009-10-30 11:49:00 +0000724
725 // Branch instructions
726 void b(int branch_offset, Condition cond = al);
727 void bl(int branch_offset, Condition cond = al);
728 void blx(int branch_offset); // v5 and above
729 void blx(Register target, Condition cond = al); // v5 and above
730 void bx(Register target, Condition cond = al); // v5 and above, plus v4t
731
732 // Convenience branch instructions using labels
733 void b(Label* L, Condition cond = al) {
734 b(branch_offset(L, cond == al), cond);
735 }
736 void b(Condition cond, Label* L) { b(branch_offset(L, cond == al), cond); }
737 void bl(Label* L, Condition cond = al) { bl(branch_offset(L, false), cond); }
738 void bl(Condition cond, Label* L) { bl(branch_offset(L, false), cond); }
739 void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above
740
741 // Data-processing instructions
Andrei Popescu31002712010-02-23 13:46:05 +0000742
Steve Blocka7e24c12009-10-30 11:49:00 +0000743 void and_(Register dst, Register src1, const Operand& src2,
744 SBit s = LeaveCC, Condition cond = al);
745
746 void eor(Register dst, Register src1, const Operand& src2,
747 SBit s = LeaveCC, Condition cond = al);
748
749 void sub(Register dst, Register src1, const Operand& src2,
750 SBit s = LeaveCC, Condition cond = al);
751 void sub(Register dst, Register src1, Register src2,
752 SBit s = LeaveCC, Condition cond = al) {
753 sub(dst, src1, Operand(src2), s, cond);
754 }
755
756 void rsb(Register dst, Register src1, const Operand& src2,
757 SBit s = LeaveCC, Condition cond = al);
758
759 void add(Register dst, Register src1, const Operand& src2,
760 SBit s = LeaveCC, Condition cond = al);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100761 void add(Register dst, Register src1, Register src2,
762 SBit s = LeaveCC, Condition cond = al) {
763 add(dst, src1, Operand(src2), s, cond);
764 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000765
766 void adc(Register dst, Register src1, const Operand& src2,
767 SBit s = LeaveCC, Condition cond = al);
768
769 void sbc(Register dst, Register src1, const Operand& src2,
770 SBit s = LeaveCC, Condition cond = al);
771
772 void rsc(Register dst, Register src1, const Operand& src2,
773 SBit s = LeaveCC, Condition cond = al);
774
775 void tst(Register src1, const Operand& src2, Condition cond = al);
776 void tst(Register src1, Register src2, Condition cond = al) {
777 tst(src1, Operand(src2), cond);
778 }
779
780 void teq(Register src1, const Operand& src2, Condition cond = al);
781
782 void cmp(Register src1, const Operand& src2, Condition cond = al);
783 void cmp(Register src1, Register src2, Condition cond = al) {
784 cmp(src1, Operand(src2), cond);
785 }
786
787 void cmn(Register src1, const Operand& src2, Condition cond = al);
788
789 void orr(Register dst, Register src1, const Operand& src2,
790 SBit s = LeaveCC, Condition cond = al);
791 void orr(Register dst, Register src1, Register src2,
792 SBit s = LeaveCC, Condition cond = al) {
793 orr(dst, src1, Operand(src2), s, cond);
794 }
795
796 void mov(Register dst, const Operand& src,
797 SBit s = LeaveCC, Condition cond = al);
798 void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
799 mov(dst, Operand(src), s, cond);
800 }
801
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100802 // ARMv7 instructions for loading a 32 bit immediate in two instructions.
803 // This may actually emit a different mov instruction, but on an ARMv7 it
804 // is guaranteed to only emit one instruction.
805 void movw(Register reg, uint32_t immediate, Condition cond = al);
806 // The constant for movt should be in the range 0-0xffff.
807 void movt(Register reg, uint32_t immediate, Condition cond = al);
808
Steve Blocka7e24c12009-10-30 11:49:00 +0000809 void bic(Register dst, Register src1, const Operand& src2,
810 SBit s = LeaveCC, Condition cond = al);
811
812 void mvn(Register dst, const Operand& src,
813 SBit s = LeaveCC, Condition cond = al);
814
815 // Multiply instructions
816
817 void mla(Register dst, Register src1, Register src2, Register srcA,
818 SBit s = LeaveCC, Condition cond = al);
819
820 void mul(Register dst, Register src1, Register src2,
821 SBit s = LeaveCC, Condition cond = al);
822
823 void smlal(Register dstL, Register dstH, Register src1, Register src2,
824 SBit s = LeaveCC, Condition cond = al);
825
826 void smull(Register dstL, Register dstH, Register src1, Register src2,
827 SBit s = LeaveCC, Condition cond = al);
828
829 void umlal(Register dstL, Register dstH, Register src1, Register src2,
830 SBit s = LeaveCC, Condition cond = al);
831
832 void umull(Register dstL, Register dstH, Register src1, Register src2,
833 SBit s = LeaveCC, Condition cond = al);
834
835 // Miscellaneous arithmetic instructions
836
837 void clz(Register dst, Register src, Condition cond = al); // v5 and above
838
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100839 // Saturating instructions. v6 and above.
840
841 // Unsigned saturate.
842 //
843 // Saturate an optionally shifted signed value to an unsigned range.
844 //
845 // usat dst, #satpos, src
846 // usat dst, #satpos, src, lsl #sh
847 // usat dst, #satpos, src, asr #sh
848 //
849 // Register dst will contain:
850 //
851 // 0, if s < 0
852 // (1 << satpos) - 1, if s > ((1 << satpos) - 1)
853 // s, otherwise
854 //
855 // where s is the contents of src after shifting (if used.)
856 void usat(Register dst, int satpos, const Operand& src, Condition cond = al);
857
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100858 // Bitfield manipulation instructions. v7 and above.
859
860 void ubfx(Register dst, Register src, int lsb, int width,
861 Condition cond = al);
862
863 void sbfx(Register dst, Register src, int lsb, int width,
864 Condition cond = al);
865
866 void bfc(Register dst, int lsb, int width, Condition cond = al);
867
868 void bfi(Register dst, Register src, int lsb, int width,
869 Condition cond = al);
870
Steve Blocka7e24c12009-10-30 11:49:00 +0000871 // Status register access instructions
872
873 void mrs(Register dst, SRegister s, Condition cond = al);
874 void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al);
875
876 // Load/Store instructions
877 void ldr(Register dst, const MemOperand& src, Condition cond = al);
878 void str(Register src, const MemOperand& dst, Condition cond = al);
879 void ldrb(Register dst, const MemOperand& src, Condition cond = al);
880 void strb(Register src, const MemOperand& dst, Condition cond = al);
881 void ldrh(Register dst, const MemOperand& src, Condition cond = al);
882 void strh(Register src, const MemOperand& dst, Condition cond = al);
883 void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
884 void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
Leon Clarkef7060e22010-06-03 12:02:55 +0100885 void ldrd(Register dst1,
886 Register dst2,
887 const MemOperand& src, Condition cond = al);
888 void strd(Register src1,
889 Register src2,
890 const MemOperand& dst, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000891
892 // Load/Store multiple instructions
893 void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
894 void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
895
Steve Blocka7e24c12009-10-30 11:49:00 +0000896 // Exception-generating instructions and debugging support
897 void stop(const char* msg);
898
899 void bkpt(uint32_t imm16); // v5 and above
900 void swi(uint32_t imm24, Condition cond = al);
901
902 // Coprocessor instructions
903
904 void cdp(Coprocessor coproc, int opcode_1,
905 CRegister crd, CRegister crn, CRegister crm,
906 int opcode_2, Condition cond = al);
907
908 void cdp2(Coprocessor coproc, int opcode_1,
909 CRegister crd, CRegister crn, CRegister crm,
910 int opcode_2); // v5 and above
911
912 void mcr(Coprocessor coproc, int opcode_1,
913 Register rd, CRegister crn, CRegister crm,
914 int opcode_2 = 0, Condition cond = al);
915
916 void mcr2(Coprocessor coproc, int opcode_1,
917 Register rd, CRegister crn, CRegister crm,
918 int opcode_2 = 0); // v5 and above
919
920 void mrc(Coprocessor coproc, int opcode_1,
921 Register rd, CRegister crn, CRegister crm,
922 int opcode_2 = 0, Condition cond = al);
923
924 void mrc2(Coprocessor coproc, int opcode_1,
925 Register rd, CRegister crn, CRegister crm,
926 int opcode_2 = 0); // v5 and above
927
928 void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src,
929 LFlag l = Short, Condition cond = al);
930 void ldc(Coprocessor coproc, CRegister crd, Register base, int option,
931 LFlag l = Short, Condition cond = al);
932
933 void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
934 LFlag l = Short); // v5 and above
935 void ldc2(Coprocessor coproc, CRegister crd, Register base, int option,
936 LFlag l = Short); // v5 and above
937
938 void stc(Coprocessor coproc, CRegister crd, const MemOperand& dst,
939 LFlag l = Short, Condition cond = al);
940 void stc(Coprocessor coproc, CRegister crd, Register base, int option,
941 LFlag l = Short, Condition cond = al);
942
943 void stc2(Coprocessor coproc, CRegister crd, const MemOperand& dst,
944 LFlag l = Short); // v5 and above
945 void stc2(Coprocessor coproc, CRegister crd, Register base, int option,
946 LFlag l = Short); // v5 and above
947
Steve Blockd0582a62009-12-15 09:54:21 +0000948 // Support for VFP.
949 // All these APIs support S0 to S31 and D0 to D15.
950 // Currently these APIs do not support extended D registers, i.e, D16 to D31.
951 // However, some simple modifications can allow
952 // these APIs to support D16 to D31.
953
Leon Clarked91b9f72010-01-27 17:25:45 +0000954 void vldr(const DwVfpRegister dst,
955 const Register base,
956 int offset, // Offset must be a multiple of 4.
957 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +0100958
959 void vldr(const SwVfpRegister dst,
960 const Register base,
961 int offset, // Offset must be a multiple of 4.
962 const Condition cond = al);
963
Leon Clarked91b9f72010-01-27 17:25:45 +0000964 void vstr(const DwVfpRegister src,
965 const Register base,
966 int offset, // Offset must be a multiple of 4.
967 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +0100968
Iain Merrick75681382010-08-19 15:07:18 +0100969 void vstr(const SwVfpRegister src,
970 const Register base,
971 int offset, // Offset must be a multiple of 4.
972 const Condition cond = al);
973
Steve Block8defd9f2010-07-08 12:39:36 +0100974 void vmov(const DwVfpRegister dst,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100975 double imm,
976 const Condition cond = al);
977 void vmov(const SwVfpRegister dst,
978 const SwVfpRegister src,
979 const Condition cond = al);
980 void vmov(const DwVfpRegister dst,
Steve Block8defd9f2010-07-08 12:39:36 +0100981 const DwVfpRegister src,
982 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +0000983 void vmov(const DwVfpRegister dst,
984 const Register src1,
Steve Blockd0582a62009-12-15 09:54:21 +0000985 const Register src2,
Leon Clarkee46be812010-01-19 14:06:41 +0000986 const Condition cond = al);
987 void vmov(const Register dst1,
988 const Register dst2,
989 const DwVfpRegister src,
990 const Condition cond = al);
991 void vmov(const SwVfpRegister dst,
992 const Register src,
993 const Condition cond = al);
994 void vmov(const Register dst,
995 const SwVfpRegister src,
996 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +0100997 void vcvt_f64_s32(const DwVfpRegister dst,
998 const SwVfpRegister src,
999 const Condition cond = al);
1000 void vcvt_f32_s32(const SwVfpRegister dst,
1001 const SwVfpRegister src,
1002 const Condition cond = al);
1003 void vcvt_f64_u32(const DwVfpRegister dst,
1004 const SwVfpRegister src,
1005 const Condition cond = al);
1006 void vcvt_s32_f64(const SwVfpRegister dst,
1007 const DwVfpRegister src,
1008 const Condition cond = al);
1009 void vcvt_u32_f64(const SwVfpRegister dst,
1010 const DwVfpRegister src,
1011 const Condition cond = al);
1012 void vcvt_f64_f32(const DwVfpRegister dst,
1013 const SwVfpRegister src,
1014 const Condition cond = al);
1015 void vcvt_f32_f64(const SwVfpRegister dst,
1016 const DwVfpRegister src,
1017 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +00001018
1019 void vadd(const DwVfpRegister dst,
1020 const DwVfpRegister src1,
1021 const DwVfpRegister src2,
1022 const Condition cond = al);
1023 void vsub(const DwVfpRegister dst,
1024 const DwVfpRegister src1,
1025 const DwVfpRegister src2,
1026 const Condition cond = al);
1027 void vmul(const DwVfpRegister dst,
1028 const DwVfpRegister src1,
1029 const DwVfpRegister src2,
1030 const Condition cond = al);
1031 void vdiv(const DwVfpRegister dst,
1032 const DwVfpRegister src1,
1033 const DwVfpRegister src2,
1034 const Condition cond = al);
1035 void vcmp(const DwVfpRegister src1,
1036 const DwVfpRegister src2,
Steve Blockd0582a62009-12-15 09:54:21 +00001037 const SBit s = LeaveCC,
1038 const Condition cond = al);
Iain Merrick75681382010-08-19 15:07:18 +01001039 void vcmp(const DwVfpRegister src1,
1040 const double src2,
1041 const SBit s = LeaveCC,
1042 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001043 void vmrs(const Register dst,
1044 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +01001045 void vsqrt(const DwVfpRegister dst,
1046 const DwVfpRegister src,
1047 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001048
Steve Blocka7e24c12009-10-30 11:49:00 +00001049 // Pseudo instructions
Steve Block6ded16b2010-05-10 14:33:55 +01001050 void nop(int type = 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001051
1052 void push(Register src, Condition cond = al) {
1053 str(src, MemOperand(sp, 4, NegPreIndex), cond);
1054 }
1055
1056 void pop(Register dst, Condition cond = al) {
1057 ldr(dst, MemOperand(sp, 4, PostIndex), cond);
1058 }
1059
1060 void pop() {
1061 add(sp, sp, Operand(kPointerSize));
1062 }
1063
Steve Blocka7e24c12009-10-30 11:49:00 +00001064 // Jump unconditionally to given label.
1065 void jmp(Label* L) { b(L, al); }
1066
1067 // Check the code size generated from label to here.
1068 int InstructionsGeneratedSince(Label* l) {
1069 return (pc_offset() - l->pos()) / kInstrSize;
1070 }
1071
Steve Blockd0582a62009-12-15 09:54:21 +00001072 // Check whether an immediate fits an addressing mode 1 instruction.
1073 bool ImmediateFitsAddrMode1Instruction(int32_t imm32);
1074
Steve Block6ded16b2010-05-10 14:33:55 +01001075 // Class for scoping postponing the constant pool generation.
1076 class BlockConstPoolScope {
1077 public:
1078 explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) {
1079 assem_->StartBlockConstPool();
1080 }
1081 ~BlockConstPoolScope() {
1082 assem_->EndBlockConstPool();
1083 }
1084
1085 private:
1086 Assembler* assem_;
1087
1088 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstPoolScope);
1089 };
1090
Steve Blockd0582a62009-12-15 09:54:21 +00001091 // Postpone the generation of the constant pool for the specified number of
1092 // instructions.
1093 void BlockConstPoolFor(int instructions);
1094
Steve Blocka7e24c12009-10-30 11:49:00 +00001095 // Debugging
1096
1097 // Mark address of the ExitJSFrame code.
1098 void RecordJSReturn();
1099
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001100 // Mark address of a debug break slot.
1101 void RecordDebugBreakSlot();
1102
Steve Blocka7e24c12009-10-30 11:49:00 +00001103 // Record a comment relocation entry that can be used by a disassembler.
1104 // Use --debug_code to enable.
1105 void RecordComment(const char* msg);
1106
1107 void RecordPosition(int pos);
1108 void RecordStatementPosition(int pos);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001109 bool WriteRecordedPositions();
Steve Blocka7e24c12009-10-30 11:49:00 +00001110
1111 int pc_offset() const { return pc_ - buffer_; }
1112 int current_position() const { return current_position_; }
Steve Block6ded16b2010-05-10 14:33:55 +01001113 int current_statement_position() const { return current_statement_position_; }
1114
Leon Clarkef7060e22010-06-03 12:02:55 +01001115 bool can_peephole_optimize(int instructions) {
1116 if (!FLAG_peephole_optimization) return false;
1117 if (last_bound_pos_ > pc_offset() - instructions * kInstrSize) return false;
1118 return reloc_info_writer.last_pc() <= pc_ - instructions * kInstrSize;
1119 }
1120
Steve Block6ded16b2010-05-10 14:33:55 +01001121 // Read/patch instructions
1122 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
1123 static void instr_at_put(byte* pc, Instr instr) {
1124 *reinterpret_cast<Instr*>(pc) = instr;
1125 }
1126 static bool IsNop(Instr instr, int type = 0);
1127 static bool IsBranch(Instr instr);
1128 static int GetBranchOffset(Instr instr);
1129 static bool IsLdrRegisterImmediate(Instr instr);
1130 static int GetLdrRegisterImmediateOffset(Instr instr);
1131 static Instr SetLdrRegisterImmediateOffset(Instr instr, int offset);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001132 static bool IsStrRegisterImmediate(Instr instr);
1133 static Instr SetStrRegisterImmediateOffset(Instr instr, int offset);
1134 static bool IsAddRegisterImmediate(Instr instr);
1135 static Instr SetAddRegisterImmediateOffset(Instr instr, int offset);
Leon Clarkef7060e22010-06-03 12:02:55 +01001136 static Register GetRd(Instr instr);
1137 static bool IsPush(Instr instr);
1138 static bool IsPop(Instr instr);
1139 static bool IsStrRegFpOffset(Instr instr);
1140 static bool IsLdrRegFpOffset(Instr instr);
1141 static bool IsStrRegFpNegOffset(Instr instr);
1142 static bool IsLdrRegFpNegOffset(Instr instr);
Steve Block6ded16b2010-05-10 14:33:55 +01001143
Steve Blocka7e24c12009-10-30 11:49:00 +00001144
1145 protected:
1146 int buffer_space() const { return reloc_info_writer.pos() - pc_; }
1147
1148 // Read/patch instructions
Steve Blocka7e24c12009-10-30 11:49:00 +00001149 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
1150 void instr_at_put(int pos, Instr instr) {
1151 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
1152 }
1153
1154 // Decode branch instruction at pos and return branch target pos
1155 int target_at(int pos);
1156
1157 // Patch branch instruction at pos to branch to given branch target pos
1158 void target_at_put(int pos, int target_pos);
1159
1160 // Check if is time to emit a constant pool for pending reloc info entries
1161 void CheckConstPool(bool force_emit, bool require_jump);
1162
1163 // Block the emission of the constant pool before pc_offset
1164 void BlockConstPoolBefore(int pc_offset) {
1165 if (no_const_pool_before_ < pc_offset) no_const_pool_before_ = pc_offset;
1166 }
1167
Steve Block6ded16b2010-05-10 14:33:55 +01001168 void StartBlockConstPool() {
1169 const_pool_blocked_nesting_++;
1170 }
1171 void EndBlockConstPool() {
1172 const_pool_blocked_nesting_--;
1173 }
Steve Block8defd9f2010-07-08 12:39:36 +01001174 bool is_const_pool_blocked() const { return const_pool_blocked_nesting_ > 0; }
Steve Block6ded16b2010-05-10 14:33:55 +01001175
Steve Blocka7e24c12009-10-30 11:49:00 +00001176 private:
1177 // Code buffer:
1178 // The buffer into which code and relocation info are generated.
1179 byte* buffer_;
1180 int buffer_size_;
1181 // True if the assembler owns the buffer, false if buffer is external.
1182 bool own_buffer_;
1183
1184 // Buffer size and constant pool distance are checked together at regular
1185 // intervals of kBufferCheckInterval emitted bytes
1186 static const int kBufferCheckInterval = 1*KB/2;
1187 int next_buffer_check_; // pc offset of next buffer check
1188
1189 // Code generation
1190 // The relocation writer's position is at least kGap bytes below the end of
1191 // the generated instructions. This is so that multi-instruction sequences do
1192 // not have to check for overflow. The same is true for writes of large
1193 // relocation info entries.
1194 static const int kGap = 32;
1195 byte* pc_; // the program counter; moves forward
1196
1197 // Constant pool generation
1198 // Pools are emitted in the instruction stream, preferably after unconditional
1199 // jumps or after returns from functions (in dead code locations).
1200 // If a long code sequence does not contain unconditional jumps, it is
1201 // necessary to emit the constant pool before the pool gets too far from the
1202 // location it is accessed from. In this case, we emit a jump over the emitted
1203 // constant pool.
1204 // Constants in the pool may be addresses of functions that gets relocated;
1205 // if so, a relocation info entry is associated to the constant pool entry.
1206
1207 // Repeated checking whether the constant pool should be emitted is rather
1208 // expensive. By default we only check again once a number of instructions
1209 // has been generated. That also means that the sizing of the buffers is not
1210 // an exact science, and that we rely on some slop to not overrun buffers.
1211 static const int kCheckConstIntervalInst = 32;
1212 static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize;
1213
1214
1215 // Pools are emitted after function return and in dead code at (more or less)
1216 // regular intervals of kDistBetweenPools bytes
1217 static const int kDistBetweenPools = 1*KB;
1218
1219 // Constants in pools are accessed via pc relative addressing, which can
1220 // reach +/-4KB thereby defining a maximum distance between the instruction
1221 // and the accessed constant. We satisfy this constraint by limiting the
1222 // distance between pools.
1223 static const int kMaxDistBetweenPools = 4*KB - 2*kBufferCheckInterval;
1224
Steve Block6ded16b2010-05-10 14:33:55 +01001225 // Emission of the constant pool may be blocked in some code sequences.
1226 int const_pool_blocked_nesting_; // Block emission if this is not zero.
1227 int no_const_pool_before_; // Block emission before this pc offset.
Steve Blocka7e24c12009-10-30 11:49:00 +00001228
1229 // Keep track of the last emitted pool to guarantee a maximal distance
1230 int last_const_pool_end_; // pc offset following the last constant pool
1231
1232 // Relocation info generation
1233 // Each relocation is encoded as a variable size value
1234 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1235 RelocInfoWriter reloc_info_writer;
1236 // Relocation info records are also used during code generation as temporary
1237 // containers for constants and code target addresses until they are emitted
1238 // to the constant pool. These pending relocation info records are temporarily
1239 // stored in a separate buffer until a constant pool is emitted.
1240 // If every instruction in a long sequence is accessing the pool, we need one
1241 // pending relocation entry per instruction.
1242 static const int kMaxNumPRInfo = kMaxDistBetweenPools/kInstrSize;
1243 RelocInfo prinfo_[kMaxNumPRInfo]; // the buffer of pending relocation info
1244 int num_prinfo_; // number of pending reloc info entries in the buffer
1245
1246 // The bound position, before this we cannot do instruction elimination.
1247 int last_bound_pos_;
1248
1249 // source position information
1250 int current_position_;
1251 int current_statement_position_;
1252 int written_position_;
1253 int written_statement_position_;
1254
1255 // Code emission
1256 inline void CheckBuffer();
1257 void GrowBuffer();
1258 inline void emit(Instr x);
1259
1260 // Instruction generation
1261 void addrmod1(Instr instr, Register rn, Register rd, const Operand& x);
1262 void addrmod2(Instr instr, Register rd, const MemOperand& x);
1263 void addrmod3(Instr instr, Register rd, const MemOperand& x);
1264 void addrmod4(Instr instr, Register rn, RegList rl);
1265 void addrmod5(Instr instr, CRegister crd, const MemOperand& x);
1266
1267 // Labels
1268 void print(Label* L);
1269 void bind_to(Label* L, int pos);
1270 void link_to(Label* L, Label* appendix);
1271 void next(Label* L);
1272
1273 // Record reloc info for current pc_
1274 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
1275
1276 friend class RegExpMacroAssemblerARM;
1277 friend class RelocInfo;
1278 friend class CodePatcher;
Steve Block6ded16b2010-05-10 14:33:55 +01001279 friend class BlockConstPoolScope;
Steve Blocka7e24c12009-10-30 11:49:00 +00001280};
1281
1282} } // namespace v8::internal
1283
1284#endif // V8_ARM_ASSEMBLER_ARM_H_