blob: 86bc18a2478ee1dc1f0bef9ec7fe3d6fa4d13d8f [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"
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
83 // (unfortunately we can't make this private in a struct)
84 int code_;
85};
86
87
88extern Register no_reg;
89extern Register r0;
90extern Register r1;
91extern Register r2;
92extern Register r3;
93extern Register r4;
94extern Register r5;
95extern Register r6;
96extern Register r7;
97extern Register r8;
98extern Register r9;
99extern Register r10;
100extern Register fp;
101extern Register ip;
102extern Register sp;
103extern Register lr;
104extern Register pc;
105
Steve Blockd0582a62009-12-15 09:54:21 +0000106// Support for VFP registers s0 to s32 (d0 to d16).
107// Note that "sN:sM" is the same as "dN/2".
108extern Register s0;
109extern Register s1;
110extern Register s2;
111extern Register s3;
112extern Register s4;
113extern Register s5;
114extern Register s6;
115extern Register s7;
116extern Register s8;
117extern Register s9;
118extern Register s10;
119extern Register s11;
120extern Register s12;
121extern Register s13;
122extern Register s14;
123extern Register s15;
124extern Register s16;
125extern Register s17;
126extern Register s18;
127extern Register s19;
128extern Register s20;
129extern Register s21;
130extern Register s22;
131extern Register s23;
132extern Register s24;
133extern Register s25;
134extern Register s26;
135extern Register s27;
136extern Register s28;
137extern Register s29;
138extern Register s30;
139extern Register s31;
140
141extern Register d0;
142extern Register d1;
143extern Register d2;
144extern Register d3;
145extern Register d4;
146extern Register d5;
147extern Register d6;
148extern Register d7;
149extern Register d8;
150extern Register d9;
151extern Register d10;
152extern Register d11;
153extern Register d12;
154extern Register d13;
155extern Register d14;
156extern Register d15;
Steve Blocka7e24c12009-10-30 11:49:00 +0000157
158// Coprocessor register
159struct CRegister {
160 bool is_valid() const { return 0 <= code_ && code_ < 16; }
161 bool is(CRegister creg) const { return code_ == creg.code_; }
162 int code() const {
163 ASSERT(is_valid());
164 return code_;
165 }
166 int bit() const {
167 ASSERT(is_valid());
168 return 1 << code_;
169 }
170
171 // (unfortunately we can't make this private in a struct)
172 int code_;
173};
174
175
176extern CRegister no_creg;
177extern CRegister cr0;
178extern CRegister cr1;
179extern CRegister cr2;
180extern CRegister cr3;
181extern CRegister cr4;
182extern CRegister cr5;
183extern CRegister cr6;
184extern CRegister cr7;
185extern CRegister cr8;
186extern CRegister cr9;
187extern CRegister cr10;
188extern CRegister cr11;
189extern CRegister cr12;
190extern CRegister cr13;
191extern CRegister cr14;
192extern CRegister cr15;
193
194
195// Coprocessor number
196enum Coprocessor {
197 p0 = 0,
198 p1 = 1,
199 p2 = 2,
200 p3 = 3,
201 p4 = 4,
202 p5 = 5,
203 p6 = 6,
204 p7 = 7,
205 p8 = 8,
206 p9 = 9,
207 p10 = 10,
208 p11 = 11,
209 p12 = 12,
210 p13 = 13,
211 p14 = 14,
212 p15 = 15
213};
214
215
216// Condition field in instructions
217enum Condition {
218 eq = 0 << 28, // Z set equal.
219 ne = 1 << 28, // Z clear not equal.
220 nz = 1 << 28, // Z clear not zero.
221 cs = 2 << 28, // C set carry set.
222 hs = 2 << 28, // C set unsigned higher or same.
223 cc = 3 << 28, // C clear carry clear.
224 lo = 3 << 28, // C clear unsigned lower.
225 mi = 4 << 28, // N set negative.
226 pl = 5 << 28, // N clear positive or zero.
227 vs = 6 << 28, // V set overflow.
228 vc = 7 << 28, // V clear no overflow.
229 hi = 8 << 28, // C set, Z clear unsigned higher.
230 ls = 9 << 28, // C clear or Z set unsigned lower or same.
231 ge = 10 << 28, // N == V greater or equal.
232 lt = 11 << 28, // N != V less than.
233 gt = 12 << 28, // Z clear, N == V greater than.
234 le = 13 << 28, // Z set or N != V less then or equal
235 al = 14 << 28 // always.
236};
237
238
239// Returns the equivalent of !cc.
240INLINE(Condition NegateCondition(Condition cc));
241
242
243// Corresponds to transposing the operands of a comparison.
244inline Condition ReverseCondition(Condition cc) {
245 switch (cc) {
246 case lo:
247 return hi;
248 case hi:
249 return lo;
250 case hs:
251 return ls;
252 case ls:
253 return hs;
254 case lt:
255 return gt;
256 case gt:
257 return lt;
258 case ge:
259 return le;
260 case le:
261 return ge;
262 default:
263 return cc;
264 };
265}
266
267
268// Branch hints are not used on the ARM. They are defined so that they can
269// appear in shared function signatures, but will be ignored in ARM
270// implementations.
271enum Hint { no_hint };
272
273// Hints are not used on the arm. Negating is trivial.
274inline Hint NegateHint(Hint ignored) { return no_hint; }
275
276
277// -----------------------------------------------------------------------------
278// Addressing modes and instruction variants
279
280// Shifter operand shift operation
281enum ShiftOp {
282 LSL = 0 << 5,
283 LSR = 1 << 5,
284 ASR = 2 << 5,
285 ROR = 3 << 5,
286 RRX = -1
287};
288
289
290// Condition code updating mode
291enum SBit {
292 SetCC = 1 << 20, // set condition code
293 LeaveCC = 0 << 20 // leave condition code unchanged
294};
295
296
297// Status register selection
298enum SRegister {
299 CPSR = 0 << 22,
300 SPSR = 1 << 22
301};
302
303
304// Status register fields
305enum SRegisterField {
306 CPSR_c = CPSR | 1 << 16,
307 CPSR_x = CPSR | 1 << 17,
308 CPSR_s = CPSR | 1 << 18,
309 CPSR_f = CPSR | 1 << 19,
310 SPSR_c = SPSR | 1 << 16,
311 SPSR_x = SPSR | 1 << 17,
312 SPSR_s = SPSR | 1 << 18,
313 SPSR_f = SPSR | 1 << 19
314};
315
316// Status register field mask (or'ed SRegisterField enum values)
317typedef uint32_t SRegisterFieldMask;
318
319
320// Memory operand addressing mode
321enum AddrMode {
322 // bit encoding P U W
323 Offset = (8|4|0) << 21, // offset (without writeback to base)
324 PreIndex = (8|4|1) << 21, // pre-indexed addressing with writeback
325 PostIndex = (0|4|0) << 21, // post-indexed addressing with writeback
326 NegOffset = (8|0|0) << 21, // negative offset (without writeback to base)
327 NegPreIndex = (8|0|1) << 21, // negative pre-indexed with writeback
328 NegPostIndex = (0|0|0) << 21 // negative post-indexed with writeback
329};
330
331
332// Load/store multiple addressing mode
333enum BlockAddrMode {
334 // bit encoding P U W
335 da = (0|0|0) << 21, // decrement after
336 ia = (0|4|0) << 21, // increment after
337 db = (8|0|0) << 21, // decrement before
338 ib = (8|4|0) << 21, // increment before
339 da_w = (0|0|1) << 21, // decrement after with writeback to base
340 ia_w = (0|4|1) << 21, // increment after with writeback to base
341 db_w = (8|0|1) << 21, // decrement before with writeback to base
342 ib_w = (8|4|1) << 21 // increment before with writeback to base
343};
344
345
346// Coprocessor load/store operand size
347enum LFlag {
348 Long = 1 << 22, // long load/store coprocessor
349 Short = 0 << 22 // short load/store coprocessor
350};
351
352
353// -----------------------------------------------------------------------------
354// Machine instruction Operands
355
356// Class Operand represents a shifter operand in data processing instructions
357class Operand BASE_EMBEDDED {
358 public:
359 // immediate
360 INLINE(explicit Operand(int32_t immediate,
361 RelocInfo::Mode rmode = RelocInfo::NONE));
362 INLINE(explicit Operand(const ExternalReference& f));
363 INLINE(explicit Operand(const char* s));
364 INLINE(explicit Operand(Object** opp));
365 INLINE(explicit Operand(Context** cpp));
366 explicit Operand(Handle<Object> handle);
367 INLINE(explicit Operand(Smi* value));
368
369 // rm
370 INLINE(explicit Operand(Register rm));
371
372 // rm <shift_op> shift_imm
373 explicit Operand(Register rm, ShiftOp shift_op, int shift_imm);
374
375 // rm <shift_op> rs
376 explicit Operand(Register rm, ShiftOp shift_op, Register rs);
377
378 // Return true if this is a register operand.
379 INLINE(bool is_reg() const);
380
381 Register rm() const { return rm_; }
382
383 private:
384 Register rm_;
385 Register rs_;
386 ShiftOp shift_op_;
387 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
388 int32_t imm32_; // valid if rm_ == no_reg
389 RelocInfo::Mode rmode_;
390
391 friend class Assembler;
392};
393
394
395// Class MemOperand represents a memory operand in load and store instructions
396class MemOperand BASE_EMBEDDED {
397 public:
398 // [rn +/- offset] Offset/NegOffset
399 // [rn +/- offset]! PreIndex/NegPreIndex
400 // [rn], +/- offset PostIndex/NegPostIndex
401 // offset is any signed 32-bit value; offset is first loaded to register ip if
402 // it does not fit the addressing mode (12-bit unsigned and sign bit)
403 explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset);
404
405 // [rn +/- rm] Offset/NegOffset
406 // [rn +/- rm]! PreIndex/NegPreIndex
407 // [rn], +/- rm PostIndex/NegPostIndex
408 explicit MemOperand(Register rn, Register rm, AddrMode am = Offset);
409
410 // [rn +/- rm <shift_op> shift_imm] Offset/NegOffset
411 // [rn +/- rm <shift_op> shift_imm]! PreIndex/NegPreIndex
412 // [rn], +/- rm <shift_op> shift_imm PostIndex/NegPostIndex
413 explicit MemOperand(Register rn, Register rm,
414 ShiftOp shift_op, int shift_imm, AddrMode am = Offset);
415
416 private:
417 Register rn_; // base
418 Register rm_; // register offset
419 int32_t offset_; // valid if rm_ == no_reg
420 ShiftOp shift_op_;
421 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
422 AddrMode am_; // bits P, U, and W
423
424 friend class Assembler;
425};
426
Steve Blockd0582a62009-12-15 09:54:21 +0000427// CpuFeatures keeps track of which features are supported by the target CPU.
428// Supported features must be enabled by a Scope before use.
429class CpuFeatures : public AllStatic {
430 public:
431 // Detect features of the target CPU. Set safe defaults if the serializer
432 // is enabled (snapshots must be portable).
433 static void Probe();
434
435 // Check whether a feature is supported by the target CPU.
436 static bool IsSupported(CpuFeature f) {
437 if (f == VFP3 && !FLAG_enable_vfp3) return false;
438 return (supported_ & (1u << f)) != 0;
439 }
440
441 // Check whether a feature is currently enabled.
442 static bool IsEnabled(CpuFeature f) {
443 return (enabled_ & (1u << f)) != 0;
444 }
445
446 // Enable a specified feature within a scope.
447 class Scope BASE_EMBEDDED {
448#ifdef DEBUG
449 public:
450 explicit Scope(CpuFeature f) {
451 ASSERT(CpuFeatures::IsSupported(f));
452 ASSERT(!Serializer::enabled() ||
453 (found_by_runtime_probing_ & (1u << f)) == 0);
454 old_enabled_ = CpuFeatures::enabled_;
455 CpuFeatures::enabled_ |= 1u << f;
456 }
457 ~Scope() { CpuFeatures::enabled_ = old_enabled_; }
458 private:
459 unsigned old_enabled_;
460#else
461 public:
462 explicit Scope(CpuFeature f) {}
463#endif
464 };
465
466 private:
467 static unsigned supported_;
468 static unsigned enabled_;
469 static unsigned found_by_runtime_probing_;
470};
471
Steve Blocka7e24c12009-10-30 11:49:00 +0000472
473typedef int32_t Instr;
474
475
476extern const Instr kMovLrPc;
477extern const Instr kLdrPCPattern;
478
479
480class Assembler : public Malloced {
481 public:
482 // Create an assembler. Instructions and relocation information are emitted
483 // into a buffer, with the instructions starting from the beginning and the
484 // relocation information starting from the end of the buffer. See CodeDesc
485 // for a detailed comment on the layout (globals.h).
486 //
487 // If the provided buffer is NULL, the assembler allocates and grows its own
488 // buffer, and buffer_size determines the initial buffer size. The buffer is
489 // owned by the assembler and deallocated upon destruction of the assembler.
490 //
491 // If the provided buffer is not NULL, the assembler uses the provided buffer
492 // for code generation and assumes its size to be buffer_size. If the buffer
493 // is too small, a fatal error occurs. No deallocation of the buffer is done
494 // upon destruction of the assembler.
495 Assembler(void* buffer, int buffer_size);
496 ~Assembler();
497
498 // GetCode emits any pending (non-emitted) code and fills the descriptor
499 // desc. GetCode() is idempotent; it returns the same result if no other
500 // Assembler functions are invoked in between GetCode() calls.
501 void GetCode(CodeDesc* desc);
502
503 // Label operations & relative jumps (PPUM Appendix D)
504 //
505 // Takes a branch opcode (cc) and a label (L) and generates
506 // either a backward branch or a forward branch and links it
507 // to the label fixup chain. Usage:
508 //
509 // Label L; // unbound label
510 // j(cc, &L); // forward branch to unbound label
511 // bind(&L); // bind label to the current pc
512 // j(cc, &L); // backward branch to bound label
513 // bind(&L); // illegal: a label may be bound only once
514 //
515 // Note: The same Label can be used for forward and backward branches
516 // but it may be bound only once.
517
518 void bind(Label* L); // binds an unbound label L to the current code position
519
520 // Returns the branch offset to the given label from the current code position
521 // Links the label to the current position if it is still unbound
522 // Manages the jump elimination optimization if the second parameter is true.
523 int branch_offset(Label* L, bool jump_elimination_allowed);
524
525 // Puts a labels target address at the given position.
526 // The high 8 bits are set to zero.
527 void label_at_put(Label* L, int at_offset);
528
529 // Return the address in the constant pool of the code target address used by
530 // the branch/call instruction at pc.
531 INLINE(static Address target_address_address_at(Address pc));
532
533 // Read/Modify the code target address in the branch/call instruction at pc.
534 INLINE(static Address target_address_at(Address pc));
535 INLINE(static void set_target_address_at(Address pc, Address target));
536
Steve Blockd0582a62009-12-15 09:54:21 +0000537 // This sets the branch destination (which is in the constant pool on ARM).
538 // This is for calls and branches within generated code.
539 inline static void set_target_at(Address constant_pool_entry, Address target);
540
541 // This sets the branch destination (which is in the constant pool on ARM).
542 // This is for calls and branches to runtime code.
543 inline static void set_external_target_at(Address constant_pool_entry,
544 Address target) {
545 set_target_at(constant_pool_entry, target);
546 }
547
548 // Here we are patching the address in the constant pool, not the actual call
549 // instruction. The address in the constant pool is the same size as a
550 // pointer.
551 static const int kCallTargetSize = kPointerSize;
552 static const int kExternalTargetSize = kPointerSize;
553
Steve Blocka7e24c12009-10-30 11:49:00 +0000554 // Size of an instruction.
555 static const int kInstrSize = sizeof(Instr);
556
557 // Distance between the instruction referring to the address of the call
558 // target (ldr pc, [target addr in const pool]) and the return address
559 static const int kCallTargetAddressOffset = kInstrSize;
560
561 // Distance between start of patched return sequence and the emitted address
562 // to jump to.
563 static const int kPatchReturnSequenceAddressOffset = kInstrSize;
564
565 // Difference between address of current opcode and value read from pc
566 // register.
567 static const int kPcLoadDelta = 8;
568
Steve Blockd0582a62009-12-15 09:54:21 +0000569 static const int kJSReturnSequenceLength = 4;
Steve Blocka7e24c12009-10-30 11:49:00 +0000570
571 // ---------------------------------------------------------------------------
572 // Code generation
573
574 // Insert the smallest number of nop instructions
575 // possible to align the pc offset to a multiple
576 // of m. m must be a power of 2 (>= 4).
577 void Align(int m);
578
579 // Branch instructions
580 void b(int branch_offset, Condition cond = al);
581 void bl(int branch_offset, Condition cond = al);
582 void blx(int branch_offset); // v5 and above
583 void blx(Register target, Condition cond = al); // v5 and above
584 void bx(Register target, Condition cond = al); // v5 and above, plus v4t
585
586 // Convenience branch instructions using labels
587 void b(Label* L, Condition cond = al) {
588 b(branch_offset(L, cond == al), cond);
589 }
590 void b(Condition cond, Label* L) { b(branch_offset(L, cond == al), cond); }
591 void bl(Label* L, Condition cond = al) { bl(branch_offset(L, false), cond); }
592 void bl(Condition cond, Label* L) { bl(branch_offset(L, false), cond); }
593 void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above
594
595 // Data-processing instructions
596 void and_(Register dst, Register src1, const Operand& src2,
597 SBit s = LeaveCC, Condition cond = al);
598
599 void eor(Register dst, Register src1, const Operand& src2,
600 SBit s = LeaveCC, Condition cond = al);
601
602 void sub(Register dst, Register src1, const Operand& src2,
603 SBit s = LeaveCC, Condition cond = al);
604 void sub(Register dst, Register src1, Register src2,
605 SBit s = LeaveCC, Condition cond = al) {
606 sub(dst, src1, Operand(src2), s, cond);
607 }
608
609 void rsb(Register dst, Register src1, const Operand& src2,
610 SBit s = LeaveCC, Condition cond = al);
611
612 void add(Register dst, Register src1, const Operand& src2,
613 SBit s = LeaveCC, Condition cond = al);
614
615 void adc(Register dst, Register src1, const Operand& src2,
616 SBit s = LeaveCC, Condition cond = al);
617
618 void sbc(Register dst, Register src1, const Operand& src2,
619 SBit s = LeaveCC, Condition cond = al);
620
621 void rsc(Register dst, Register src1, const Operand& src2,
622 SBit s = LeaveCC, Condition cond = al);
623
624 void tst(Register src1, const Operand& src2, Condition cond = al);
625 void tst(Register src1, Register src2, Condition cond = al) {
626 tst(src1, Operand(src2), cond);
627 }
628
629 void teq(Register src1, const Operand& src2, Condition cond = al);
630
631 void cmp(Register src1, const Operand& src2, Condition cond = al);
632 void cmp(Register src1, Register src2, Condition cond = al) {
633 cmp(src1, Operand(src2), cond);
634 }
635
636 void cmn(Register src1, const Operand& src2, Condition cond = al);
637
638 void orr(Register dst, Register src1, const Operand& src2,
639 SBit s = LeaveCC, Condition cond = al);
640 void orr(Register dst, Register src1, Register src2,
641 SBit s = LeaveCC, Condition cond = al) {
642 orr(dst, src1, Operand(src2), s, cond);
643 }
644
645 void mov(Register dst, const Operand& src,
646 SBit s = LeaveCC, Condition cond = al);
647 void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
648 mov(dst, Operand(src), s, cond);
649 }
650
651 void bic(Register dst, Register src1, const Operand& src2,
652 SBit s = LeaveCC, Condition cond = al);
653
654 void mvn(Register dst, const Operand& src,
655 SBit s = LeaveCC, Condition cond = al);
656
657 // Multiply instructions
658
659 void mla(Register dst, Register src1, Register src2, Register srcA,
660 SBit s = LeaveCC, Condition cond = al);
661
662 void mul(Register dst, Register src1, Register src2,
663 SBit s = LeaveCC, Condition cond = al);
664
665 void smlal(Register dstL, Register dstH, Register src1, Register src2,
666 SBit s = LeaveCC, Condition cond = al);
667
668 void smull(Register dstL, Register dstH, Register src1, Register src2,
669 SBit s = LeaveCC, Condition cond = al);
670
671 void umlal(Register dstL, Register dstH, Register src1, Register src2,
672 SBit s = LeaveCC, Condition cond = al);
673
674 void umull(Register dstL, Register dstH, Register src1, Register src2,
675 SBit s = LeaveCC, Condition cond = al);
676
677 // Miscellaneous arithmetic instructions
678
679 void clz(Register dst, Register src, Condition cond = al); // v5 and above
680
681 // Status register access instructions
682
683 void mrs(Register dst, SRegister s, Condition cond = al);
684 void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al);
685
686 // Load/Store instructions
687 void ldr(Register dst, const MemOperand& src, Condition cond = al);
688 void str(Register src, const MemOperand& dst, Condition cond = al);
689 void ldrb(Register dst, const MemOperand& src, Condition cond = al);
690 void strb(Register src, const MemOperand& dst, Condition cond = al);
691 void ldrh(Register dst, const MemOperand& src, Condition cond = al);
692 void strh(Register src, const MemOperand& dst, Condition cond = al);
693 void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
694 void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
695
696 // Load/Store multiple instructions
697 void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
698 void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
699
700 // Semaphore instructions
701 void swp(Register dst, Register src, Register base, Condition cond = al);
702 void swpb(Register dst, Register src, Register base, Condition cond = al);
703
704 // Exception-generating instructions and debugging support
705 void stop(const char* msg);
706
707 void bkpt(uint32_t imm16); // v5 and above
708 void swi(uint32_t imm24, Condition cond = al);
709
710 // Coprocessor instructions
711
712 void cdp(Coprocessor coproc, int opcode_1,
713 CRegister crd, CRegister crn, CRegister crm,
714 int opcode_2, Condition cond = al);
715
716 void cdp2(Coprocessor coproc, int opcode_1,
717 CRegister crd, CRegister crn, CRegister crm,
718 int opcode_2); // v5 and above
719
720 void mcr(Coprocessor coproc, int opcode_1,
721 Register rd, CRegister crn, CRegister crm,
722 int opcode_2 = 0, Condition cond = al);
723
724 void mcr2(Coprocessor coproc, int opcode_1,
725 Register rd, CRegister crn, CRegister crm,
726 int opcode_2 = 0); // v5 and above
727
728 void mrc(Coprocessor coproc, int opcode_1,
729 Register rd, CRegister crn, CRegister crm,
730 int opcode_2 = 0, Condition cond = al);
731
732 void mrc2(Coprocessor coproc, int opcode_1,
733 Register rd, CRegister crn, CRegister crm,
734 int opcode_2 = 0); // v5 and above
735
736 void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src,
737 LFlag l = Short, Condition cond = al);
738 void ldc(Coprocessor coproc, CRegister crd, Register base, int option,
739 LFlag l = Short, Condition cond = al);
740
741 void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
742 LFlag l = Short); // v5 and above
743 void ldc2(Coprocessor coproc, CRegister crd, Register base, int option,
744 LFlag l = Short); // v5 and above
745
746 void stc(Coprocessor coproc, CRegister crd, const MemOperand& dst,
747 LFlag l = Short, Condition cond = al);
748 void stc(Coprocessor coproc, CRegister crd, Register base, int option,
749 LFlag l = Short, Condition cond = al);
750
751 void stc2(Coprocessor coproc, CRegister crd, const MemOperand& dst,
752 LFlag l = Short); // v5 and above
753 void stc2(Coprocessor coproc, CRegister crd, Register base, int option,
754 LFlag l = Short); // v5 and above
755
Steve Blockd0582a62009-12-15 09:54:21 +0000756 // Support for VFP.
757 // All these APIs support S0 to S31 and D0 to D15.
758 // Currently these APIs do not support extended D registers, i.e, D16 to D31.
759 // However, some simple modifications can allow
760 // these APIs to support D16 to D31.
761
762 void fmdrr(const Register dst,
763 const Register src1,
764 const Register src2,
765 const SBit s = LeaveCC,
766 const Condition cond = al);
767 void fmrrd(const Register dst1,
768 const Register dst2,
769 const Register src,
770 const SBit s = LeaveCC,
771 const Condition cond = al);
772 void fmsr(const Register dst,
773 const Register src,
774 const SBit s = LeaveCC,
775 const Condition cond = al);
776 void fmrs(const Register dst,
777 const Register src,
778 const SBit s = LeaveCC,
779 const Condition cond = al);
780 void fsitod(const Register dst,
781 const Register src,
782 const SBit s = LeaveCC,
783 const Condition cond = al);
784 void ftosid(const Register dst,
785 const Register src,
786 const SBit s = LeaveCC,
787 const Condition cond = al);
788
789 void faddd(const Register dst,
790 const Register src1,
791 const Register src2,
792 const SBit s = LeaveCC,
793 const Condition cond = al);
794 void fsubd(const Register dst,
795 const Register src1,
796 const Register src2,
797 const SBit s = LeaveCC,
798 const Condition cond = al);
799 void fmuld(const Register dst,
800 const Register src1,
801 const Register src2,
802 const SBit s = LeaveCC,
803 const Condition cond = al);
804 void fdivd(const Register dst,
805 const Register src1,
806 const Register src2,
807 const SBit s = LeaveCC,
808 const Condition cond = al);
809 void fcmp(const Register src1,
810 const Register src2,
811 const SBit s = LeaveCC,
812 const Condition cond = al);
813 void vmrs(const Register dst,
814 const Condition cond = al);
815
Steve Blocka7e24c12009-10-30 11:49:00 +0000816 // Pseudo instructions
817 void nop() { mov(r0, Operand(r0)); }
818
819 void push(Register src, Condition cond = al) {
820 str(src, MemOperand(sp, 4, NegPreIndex), cond);
821 }
822
823 void pop(Register dst, Condition cond = al) {
824 ldr(dst, MemOperand(sp, 4, PostIndex), cond);
825 }
826
827 void pop() {
828 add(sp, sp, Operand(kPointerSize));
829 }
830
831 // Load effective address of memory operand x into register dst
832 void lea(Register dst, const MemOperand& x,
833 SBit s = LeaveCC, Condition cond = al);
834
835 // Jump unconditionally to given label.
836 void jmp(Label* L) { b(L, al); }
837
838 // Check the code size generated from label to here.
839 int InstructionsGeneratedSince(Label* l) {
840 return (pc_offset() - l->pos()) / kInstrSize;
841 }
842
Steve Blockd0582a62009-12-15 09:54:21 +0000843 // Check whether an immediate fits an addressing mode 1 instruction.
844 bool ImmediateFitsAddrMode1Instruction(int32_t imm32);
845
846 // Postpone the generation of the constant pool for the specified number of
847 // instructions.
848 void BlockConstPoolFor(int instructions);
849
Steve Blocka7e24c12009-10-30 11:49:00 +0000850 // Debugging
851
852 // Mark address of the ExitJSFrame code.
853 void RecordJSReturn();
854
855 // Record a comment relocation entry that can be used by a disassembler.
856 // Use --debug_code to enable.
857 void RecordComment(const char* msg);
858
859 void RecordPosition(int pos);
860 void RecordStatementPosition(int pos);
861 void WriteRecordedPositions();
862
863 int pc_offset() const { return pc_ - buffer_; }
864 int current_position() const { return current_position_; }
865 int current_statement_position() const { return current_position_; }
866
867 protected:
868 int buffer_space() const { return reloc_info_writer.pos() - pc_; }
869
870 // Read/patch instructions
871 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
872 void instr_at_put(byte* pc, Instr instr) {
873 *reinterpret_cast<Instr*>(pc) = instr;
874 }
875 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
876 void instr_at_put(int pos, Instr instr) {
877 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
878 }
879
880 // Decode branch instruction at pos and return branch target pos
881 int target_at(int pos);
882
883 // Patch branch instruction at pos to branch to given branch target pos
884 void target_at_put(int pos, int target_pos);
885
886 // Check if is time to emit a constant pool for pending reloc info entries
887 void CheckConstPool(bool force_emit, bool require_jump);
888
889 // Block the emission of the constant pool before pc_offset
890 void BlockConstPoolBefore(int pc_offset) {
891 if (no_const_pool_before_ < pc_offset) no_const_pool_before_ = pc_offset;
892 }
893
894 private:
895 // Code buffer:
896 // The buffer into which code and relocation info are generated.
897 byte* buffer_;
898 int buffer_size_;
899 // True if the assembler owns the buffer, false if buffer is external.
900 bool own_buffer_;
901
902 // Buffer size and constant pool distance are checked together at regular
903 // intervals of kBufferCheckInterval emitted bytes
904 static const int kBufferCheckInterval = 1*KB/2;
905 int next_buffer_check_; // pc offset of next buffer check
906
907 // Code generation
908 // The relocation writer's position is at least kGap bytes below the end of
909 // the generated instructions. This is so that multi-instruction sequences do
910 // not have to check for overflow. The same is true for writes of large
911 // relocation info entries.
912 static const int kGap = 32;
913 byte* pc_; // the program counter; moves forward
914
915 // Constant pool generation
916 // Pools are emitted in the instruction stream, preferably after unconditional
917 // jumps or after returns from functions (in dead code locations).
918 // If a long code sequence does not contain unconditional jumps, it is
919 // necessary to emit the constant pool before the pool gets too far from the
920 // location it is accessed from. In this case, we emit a jump over the emitted
921 // constant pool.
922 // Constants in the pool may be addresses of functions that gets relocated;
923 // if so, a relocation info entry is associated to the constant pool entry.
924
925 // Repeated checking whether the constant pool should be emitted is rather
926 // expensive. By default we only check again once a number of instructions
927 // has been generated. That also means that the sizing of the buffers is not
928 // an exact science, and that we rely on some slop to not overrun buffers.
929 static const int kCheckConstIntervalInst = 32;
930 static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize;
931
932
933 // Pools are emitted after function return and in dead code at (more or less)
934 // regular intervals of kDistBetweenPools bytes
935 static const int kDistBetweenPools = 1*KB;
936
937 // Constants in pools are accessed via pc relative addressing, which can
938 // reach +/-4KB thereby defining a maximum distance between the instruction
939 // and the accessed constant. We satisfy this constraint by limiting the
940 // distance between pools.
941 static const int kMaxDistBetweenPools = 4*KB - 2*kBufferCheckInterval;
942
943 // Emission of the constant pool may be blocked in some code sequences
944 int no_const_pool_before_; // block emission before this pc offset
945
946 // Keep track of the last emitted pool to guarantee a maximal distance
947 int last_const_pool_end_; // pc offset following the last constant pool
948
949 // Relocation info generation
950 // Each relocation is encoded as a variable size value
951 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
952 RelocInfoWriter reloc_info_writer;
953 // Relocation info records are also used during code generation as temporary
954 // containers for constants and code target addresses until they are emitted
955 // to the constant pool. These pending relocation info records are temporarily
956 // stored in a separate buffer until a constant pool is emitted.
957 // If every instruction in a long sequence is accessing the pool, we need one
958 // pending relocation entry per instruction.
959 static const int kMaxNumPRInfo = kMaxDistBetweenPools/kInstrSize;
960 RelocInfo prinfo_[kMaxNumPRInfo]; // the buffer of pending relocation info
961 int num_prinfo_; // number of pending reloc info entries in the buffer
962
963 // The bound position, before this we cannot do instruction elimination.
964 int last_bound_pos_;
965
966 // source position information
967 int current_position_;
968 int current_statement_position_;
969 int written_position_;
970 int written_statement_position_;
971
972 // Code emission
973 inline void CheckBuffer();
974 void GrowBuffer();
975 inline void emit(Instr x);
976
977 // Instruction generation
978 void addrmod1(Instr instr, Register rn, Register rd, const Operand& x);
979 void addrmod2(Instr instr, Register rd, const MemOperand& x);
980 void addrmod3(Instr instr, Register rd, const MemOperand& x);
981 void addrmod4(Instr instr, Register rn, RegList rl);
982 void addrmod5(Instr instr, CRegister crd, const MemOperand& x);
983
984 // Labels
985 void print(Label* L);
986 void bind_to(Label* L, int pos);
987 void link_to(Label* L, Label* appendix);
988 void next(Label* L);
989
990 // Record reloc info for current pc_
991 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
992
993 friend class RegExpMacroAssemblerARM;
994 friend class RelocInfo;
995 friend class CodePatcher;
996};
997
998} } // namespace v8::internal
999
1000#endif // V8_ARM_ASSEMBLER_ARM_H_