blob: d1df08c5712cf3b246ce55ca53c0c96606246d74 [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
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
45namespace v8 {
46namespace 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
70struct Register {
71 bool is_valid() const { return 0 <= code_ && code_ < 16; }
72 bool is(Register reg) const { return code_ == reg.code_; }
73 int code() const {
74 ASSERT(is_valid());
75 return code_;
76 }
77 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
87extern Register no_reg;
88extern Register r0;
89extern Register r1;
90extern Register r2;
91extern Register r3;
92extern Register r4;
93extern Register r5;
94extern Register r6;
95extern Register r7;
96extern Register r8;
97extern Register r9;
98extern Register r10;
99extern Register fp;
100extern Register ip;
101extern Register sp;
102extern Register lr;
103extern Register pc;
104
105
106// Coprocessor register
107struct CRegister {
108 bool is_valid() const { return 0 <= code_ && code_ < 16; }
109 bool is(CRegister creg) const { return code_ == creg.code_; }
110 int code() const {
111 ASSERT(is_valid());
112 return code_;
113 }
114 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
124extern CRegister no_creg;
125extern CRegister cr0;
126extern CRegister cr1;
127extern CRegister cr2;
128extern CRegister cr3;
129extern CRegister cr4;
130extern CRegister cr5;
131extern CRegister cr6;
132extern CRegister cr7;
133extern CRegister cr8;
134extern CRegister cr9;
135extern CRegister cr10;
136extern CRegister cr11;
137extern CRegister cr12;
138extern CRegister cr13;
139extern CRegister cr14;
140extern CRegister cr15;
141
142
143// Coprocessor number
144enum 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
165enum 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.
188INLINE(Condition NegateCondition(Condition cc));
189
190
191// Corresponds to transposing the operands of a comparison.
192inline 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.
219enum Hint { no_hint };
220
221// Hints are not used on the arm. Negating is trivial.
222inline Hint NegateHint(Hint ignored) { return no_hint; }
223
224
225// -----------------------------------------------------------------------------
226// Addressing modes and instruction variants
227
228// Shifter operand shift operation
229enum 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
239enum SBit {
240 SetCC = 1 << 20, // set condition code
241 LeaveCC = 0 << 20 // leave condition code unchanged
242};
243
244
245// Status register selection
246enum SRegister {
247 CPSR = 0 << 22,
248 SPSR = 1 << 22
249};
250
251
252// Status register fields
253enum 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)
265typedef uint32_t SRegisterFieldMask;
266
267
268// Memory operand addressing mode
269enum 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
281enum 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
295enum 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
305class 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
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
344class 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
376typedef int32_t Instr;
377
378
379extern const Instr kMovLrPc;
380extern const Instr kLdrPCPattern;
381
382
383class Assembler : public Malloced {
384 public:
385 // Create an assembler. Instructions and relocation information are emitted
386 // into a buffer, with the instructions starting from the beginning and the
387 // relocation information starting from the end of the buffer. See CodeDesc
388 // for a detailed comment on the layout (globals.h).
389 //
390 // If the provided buffer is NULL, the assembler allocates and grows its own
391 // buffer, and buffer_size determines the initial buffer size. The buffer is
392 // owned by the assembler and deallocated upon destruction of the assembler.
393 //
394 // If the provided buffer is not NULL, the assembler uses the provided buffer
395 // for code generation and assumes its size to be buffer_size. If the buffer
396 // is too small, a fatal error occurs. No deallocation of the buffer is done
397 // upon destruction of the assembler.
398 Assembler(void* buffer, int buffer_size);
399 ~Assembler();
400
401 // GetCode emits any pending (non-emitted) code and fills the descriptor
402 // desc. GetCode() is idempotent; it returns the same result if no other
403 // Assembler functions are invoked in between GetCode() calls.
404 void GetCode(CodeDesc* desc);
405
406 // Label operations & relative jumps (PPUM Appendix D)
407 //
408 // Takes a branch opcode (cc) and a label (L) and generates
409 // either a backward branch or a forward branch and links it
410 // to the label fixup chain. Usage:
411 //
412 // Label L; // unbound label
413 // j(cc, &L); // forward branch to unbound label
414 // bind(&L); // bind label to the current pc
415 // j(cc, &L); // backward branch to bound label
416 // bind(&L); // illegal: a label may be bound only once
417 //
418 // Note: The same Label can be used for forward and backward branches
419 // but it may be bound only once.
420
421 void bind(Label* L); // binds an unbound label L to the current code position
422
423 // Returns the branch offset to the given label from the current code position
424 // Links the label to the current position if it is still unbound
425 // Manages the jump elimination optimization if the second parameter is true.
426 int branch_offset(Label* L, bool jump_elimination_allowed);
427
428 // Puts a labels target address at the given position.
429 // The high 8 bits are set to zero.
430 void label_at_put(Label* L, int at_offset);
431
432 // Return the address in the constant pool of the code target address used by
433 // the branch/call instruction at pc.
434 INLINE(static Address target_address_address_at(Address pc));
435
436 // Read/Modify the code target address in the branch/call instruction at pc.
437 INLINE(static Address target_address_at(Address pc));
438 INLINE(static void set_target_address_at(Address pc, Address target));
439
440 // Size of an instruction.
441 static const int kInstrSize = sizeof(Instr);
442
443 // Distance between the instruction referring to the address of the call
444 // target (ldr pc, [target addr in const pool]) and the return address
445 static const int kCallTargetAddressOffset = kInstrSize;
446
447 // Distance between start of patched return sequence and the emitted address
448 // to jump to.
449 static const int kPatchReturnSequenceAddressOffset = kInstrSize;
450
451 // Difference between address of current opcode and value read from pc
452 // register.
453 static const int kPcLoadDelta = 8;
454
455
456 // ---------------------------------------------------------------------------
457 // Code generation
458
459 // Insert the smallest number of nop instructions
460 // possible to align the pc offset to a multiple
461 // of m. m must be a power of 2 (>= 4).
462 void Align(int m);
463
464 // Branch instructions
465 void b(int branch_offset, Condition cond = al);
466 void bl(int branch_offset, Condition cond = al);
467 void blx(int branch_offset); // v5 and above
468 void blx(Register target, Condition cond = al); // v5 and above
469 void bx(Register target, Condition cond = al); // v5 and above, plus v4t
470
471 // Convenience branch instructions using labels
472 void b(Label* L, Condition cond = al) {
473 b(branch_offset(L, cond == al), cond);
474 }
475 void b(Condition cond, Label* L) { b(branch_offset(L, cond == al), cond); }
476 void bl(Label* L, Condition cond = al) { bl(branch_offset(L, false), cond); }
477 void bl(Condition cond, Label* L) { bl(branch_offset(L, false), cond); }
478 void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above
479
480 // Data-processing instructions
481 void and_(Register dst, Register src1, const Operand& src2,
482 SBit s = LeaveCC, Condition cond = al);
483
484 void eor(Register dst, Register src1, const Operand& src2,
485 SBit s = LeaveCC, Condition cond = al);
486
487 void sub(Register dst, Register src1, const Operand& src2,
488 SBit s = LeaveCC, Condition cond = al);
489 void sub(Register dst, Register src1, Register src2,
490 SBit s = LeaveCC, Condition cond = al) {
491 sub(dst, src1, Operand(src2), s, cond);
492 }
493
494 void rsb(Register dst, Register src1, const Operand& src2,
495 SBit s = LeaveCC, Condition cond = al);
496
497 void add(Register dst, Register src1, const Operand& src2,
498 SBit s = LeaveCC, Condition cond = al);
499
500 void adc(Register dst, Register src1, const Operand& src2,
501 SBit s = LeaveCC, Condition cond = al);
502
503 void sbc(Register dst, Register src1, const Operand& src2,
504 SBit s = LeaveCC, Condition cond = al);
505
506 void rsc(Register dst, Register src1, const Operand& src2,
507 SBit s = LeaveCC, Condition cond = al);
508
509 void tst(Register src1, const Operand& src2, Condition cond = al);
510 void tst(Register src1, Register src2, Condition cond = al) {
511 tst(src1, Operand(src2), cond);
512 }
513
514 void teq(Register src1, const Operand& src2, Condition cond = al);
515
516 void cmp(Register src1, const Operand& src2, Condition cond = al);
517 void cmp(Register src1, Register src2, Condition cond = al) {
518 cmp(src1, Operand(src2), cond);
519 }
520
521 void cmn(Register src1, const Operand& src2, Condition cond = al);
522
523 void orr(Register dst, Register src1, const Operand& src2,
524 SBit s = LeaveCC, Condition cond = al);
525 void orr(Register dst, Register src1, Register src2,
526 SBit s = LeaveCC, Condition cond = al) {
527 orr(dst, src1, Operand(src2), s, cond);
528 }
529
530 void mov(Register dst, const Operand& src,
531 SBit s = LeaveCC, Condition cond = al);
532 void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
533 mov(dst, Operand(src), s, cond);
534 }
535
536 void bic(Register dst, Register src1, const Operand& src2,
537 SBit s = LeaveCC, Condition cond = al);
538
539 void mvn(Register dst, const Operand& src,
540 SBit s = LeaveCC, Condition cond = al);
541
542 // Multiply instructions
543
544 void mla(Register dst, Register src1, Register src2, Register srcA,
545 SBit s = LeaveCC, Condition cond = al);
546
547 void mul(Register dst, Register src1, Register src2,
548 SBit s = LeaveCC, Condition cond = al);
549
550 void smlal(Register dstL, Register dstH, Register src1, Register src2,
551 SBit s = LeaveCC, Condition cond = al);
552
553 void smull(Register dstL, Register dstH, Register src1, Register src2,
554 SBit s = LeaveCC, Condition cond = al);
555
556 void umlal(Register dstL, Register dstH, Register src1, Register src2,
557 SBit s = LeaveCC, Condition cond = al);
558
559 void umull(Register dstL, Register dstH, Register src1, Register src2,
560 SBit s = LeaveCC, Condition cond = al);
561
562 // Miscellaneous arithmetic instructions
563
564 void clz(Register dst, Register src, Condition cond = al); // v5 and above
565
566 // Status register access instructions
567
568 void mrs(Register dst, SRegister s, Condition cond = al);
569 void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al);
570
571 // Load/Store instructions
572 void ldr(Register dst, const MemOperand& src, Condition cond = al);
573 void str(Register src, const MemOperand& dst, Condition cond = al);
574 void ldrb(Register dst, const MemOperand& src, Condition cond = al);
575 void strb(Register src, const MemOperand& dst, Condition cond = al);
576 void ldrh(Register dst, const MemOperand& src, Condition cond = al);
577 void strh(Register src, const MemOperand& dst, Condition cond = al);
578 void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
579 void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
580
581 // Load/Store multiple instructions
582 void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
583 void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
584
585 // Semaphore instructions
586 void swp(Register dst, Register src, Register base, Condition cond = al);
587 void swpb(Register dst, Register src, Register base, Condition cond = al);
588
589 // Exception-generating instructions and debugging support
590 void stop(const char* msg);
591
592 void bkpt(uint32_t imm16); // v5 and above
593 void swi(uint32_t imm24, Condition cond = al);
594
595 // Coprocessor instructions
596
597 void cdp(Coprocessor coproc, int opcode_1,
598 CRegister crd, CRegister crn, CRegister crm,
599 int opcode_2, Condition cond = al);
600
601 void cdp2(Coprocessor coproc, int opcode_1,
602 CRegister crd, CRegister crn, CRegister crm,
603 int opcode_2); // v5 and above
604
605 void mcr(Coprocessor coproc, int opcode_1,
606 Register rd, CRegister crn, CRegister crm,
607 int opcode_2 = 0, Condition cond = al);
608
609 void mcr2(Coprocessor coproc, int opcode_1,
610 Register rd, CRegister crn, CRegister crm,
611 int opcode_2 = 0); // v5 and above
612
613 void mrc(Coprocessor coproc, int opcode_1,
614 Register rd, CRegister crn, CRegister crm,
615 int opcode_2 = 0, Condition cond = al);
616
617 void mrc2(Coprocessor coproc, int opcode_1,
618 Register rd, CRegister crn, CRegister crm,
619 int opcode_2 = 0); // v5 and above
620
621 void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src,
622 LFlag l = Short, Condition cond = al);
623 void ldc(Coprocessor coproc, CRegister crd, Register base, int option,
624 LFlag l = Short, Condition cond = al);
625
626 void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
627 LFlag l = Short); // v5 and above
628 void ldc2(Coprocessor coproc, CRegister crd, Register base, int option,
629 LFlag l = Short); // v5 and above
630
631 void stc(Coprocessor coproc, CRegister crd, const MemOperand& dst,
632 LFlag l = Short, Condition cond = al);
633 void stc(Coprocessor coproc, CRegister crd, Register base, int option,
634 LFlag l = Short, Condition cond = al);
635
636 void stc2(Coprocessor coproc, CRegister crd, const MemOperand& dst,
637 LFlag l = Short); // v5 and above
638 void stc2(Coprocessor coproc, CRegister crd, Register base, int option,
639 LFlag l = Short); // v5 and above
640
641 // Pseudo instructions
642 void nop() { mov(r0, Operand(r0)); }
643
644 void push(Register src, Condition cond = al) {
645 str(src, MemOperand(sp, 4, NegPreIndex), cond);
646 }
647
648 void pop(Register dst, Condition cond = al) {
649 ldr(dst, MemOperand(sp, 4, PostIndex), cond);
650 }
651
652 void pop() {
653 add(sp, sp, Operand(kPointerSize));
654 }
655
656 // Load effective address of memory operand x into register dst
657 void lea(Register dst, const MemOperand& x,
658 SBit s = LeaveCC, Condition cond = al);
659
660 // Jump unconditionally to given label.
661 void jmp(Label* L) { b(L, al); }
662
663 // Check the code size generated from label to here.
664 int InstructionsGeneratedSince(Label* l) {
665 return (pc_offset() - l->pos()) / kInstrSize;
666 }
667
668 // Debugging
669
670 // Mark address of the ExitJSFrame code.
671 void RecordJSReturn();
672
673 // Record a comment relocation entry that can be used by a disassembler.
674 // Use --debug_code to enable.
675 void RecordComment(const char* msg);
676
677 void RecordPosition(int pos);
678 void RecordStatementPosition(int pos);
679 void WriteRecordedPositions();
680
681 int pc_offset() const { return pc_ - buffer_; }
682 int current_position() const { return current_position_; }
683 int current_statement_position() const { return current_position_; }
684
685 protected:
686 int buffer_space() const { return reloc_info_writer.pos() - pc_; }
687
688 // Read/patch instructions
689 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
690 void instr_at_put(byte* pc, Instr instr) {
691 *reinterpret_cast<Instr*>(pc) = instr;
692 }
693 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
694 void instr_at_put(int pos, Instr instr) {
695 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
696 }
697
698 // Decode branch instruction at pos and return branch target pos
699 int target_at(int pos);
700
701 // Patch branch instruction at pos to branch to given branch target pos
702 void target_at_put(int pos, int target_pos);
703
704 // Check if is time to emit a constant pool for pending reloc info entries
705 void CheckConstPool(bool force_emit, bool require_jump);
706
707 // Block the emission of the constant pool before pc_offset
708 void BlockConstPoolBefore(int pc_offset) {
709 if (no_const_pool_before_ < pc_offset) no_const_pool_before_ = pc_offset;
710 }
711
712 private:
713 // Code buffer:
714 // The buffer into which code and relocation info are generated.
715 byte* buffer_;
716 int buffer_size_;
717 // True if the assembler owns the buffer, false if buffer is external.
718 bool own_buffer_;
719
720 // Buffer size and constant pool distance are checked together at regular
721 // intervals of kBufferCheckInterval emitted bytes
722 static const int kBufferCheckInterval = 1*KB/2;
723 int next_buffer_check_; // pc offset of next buffer check
724
725 // Code generation
726 // The relocation writer's position is at least kGap bytes below the end of
727 // the generated instructions. This is so that multi-instruction sequences do
728 // not have to check for overflow. The same is true for writes of large
729 // relocation info entries.
730 static const int kGap = 32;
731 byte* pc_; // the program counter; moves forward
732
733 // Constant pool generation
734 // Pools are emitted in the instruction stream, preferably after unconditional
735 // jumps or after returns from functions (in dead code locations).
736 // If a long code sequence does not contain unconditional jumps, it is
737 // necessary to emit the constant pool before the pool gets too far from the
738 // location it is accessed from. In this case, we emit a jump over the emitted
739 // constant pool.
740 // Constants in the pool may be addresses of functions that gets relocated;
741 // if so, a relocation info entry is associated to the constant pool entry.
742
743 // Repeated checking whether the constant pool should be emitted is rather
744 // expensive. By default we only check again once a number of instructions
745 // has been generated. That also means that the sizing of the buffers is not
746 // an exact science, and that we rely on some slop to not overrun buffers.
747 static const int kCheckConstIntervalInst = 32;
748 static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize;
749
750
751 // Pools are emitted after function return and in dead code at (more or less)
752 // regular intervals of kDistBetweenPools bytes
753 static const int kDistBetweenPools = 1*KB;
754
755 // Constants in pools are accessed via pc relative addressing, which can
756 // reach +/-4KB thereby defining a maximum distance between the instruction
757 // and the accessed constant. We satisfy this constraint by limiting the
758 // distance between pools.
759 static const int kMaxDistBetweenPools = 4*KB - 2*kBufferCheckInterval;
760
761 // Emission of the constant pool may be blocked in some code sequences
762 int no_const_pool_before_; // block emission before this pc offset
763
764 // Keep track of the last emitted pool to guarantee a maximal distance
765 int last_const_pool_end_; // pc offset following the last constant pool
766
767 // Relocation info generation
768 // Each relocation is encoded as a variable size value
769 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
770 RelocInfoWriter reloc_info_writer;
771 // Relocation info records are also used during code generation as temporary
772 // containers for constants and code target addresses until they are emitted
773 // to the constant pool. These pending relocation info records are temporarily
774 // stored in a separate buffer until a constant pool is emitted.
775 // If every instruction in a long sequence is accessing the pool, we need one
776 // pending relocation entry per instruction.
777 static const int kMaxNumPRInfo = kMaxDistBetweenPools/kInstrSize;
778 RelocInfo prinfo_[kMaxNumPRInfo]; // the buffer of pending relocation info
779 int num_prinfo_; // number of pending reloc info entries in the buffer
780
781 // The bound position, before this we cannot do instruction elimination.
782 int last_bound_pos_;
783
784 // source position information
785 int current_position_;
786 int current_statement_position_;
787 int written_position_;
788 int written_statement_position_;
789
790 // Code emission
791 inline void CheckBuffer();
792 void GrowBuffer();
793 inline void emit(Instr x);
794
795 // Instruction generation
796 void addrmod1(Instr instr, Register rn, Register rd, const Operand& x);
797 void addrmod2(Instr instr, Register rd, const MemOperand& x);
798 void addrmod3(Instr instr, Register rd, const MemOperand& x);
799 void addrmod4(Instr instr, Register rn, RegList rl);
800 void addrmod5(Instr instr, CRegister crd, const MemOperand& x);
801
802 // Labels
803 void print(Label* L);
804 void bind_to(Label* L, int pos);
805 void link_to(Label* L, Label* appendix);
806 void next(Label* L);
807
808 // Record reloc info for current pc_
809 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
810
811 friend class RegExpMacroAssemblerARM;
812 friend class RelocInfo;
813 friend class CodePatcher;
814};
815
816} } // namespace v8::internal
817
818#endif // V8_ARM_ASSEMBLER_ARM_H_