1 // 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
33 // The original source code covered by the above license above has been modified
34 // significantly by Google Inc.
35 // Copyright 2006-2008 the V8 project authors. All rights reserved.
36
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"
44
45 namespace v8 {
46 namespace internal {
47
48 // CPU Registers.
49 //
50 // 1) We would prefer to use an enum, but enum values are assignment-
51 // compatible with int, which has caused code-generation bugs.
52 //
53 // 2) We would prefer to use a class instead of a struct but we don't like
54 // the register initialization to depend on the particular initialization
55 // order (which appears to be different on OS X, Linux, and Windows for the
56 // installed versions of C++ we tried). Using a struct permits C-style
57 // "initialization". Also, the Register objects cannot be const as this
58 // forces initialization stubs in MSVC, making us dependent on initialization
59 // order.
60 //
61 // 3) By not using an enum, we are possibly preventing the compiler from
62 // doing certain constant folds, which may significantly reduce the
63 // code generated for some assembly instructions (because they boil down
64 // to a few constants). If this is a problem, we could change the code
65 // such that we use an enum in optimized mode, and the struct in debug
66 // mode. This way we get the compile-time error checking in debug mode
67 // and best performance in optimized code.
68 //
69 // Core register
70 struct Register {
is_validRegister71 bool is_valid() const { return 0 <= code_ && code_ < 16; }
isRegister72 bool is(Register reg) const { return code_ == reg.code_; }
codeRegister73 int code() const {
74 ASSERT(is_valid());
75 return code_;
76 }
bitRegister77 int bit() const {
78 ASSERT(is_valid());
79 return 1 << code_;
80 }
81
82 // (unfortunately we can't make this private in a struct)
83 int code_;
84 };
85
86
87 extern Register no_reg;
88 extern Register r0;
89 extern Register r1;
90 extern Register r2;
91 extern Register r3;
92 extern Register r4;
93 extern Register r5;
94 extern Register r6;
95 extern Register r7;
96 extern Register r8;
97 extern Register r9;
98 extern Register r10;
99 extern Register fp;
100 extern Register ip;
101 extern Register sp;
102 extern Register lr;
103 extern Register pc;
104
105
106 // Coprocessor register
107 struct CRegister {
is_validCRegister108 bool is_valid() const { return 0 <= code_ && code_ < 16; }
isCRegister109 bool is(CRegister creg) const { return code_ == creg.code_; }
codeCRegister110 int code() const {
111 ASSERT(is_valid());
112 return code_;
113 }
bitCRegister114 int bit() const {
115 ASSERT(is_valid());
116 return 1 << code_;
117 }
118
119 // (unfortunately we can't make this private in a struct)
120 int code_;
121 };
122
123
124 extern CRegister no_creg;
125 extern CRegister cr0;
126 extern CRegister cr1;
127 extern CRegister cr2;
128 extern CRegister cr3;
129 extern CRegister cr4;
130 extern CRegister cr5;
131 extern CRegister cr6;
132 extern CRegister cr7;
133 extern CRegister cr8;
134 extern CRegister cr9;
135 extern CRegister cr10;
136 extern CRegister cr11;
137 extern CRegister cr12;
138 extern CRegister cr13;
139 extern CRegister cr14;
140 extern CRegister cr15;
141
142
143 // Coprocessor number
144 enum Coprocessor {
145 p0 = 0,
146 p1 = 1,
147 p2 = 2,
148 p3 = 3,
149 p4 = 4,
150 p5 = 5,
151 p6 = 6,
152 p7 = 7,
153 p8 = 8,
154 p9 = 9,
155 p10 = 10,
156 p11 = 11,
157 p12 = 12,
158 p13 = 13,
159 p14 = 14,
160 p15 = 15
161 };
162
163
164 // Condition field in instructions
165 enum Condition {
166 eq = 0 << 28, // Z set equal.
167 ne = 1 << 28, // Z clear not equal.
168 nz = 1 << 28, // Z clear not zero.
169 cs = 2 << 28, // C set carry set.
170 hs = 2 << 28, // C set unsigned higher or same.
171 cc = 3 << 28, // C clear carry clear.
172 lo = 3 << 28, // C clear unsigned lower.
173 mi = 4 << 28, // N set negative.
174 pl = 5 << 28, // N clear positive or zero.
175 vs = 6 << 28, // V set overflow.
176 vc = 7 << 28, // V clear no overflow.
177 hi = 8 << 28, // C set, Z clear unsigned higher.
178 ls = 9 << 28, // C clear or Z set unsigned lower or same.
179 ge = 10 << 28, // N == V greater or equal.
180 lt = 11 << 28, // N != V less than.
181 gt = 12 << 28, // Z clear, N == V greater than.
182 le = 13 << 28, // Z set or N != V less then or equal
183 al = 14 << 28 // always.
184 };
185
186
187 // Returns the equivalent of !cc.
188 INLINE(Condition NegateCondition(Condition cc));
189
190
191 // Corresponds to transposing the operands of a comparison.
ReverseCondition(Condition cc)192 inline Condition ReverseCondition(Condition cc) {
193 switch (cc) {
194 case lo:
195 return hi;
196 case hi:
197 return lo;
198 case hs:
199 return ls;
200 case ls:
201 return hs;
202 case lt:
203 return gt;
204 case gt:
205 return lt;
206 case ge:
207 return le;
208 case le:
209 return ge;
210 default:
211 return cc;
212 };
213 }
214
215
216 // Branch hints are not used on the ARM. They are defined so that they can
217 // appear in shared function signatures, but will be ignored in ARM
218 // implementations.
219 enum Hint { no_hint };
220
221 // Hints are not used on the arm. Negating is trivial.
NegateHint(Hint ignored)222 inline Hint NegateHint(Hint ignored) { return no_hint; }
223
224
225 // -----------------------------------------------------------------------------
226 // Addressing modes and instruction variants
227
228 // Shifter operand shift operation
229 enum ShiftOp {
230 LSL = 0 << 5,
231 LSR = 1 << 5,
232 ASR = 2 << 5,
233 ROR = 3 << 5,
234 RRX = -1
235 };
236
237
238 // Condition code updating mode
239 enum SBit {
240 SetCC = 1 << 20, // set condition code
241 LeaveCC = 0 << 20 // leave condition code unchanged
242 };
243
244
245 // Status register selection
246 enum SRegister {
247 CPSR = 0 << 22,
248 SPSR = 1 << 22
249 };
250
251
252 // Status register fields
253 enum SRegisterField {
254 CPSR_c = CPSR | 1 << 16,
255 CPSR_x = CPSR | 1 << 17,
256 CPSR_s = CPSR | 1 << 18,
257 CPSR_f = CPSR | 1 << 19,
258 SPSR_c = SPSR | 1 << 16,
259 SPSR_x = SPSR | 1 << 17,
260 SPSR_s = SPSR | 1 << 18,
261 SPSR_f = SPSR | 1 << 19
262 };
263
264 // Status register field mask (or'ed SRegisterField enum values)
265 typedef uint32_t SRegisterFieldMask;
266
267
268 // Memory operand addressing mode
269 enum AddrMode {
270 // bit encoding P U W
271 Offset = (8|4|0) << 21, // offset (without writeback to base)
272 PreIndex = (8|4|1) << 21, // pre-indexed addressing with writeback
273 PostIndex = (0|4|0) << 21, // post-indexed addressing with writeback
274 NegOffset = (8|0|0) << 21, // negative offset (without writeback to base)
275 NegPreIndex = (8|0|1) << 21, // negative pre-indexed with writeback
276 NegPostIndex = (0|0|0) << 21 // negative post-indexed with writeback
277 };
278
279
280 // Load/store multiple addressing mode
281 enum BlockAddrMode {
282 // bit encoding P U W
283 da = (0|0|0) << 21, // decrement after
284 ia = (0|4|0) << 21, // increment after
285 db = (8|0|0) << 21, // decrement before
286 ib = (8|4|0) << 21, // increment before
287 da_w = (0|0|1) << 21, // decrement after with writeback to base
288 ia_w = (0|4|1) << 21, // increment after with writeback to base
289 db_w = (8|0|1) << 21, // decrement before with writeback to base
290 ib_w = (8|4|1) << 21 // increment before with writeback to base
291 };
292
293
294 // Coprocessor load/store operand size
295 enum LFlag {
296 Long = 1 << 22, // long load/store coprocessor
297 Short = 0 << 22 // short load/store coprocessor
298 };
299
300
301 // -----------------------------------------------------------------------------
302 // Machine instruction Operands
303
304 // Class Operand represents a shifter operand in data processing instructions
305 class Operand BASE_EMBEDDED {
306 public:
307 // immediate
308 INLINE(explicit Operand(int32_t immediate,
309 RelocInfo::Mode rmode = RelocInfo::NONE));
310 INLINE(explicit Operand(const ExternalReference& f));
311 INLINE(explicit Operand(const char* s));
312 INLINE(explicit Operand(Object** opp));
313 INLINE(explicit Operand(Context** cpp));
314 explicit Operand(Handle<Object> handle);
315 INLINE(explicit Operand(Smi* value));
316
317 // rm
318 INLINE(explicit Operand(Register rm));
319
320 // rm <shift_op> shift_imm
321 explicit Operand(Register rm, ShiftOp shift_op, int shift_imm);
322
323 // rm <shift_op> rs
324 explicit Operand(Register rm, ShiftOp shift_op, Register rs);
325
326 // Return true if this is a register operand.
327 INLINE(bool is_reg() const);
328
rm()329 Register rm() const { return rm_; }
330
331 private:
332 Register rm_;
333 Register rs_;
334 ShiftOp shift_op_;
335 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
336 int32_t imm32_; // valid if rm_ == no_reg
337 RelocInfo::Mode rmode_;
338
339 friend class Assembler;
340 };
341
342
343 // Class MemOperand represents a memory operand in load and store instructions
344 class MemOperand BASE_EMBEDDED {
345 public:
346 // [rn +/- offset] Offset/NegOffset
347 // [rn +/- offset]! PreIndex/NegPreIndex
348 // [rn], +/- offset PostIndex/NegPostIndex
349 // offset is any signed 32-bit value; offset is first loaded to register ip if
350 // it does not fit the addressing mode (12-bit unsigned and sign bit)
351 explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset);
352
353 // [rn +/- rm] Offset/NegOffset
354 // [rn +/- rm]! PreIndex/NegPreIndex
355 // [rn], +/- rm PostIndex/NegPostIndex
356 explicit MemOperand(Register rn, Register rm, AddrMode am = Offset);
357
358 // [rn +/- rm <shift_op> shift_imm] Offset/NegOffset
359 // [rn +/- rm <shift_op> shift_imm]! PreIndex/NegPreIndex
360 // [rn], +/- rm <shift_op> shift_imm PostIndex/NegPostIndex
361 explicit MemOperand(Register rn, Register rm,
362 ShiftOp shift_op, int shift_imm, AddrMode am = Offset);
363
364 private:
365 Register rn_; // base
366 Register rm_; // register offset
367 int32_t offset_; // valid if rm_ == no_reg
368 ShiftOp shift_op_;
369 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
370 AddrMode am_; // bits P, U, and W
371
372 friend class Assembler;
373 };
374
375
376 typedef int32_t Instr;
377
378
379 class Assembler : public Malloced {
380 public:
381 // Create an assembler. Instructions and relocation information are emitted
382 // into a buffer, with the instructions starting from the beginning and the
383 // relocation information starting from the end of the buffer. See CodeDesc
384 // for a detailed comment on the layout (globals.h).
385 //
386 // If the provided buffer is NULL, the assembler allocates and grows its own
387 // buffer, and buffer_size determines the initial buffer size. The buffer is
388 // owned by the assembler and deallocated upon destruction of the assembler.
389 //
390 // If the provided buffer is not NULL, the assembler uses the provided buffer
391 // for code generation and assumes its size to be buffer_size. If the buffer
392 // is too small, a fatal error occurs. No deallocation of the buffer is done
393 // upon destruction of the assembler.
394 Assembler(void* buffer, int buffer_size);
395 ~Assembler();
396
397 // GetCode emits any pending (non-emitted) code and fills the descriptor
398 // desc. GetCode() is idempotent; it returns the same result if no other
399 // Assembler functions are invoked in between GetCode() calls.
400 void GetCode(CodeDesc* desc);
401
402 // Label operations & relative jumps (PPUM Appendix D)
403 //
404 // Takes a branch opcode (cc) and a label (L) and generates
405 // either a backward branch or a forward branch and links it
406 // to the label fixup chain. Usage:
407 //
408 // Label L; // unbound label
409 // j(cc, &L); // forward branch to unbound label
410 // bind(&L); // bind label to the current pc
411 // j(cc, &L); // backward branch to bound label
412 // bind(&L); // illegal: a label may be bound only once
413 //
414 // Note: The same Label can be used for forward and backward branches
415 // but it may be bound only once.
416
417 void bind(Label* L); // binds an unbound label L to the current code position
418
419 // Returns the branch offset to the given label from the current code position
420 // Links the label to the current position if it is still unbound
421 // Manages the jump elimination optimization if the second parameter is true.
422 int branch_offset(Label* L, bool jump_elimination_allowed);
423
424 // Puts a labels target address at the given position.
425 // The high 8 bits are set to zero.
426 void label_at_put(Label* L, int at_offset);
427
428 // Return the address in the constant pool of the code target address used by
429 // the branch/call instruction at pc.
430 INLINE(static Address target_address_address_at(Address pc));
431
432 // Read/Modify the code target address in the branch/call instruction at pc.
433 INLINE(static Address target_address_at(Address pc));
434 INLINE(static void set_target_address_at(Address pc, Address target));
435
436 // Distance between the instruction referring to the address of the call
437 // target (ldr pc, [target addr in const pool]) and the return address
438 static const int kPatchReturnSequenceLength = sizeof(Instr);
439 // Distance between start of patched return sequence and the emitted address
440 // to jump to.
441 static const int kPatchReturnSequenceAddressOffset = 1;
442
443 // Difference between address of current opcode and value read from pc
444 // register.
445 static const int kPcLoadDelta = 8;
446
447
448 // ---------------------------------------------------------------------------
449 // Code generation
450
451 // Insert the smallest number of nop instructions
452 // possible to align the pc offset to a multiple
453 // of m. m must be a power of 2 (>= 4).
454 void Align(int m);
455
456 // Branch instructions
457 void b(int branch_offset, Condition cond = al);
458 void bl(int branch_offset, Condition cond = al);
459 void blx(int branch_offset); // v5 and above
460 void blx(Register target, Condition cond = al); // v5 and above
461 void bx(Register target, Condition cond = al); // v5 and above, plus v4t
462
463 // Convenience branch instructions using labels
464 void b(Label* L, Condition cond = al) {
465 b(branch_offset(L, cond == al), cond);
466 }
b(Condition cond,Label * L)467 void b(Condition cond, Label* L) { b(branch_offset(L, cond == al), cond); }
468 void bl(Label* L, Condition cond = al) { bl(branch_offset(L, false), cond); }
bl(Condition cond,Label * L)469 void bl(Condition cond, Label* L) { bl(branch_offset(L, false), cond); }
blx(Label * L)470 void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above
471
472 // Data-processing instructions
473 void and_(Register dst, Register src1, const Operand& src2,
474 SBit s = LeaveCC, Condition cond = al);
475
476 void eor(Register dst, Register src1, const Operand& src2,
477 SBit s = LeaveCC, Condition cond = al);
478
479 void sub(Register dst, Register src1, const Operand& src2,
480 SBit s = LeaveCC, Condition cond = al);
481 void sub(Register dst, Register src1, Register src2,
482 SBit s = LeaveCC, Condition cond = al) {
483 sub(dst, src1, Operand(src2), s, cond);
484 }
485
486 void rsb(Register dst, Register src1, const Operand& src2,
487 SBit s = LeaveCC, Condition cond = al);
488
489 void add(Register dst, Register src1, const Operand& src2,
490 SBit s = LeaveCC, Condition cond = al);
491
492 void adc(Register dst, Register src1, const Operand& src2,
493 SBit s = LeaveCC, Condition cond = al);
494
495 void sbc(Register dst, Register src1, const Operand& src2,
496 SBit s = LeaveCC, Condition cond = al);
497
498 void rsc(Register dst, Register src1, const Operand& src2,
499 SBit s = LeaveCC, Condition cond = al);
500
501 void tst(Register src1, const Operand& src2, Condition cond = al);
502 void tst(Register src1, Register src2, Condition cond = al) {
503 tst(src1, Operand(src2), cond);
504 }
505
506 void teq(Register src1, const Operand& src2, Condition cond = al);
507
508 void cmp(Register src1, const Operand& src2, Condition cond = al);
509 void cmp(Register src1, Register src2, Condition cond = al) {
510 cmp(src1, Operand(src2), cond);
511 }
512
513 void cmn(Register src1, const Operand& src2, Condition cond = al);
514
515 void orr(Register dst, Register src1, const Operand& src2,
516 SBit s = LeaveCC, Condition cond = al);
517 void orr(Register dst, Register src1, Register src2,
518 SBit s = LeaveCC, Condition cond = al) {
519 orr(dst, src1, Operand(src2), s, cond);
520 }
521
522 void mov(Register dst, const Operand& src,
523 SBit s = LeaveCC, Condition cond = al);
524 void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
525 mov(dst, Operand(src), s, cond);
526 }
527
528 void bic(Register dst, Register src1, const Operand& src2,
529 SBit s = LeaveCC, Condition cond = al);
530
531 void mvn(Register dst, const Operand& src,
532 SBit s = LeaveCC, Condition cond = al);
533
534 // Multiply instructions
535
536 void mla(Register dst, Register src1, Register src2, Register srcA,
537 SBit s = LeaveCC, Condition cond = al);
538
539 void mul(Register dst, Register src1, Register src2,
540 SBit s = LeaveCC, Condition cond = al);
541
542 void smlal(Register dstL, Register dstH, Register src1, Register src2,
543 SBit s = LeaveCC, Condition cond = al);
544
545 void smull(Register dstL, Register dstH, Register src1, Register src2,
546 SBit s = LeaveCC, Condition cond = al);
547
548 void umlal(Register dstL, Register dstH, Register src1, Register src2,
549 SBit s = LeaveCC, Condition cond = al);
550
551 void umull(Register dstL, Register dstH, Register src1, Register src2,
552 SBit s = LeaveCC, Condition cond = al);
553
554 // Miscellaneous arithmetic instructions
555
556 void clz(Register dst, Register src, Condition cond = al); // v5 and above
557
558 // Status register access instructions
559
560 void mrs(Register dst, SRegister s, Condition cond = al);
561 void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al);
562
563 // Load/Store instructions
564 void ldr(Register dst, const MemOperand& src, Condition cond = al);
565 void str(Register src, const MemOperand& dst, Condition cond = al);
566 void ldrb(Register dst, const MemOperand& src, Condition cond = al);
567 void strb(Register src, const MemOperand& dst, Condition cond = al);
568 void ldrh(Register dst, const MemOperand& src, Condition cond = al);
569 void strh(Register src, const MemOperand& dst, Condition cond = al);
570 void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
571 void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
572
573 // Load/Store multiple instructions
574 void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
575 void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
576
577 // Semaphore instructions
578 void swp(Register dst, Register src, Register base, Condition cond = al);
579 void swpb(Register dst, Register src, Register base, Condition cond = al);
580
581 // Exception-generating instructions and debugging support
582 void stop(const char* msg);
583
584 void bkpt(uint32_t imm16); // v5 and above
585 void swi(uint32_t imm24, Condition cond = al);
586
587 // Coprocessor instructions
588
589 void cdp(Coprocessor coproc, int opcode_1,
590 CRegister crd, CRegister crn, CRegister crm,
591 int opcode_2, Condition cond = al);
592
593 void cdp2(Coprocessor coproc, int opcode_1,
594 CRegister crd, CRegister crn, CRegister crm,
595 int opcode_2); // v5 and above
596
597 void mcr(Coprocessor coproc, int opcode_1,
598 Register rd, CRegister crn, CRegister crm,
599 int opcode_2 = 0, Condition cond = al);
600
601 void mcr2(Coprocessor coproc, int opcode_1,
602 Register rd, CRegister crn, CRegister crm,
603 int opcode_2 = 0); // v5 and above
604
605 void mrc(Coprocessor coproc, int opcode_1,
606 Register rd, CRegister crn, CRegister crm,
607 int opcode_2 = 0, Condition cond = al);
608
609 void mrc2(Coprocessor coproc, int opcode_1,
610 Register rd, CRegister crn, CRegister crm,
611 int opcode_2 = 0); // v5 and above
612
613 void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src,
614 LFlag l = Short, Condition cond = al);
615 void ldc(Coprocessor coproc, CRegister crd, Register base, int option,
616 LFlag l = Short, Condition cond = al);
617
618 void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
619 LFlag l = Short); // v5 and above
620 void ldc2(Coprocessor coproc, CRegister crd, Register base, int option,
621 LFlag l = Short); // v5 and above
622
623 void stc(Coprocessor coproc, CRegister crd, const MemOperand& dst,
624 LFlag l = Short, Condition cond = al);
625 void stc(Coprocessor coproc, CRegister crd, Register base, int option,
626 LFlag l = Short, Condition cond = al);
627
628 void stc2(Coprocessor coproc, CRegister crd, const MemOperand& dst,
629 LFlag l = Short); // v5 and above
630 void stc2(Coprocessor coproc, CRegister crd, Register base, int option,
631 LFlag l = Short); // v5 and above
632
633 // Pseudo instructions
nop()634 void nop() { mov(r0, Operand(r0)); }
635
636 void push(Register src, Condition cond = al) {
637 str(src, MemOperand(sp, 4, NegPreIndex), cond);
638 }
639
pop(Register dst)640 void pop(Register dst) {
641 ldr(dst, MemOperand(sp, 4, PostIndex), al);
642 }
643
pop()644 void pop() {
645 add(sp, sp, Operand(kPointerSize));
646 }
647
648 // Load effective address of memory operand x into register dst
649 void lea(Register dst, const MemOperand& x,
650 SBit s = LeaveCC, Condition cond = al);
651
652 // Jump unconditionally to given label.
jmp(Label * L)653 void jmp(Label* L) { b(L, al); }
654
655
656 // Debugging
657
658 // Record a comment relocation entry that can be used by a disassembler.
659 // Use --debug_code to enable.
660 void RecordComment(const char* msg);
661
662 void RecordPosition(int pos);
663 void RecordStatementPosition(int pos);
664 void WriteRecordedPositions();
665
pc_offset()666 int pc_offset() const { return pc_ - buffer_; }
current_position()667 int current_position() const { return current_position_; }
current_statement_position()668 int current_statement_position() const { return current_position_; }
669
670 protected:
buffer_space()671 int buffer_space() const { return reloc_info_writer.pos() - pc_; }
672
673 // Read/patch instructions
instr_at(byte * pc)674 Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
instr_at_put(byte * pc,Instr instr)675 void instr_at_put(byte* pc, Instr instr) {
676 *reinterpret_cast<Instr*>(pc) = instr;
677 }
instr_at(int pos)678 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
instr_at_put(int pos,Instr instr)679 void instr_at_put(int pos, Instr instr) {
680 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
681 }
682
683 // Decode branch instruction at pos and return branch target pos
684 int target_at(int pos);
685
686 // Patch branch instruction at pos to branch to given branch target pos
687 void target_at_put(int pos, int target_pos);
688
689 // Check if is time to emit a constant pool for pending reloc info entries
690 void CheckConstPool(bool force_emit, bool require_jump);
691
692 // Block the emission of the constant pool before pc_offset
BlockConstPoolBefore(int pc_offset)693 void BlockConstPoolBefore(int pc_offset) {
694 if (no_const_pool_before_ < pc_offset) no_const_pool_before_ = pc_offset;
695 }
696
697 private:
698 // Code buffer:
699 // The buffer into which code and relocation info are generated.
700 byte* buffer_;
701 int buffer_size_;
702 // True if the assembler owns the buffer, false if buffer is external.
703 bool own_buffer_;
704
705 // Buffer size and constant pool distance are checked together at regular
706 // intervals of kBufferCheckInterval emitted bytes
707 static const int kBufferCheckInterval = 1*KB/2;
708 int next_buffer_check_; // pc offset of next buffer check
709
710 // Code generation
711 static const int kInstrSize = sizeof(Instr); // signed size
712 // The relocation writer's position is at least kGap bytes below the end of
713 // the generated instructions. This is so that multi-instruction sequences do
714 // not have to check for overflow. The same is true for writes of large
715 // relocation info entries.
716 static const int kGap = 32;
717 byte* pc_; // the program counter; moves forward
718
719 // Constant pool generation
720 // Pools are emitted in the instruction stream, preferably after unconditional
721 // jumps or after returns from functions (in dead code locations).
722 // If a long code sequence does not contain unconditional jumps, it is
723 // necessary to emit the constant pool before the pool gets too far from the
724 // location it is accessed from. In this case, we emit a jump over the emitted
725 // constant pool.
726 // Constants in the pool may be addresses of functions that gets relocated;
727 // if so, a relocation info entry is associated to the constant pool entry.
728
729 // Repeated checking whether the constant pool should be emitted is rather
730 // expensive. By default we only check again once a number of instructions
731 // has been generated. That also means that the sizing of the buffers is not
732 // an exact science, and that we rely on some slop to not overrun buffers.
733 static const int kCheckConstIntervalInst = 32;
734 static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize;
735
736
737 // Pools are emitted after function return and in dead code at (more or less)
738 // regular intervals of kDistBetweenPools bytes
739 static const int kDistBetweenPools = 1*KB;
740
741 // Constants in pools are accessed via pc relative addressing, which can
742 // reach +/-4KB thereby defining a maximum distance between the instruction
743 // and the accessed constant. We satisfy this constraint by limiting the
744 // distance between pools.
745 static const int kMaxDistBetweenPools = 4*KB - 2*kBufferCheckInterval;
746
747 // Emission of the constant pool may be blocked in some code sequences
748 int no_const_pool_before_; // block emission before this pc offset
749
750 // Keep track of the last emitted pool to guarantee a maximal distance
751 int last_const_pool_end_; // pc offset following the last constant pool
752
753 // Relocation info generation
754 // Each relocation is encoded as a variable size value
755 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
756 RelocInfoWriter reloc_info_writer;
757 // Relocation info records are also used during code generation as temporary
758 // containers for constants and code target addresses until they are emitted
759 // to the constant pool. These pending relocation info records are temporarily
760 // stored in a separate buffer until a constant pool is emitted.
761 // If every instruction in a long sequence is accessing the pool, we need one
762 // pending relocation entry per instruction.
763 static const int kMaxNumPRInfo = kMaxDistBetweenPools/kInstrSize;
764 RelocInfo prinfo_[kMaxNumPRInfo]; // the buffer of pending relocation info
765 int num_prinfo_; // number of pending reloc info entries in the buffer
766
767 // The bound position, before this we cannot do instruction elimination.
768 int last_bound_pos_;
769
770 // source position information
771 int current_position_;
772 int current_statement_position_;
773 int written_position_;
774 int written_statement_position_;
775
776 // Code emission
777 inline void CheckBuffer();
778 void GrowBuffer();
779 inline void emit(Instr x);
780
781 // Instruction generation
782 void addrmod1(Instr instr, Register rn, Register rd, const Operand& x);
783 void addrmod2(Instr instr, Register rd, const MemOperand& x);
784 void addrmod3(Instr instr, Register rd, const MemOperand& x);
785 void addrmod4(Instr instr, Register rn, RegList rl);
786 void addrmod5(Instr instr, CRegister crd, const MemOperand& x);
787
788 // Labels
789 void print(Label* L);
790 void bind_to(Label* L, int pos);
791 void link_to(Label* L, Label* appendix);
792 void next(Label* L);
793
794 // Record reloc info for current pc_
795 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
796
797 friend class RegExpMacroAssemblerARM;
798 };
799
800 } } // namespace v8::internal
801
802 #endif // V8_ARM_ASSEMBLER_ARM_H_
803