blob: 839ed67375b1884ed417683bfff1c1f77f1f9d2f [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright (c) 1994-2006 Sun Microsystems Inc.
2// All Rights Reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions
6// are met:
7//
8// - Redistributions of source code must retain the above copyright notice,
9// this list of conditions and the following disclaimer.
10//
11// - Redistribution in binary form must reproduce the above copyright
12// notice, this list of conditions and the following disclaimer in the
13// documentation and/or other materials provided with the
14// distribution.
15//
16// - Neither the name of Sun Microsystems or the names of contributors may
17// be used to endorse or promote products derived from this software without
18// specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31// OF THE POSSIBILITY OF SUCH DAMAGE.
32
Leon Clarked91b9f72010-01-27 17:25:45 +000033// The original source code covered by the above license above has been
34// modified significantly by Google Inc.
35// Copyright 2010 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +000036
37// A light-weight ARM Assembler
38// Generates user mode instructions for the ARM architecture up to version 5
39
40#ifndef V8_ARM_ASSEMBLER_ARM_H_
41#define V8_ARM_ASSEMBLER_ARM_H_
42#include <stdio.h>
43#include "assembler.h"
Steve Blockd0582a62009-12-15 09:54:21 +000044#include "serialize.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000045
46namespace v8 {
47namespace internal {
48
49// CPU Registers.
50//
51// 1) We would prefer to use an enum, but enum values are assignment-
52// compatible with int, which has caused code-generation bugs.
53//
54// 2) We would prefer to use a class instead of a struct but we don't like
55// the register initialization to depend on the particular initialization
56// order (which appears to be different on OS X, Linux, and Windows for the
57// installed versions of C++ we tried). Using a struct permits C-style
58// "initialization". Also, the Register objects cannot be const as this
59// forces initialization stubs in MSVC, making us dependent on initialization
60// order.
61//
62// 3) By not using an enum, we are possibly preventing the compiler from
63// doing certain constant folds, which may significantly reduce the
64// code generated for some assembly instructions (because they boil down
65// to a few constants). If this is a problem, we could change the code
66// such that we use an enum in optimized mode, and the struct in debug
67// mode. This way we get the compile-time error checking in debug mode
68// and best performance in optimized code.
69//
70// Core register
71struct Register {
72 bool is_valid() const { return 0 <= code_ && code_ < 16; }
73 bool is(Register reg) const { return code_ == reg.code_; }
74 int code() const {
75 ASSERT(is_valid());
76 return code_;
77 }
78 int bit() const {
79 ASSERT(is_valid());
80 return 1 << code_;
81 }
82
Andrei Popescu31002712010-02-23 13:46:05 +000083 // Unfortunately we can't make this private in a struct.
Steve Blocka7e24c12009-10-30 11:49:00 +000084 int code_;
85};
86
Steve Block6ded16b2010-05-10 14:33:55 +010087const Register no_reg = { -1 };
Steve Blocka7e24c12009-10-30 11:49:00 +000088
Steve Block6ded16b2010-05-10 14:33:55 +010089const Register r0 = { 0 };
90const Register r1 = { 1 };
91const Register r2 = { 2 };
92const Register r3 = { 3 };
93const Register r4 = { 4 };
94const Register r5 = { 5 };
95const Register r6 = { 6 };
96const Register r7 = { 7 };
97const Register r8 = { 8 }; // Used as context register.
98const Register r9 = { 9 };
99const Register r10 = { 10 }; // Used as roots register.
100const Register fp = { 11 };
101const Register ip = { 12 };
102const Register sp = { 13 };
103const Register lr = { 14 };
104const Register pc = { 15 };
Steve Blockd0582a62009-12-15 09:54:21 +0000105
Leon Clarkee46be812010-01-19 14:06:41 +0000106// Single word VFP register.
107struct SwVfpRegister {
108 bool is_valid() const { return 0 <= code_ && code_ < 32; }
109 bool is(SwVfpRegister reg) const { return code_ == reg.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 int code_;
120};
121
122
123// Double word VFP register.
124struct DwVfpRegister {
125 // Supporting d0 to d15, can be later extended to d31.
126 bool is_valid() const { return 0 <= code_ && code_ < 16; }
127 bool is(DwVfpRegister reg) const { return code_ == reg.code_; }
128 int code() const {
129 ASSERT(is_valid());
130 return code_;
131 }
132 int bit() const {
133 ASSERT(is_valid());
134 return 1 << code_;
135 }
136
137 int code_;
138};
139
140
Steve Block6ded16b2010-05-10 14:33:55 +0100141// Support for the VFP registers s0 to s31 (d0 to d15).
Leon Clarkee46be812010-01-19 14:06:41 +0000142// Note that "s(N):s(N+1)" is the same as "d(N/2)".
Steve Block6ded16b2010-05-10 14:33:55 +0100143const SwVfpRegister s0 = { 0 };
144const SwVfpRegister s1 = { 1 };
145const SwVfpRegister s2 = { 2 };
146const SwVfpRegister s3 = { 3 };
147const SwVfpRegister s4 = { 4 };
148const SwVfpRegister s5 = { 5 };
149const SwVfpRegister s6 = { 6 };
150const SwVfpRegister s7 = { 7 };
151const SwVfpRegister s8 = { 8 };
152const SwVfpRegister s9 = { 9 };
153const SwVfpRegister s10 = { 10 };
154const SwVfpRegister s11 = { 11 };
155const SwVfpRegister s12 = { 12 };
156const SwVfpRegister s13 = { 13 };
157const SwVfpRegister s14 = { 14 };
158const SwVfpRegister s15 = { 15 };
159const SwVfpRegister s16 = { 16 };
160const SwVfpRegister s17 = { 17 };
161const SwVfpRegister s18 = { 18 };
162const SwVfpRegister s19 = { 19 };
163const SwVfpRegister s20 = { 20 };
164const SwVfpRegister s21 = { 21 };
165const SwVfpRegister s22 = { 22 };
166const SwVfpRegister s23 = { 23 };
167const SwVfpRegister s24 = { 24 };
168const SwVfpRegister s25 = { 25 };
169const SwVfpRegister s26 = { 26 };
170const SwVfpRegister s27 = { 27 };
171const SwVfpRegister s28 = { 28 };
172const SwVfpRegister s29 = { 29 };
173const SwVfpRegister s30 = { 30 };
174const SwVfpRegister s31 = { 31 };
Leon Clarkee46be812010-01-19 14:06:41 +0000175
Steve Block6ded16b2010-05-10 14:33:55 +0100176const DwVfpRegister d0 = { 0 };
177const DwVfpRegister d1 = { 1 };
178const DwVfpRegister d2 = { 2 };
179const DwVfpRegister d3 = { 3 };
180const DwVfpRegister d4 = { 4 };
181const DwVfpRegister d5 = { 5 };
182const DwVfpRegister d6 = { 6 };
183const DwVfpRegister d7 = { 7 };
184const DwVfpRegister d8 = { 8 };
185const DwVfpRegister d9 = { 9 };
186const DwVfpRegister d10 = { 10 };
187const DwVfpRegister d11 = { 11 };
188const DwVfpRegister d12 = { 12 };
189const DwVfpRegister d13 = { 13 };
190const DwVfpRegister d14 = { 14 };
191const DwVfpRegister d15 = { 15 };
Leon Clarkee46be812010-01-19 14:06:41 +0000192
Steve Blocka7e24c12009-10-30 11:49:00 +0000193
194// Coprocessor register
195struct CRegister {
196 bool is_valid() const { return 0 <= code_ && code_ < 16; }
197 bool is(CRegister creg) const { return code_ == creg.code_; }
198 int code() const {
199 ASSERT(is_valid());
200 return code_;
201 }
202 int bit() const {
203 ASSERT(is_valid());
204 return 1 << code_;
205 }
206
Andrei Popescu31002712010-02-23 13:46:05 +0000207 // Unfortunately we can't make this private in a struct.
Steve Blocka7e24c12009-10-30 11:49:00 +0000208 int code_;
209};
210
211
Steve Block6ded16b2010-05-10 14:33:55 +0100212const CRegister no_creg = { -1 };
213
214const CRegister cr0 = { 0 };
215const CRegister cr1 = { 1 };
216const CRegister cr2 = { 2 };
217const CRegister cr3 = { 3 };
218const CRegister cr4 = { 4 };
219const CRegister cr5 = { 5 };
220const CRegister cr6 = { 6 };
221const CRegister cr7 = { 7 };
222const CRegister cr8 = { 8 };
223const CRegister cr9 = { 9 };
224const CRegister cr10 = { 10 };
225const CRegister cr11 = { 11 };
226const CRegister cr12 = { 12 };
227const CRegister cr13 = { 13 };
228const CRegister cr14 = { 14 };
229const CRegister cr15 = { 15 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000230
231
232// Coprocessor number
233enum Coprocessor {
234 p0 = 0,
235 p1 = 1,
236 p2 = 2,
237 p3 = 3,
238 p4 = 4,
239 p5 = 5,
240 p6 = 6,
241 p7 = 7,
242 p8 = 8,
243 p9 = 9,
244 p10 = 10,
245 p11 = 11,
246 p12 = 12,
247 p13 = 13,
248 p14 = 14,
249 p15 = 15
250};
251
252
Andrei Popescu31002712010-02-23 13:46:05 +0000253// Condition field in instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +0000254enum Condition {
255 eq = 0 << 28, // Z set equal.
256 ne = 1 << 28, // Z clear not equal.
257 nz = 1 << 28, // Z clear not zero.
258 cs = 2 << 28, // C set carry set.
259 hs = 2 << 28, // C set unsigned higher or same.
260 cc = 3 << 28, // C clear carry clear.
261 lo = 3 << 28, // C clear unsigned lower.
262 mi = 4 << 28, // N set negative.
263 pl = 5 << 28, // N clear positive or zero.
264 vs = 6 << 28, // V set overflow.
265 vc = 7 << 28, // V clear no overflow.
266 hi = 8 << 28, // C set, Z clear unsigned higher.
267 ls = 9 << 28, // C clear or Z set unsigned lower or same.
268 ge = 10 << 28, // N == V greater or equal.
269 lt = 11 << 28, // N != V less than.
270 gt = 12 << 28, // Z clear, N == V greater than.
271 le = 13 << 28, // Z set or N != V less then or equal
272 al = 14 << 28 // always.
273};
274
275
276// Returns the equivalent of !cc.
277INLINE(Condition NegateCondition(Condition cc));
278
279
280// Corresponds to transposing the operands of a comparison.
281inline Condition ReverseCondition(Condition cc) {
282 switch (cc) {
283 case lo:
284 return hi;
285 case hi:
286 return lo;
287 case hs:
288 return ls;
289 case ls:
290 return hs;
291 case lt:
292 return gt;
293 case gt:
294 return lt;
295 case ge:
296 return le;
297 case le:
298 return ge;
299 default:
300 return cc;
301 };
302}
303
304
305// Branch hints are not used on the ARM. They are defined so that they can
306// appear in shared function signatures, but will be ignored in ARM
307// implementations.
308enum Hint { no_hint };
309
310// Hints are not used on the arm. Negating is trivial.
311inline Hint NegateHint(Hint ignored) { return no_hint; }
312
313
314// -----------------------------------------------------------------------------
315// Addressing modes and instruction variants
316
317// Shifter operand shift operation
318enum ShiftOp {
319 LSL = 0 << 5,
320 LSR = 1 << 5,
321 ASR = 2 << 5,
322 ROR = 3 << 5,
323 RRX = -1
324};
325
326
327// Condition code updating mode
328enum SBit {
329 SetCC = 1 << 20, // set condition code
330 LeaveCC = 0 << 20 // leave condition code unchanged
331};
332
333
334// Status register selection
335enum SRegister {
336 CPSR = 0 << 22,
337 SPSR = 1 << 22
338};
339
340
341// Status register fields
342enum SRegisterField {
343 CPSR_c = CPSR | 1 << 16,
344 CPSR_x = CPSR | 1 << 17,
345 CPSR_s = CPSR | 1 << 18,
346 CPSR_f = CPSR | 1 << 19,
347 SPSR_c = SPSR | 1 << 16,
348 SPSR_x = SPSR | 1 << 17,
349 SPSR_s = SPSR | 1 << 18,
350 SPSR_f = SPSR | 1 << 19
351};
352
353// Status register field mask (or'ed SRegisterField enum values)
354typedef uint32_t SRegisterFieldMask;
355
356
357// Memory operand addressing mode
358enum AddrMode {
359 // bit encoding P U W
360 Offset = (8|4|0) << 21, // offset (without writeback to base)
361 PreIndex = (8|4|1) << 21, // pre-indexed addressing with writeback
362 PostIndex = (0|4|0) << 21, // post-indexed addressing with writeback
363 NegOffset = (8|0|0) << 21, // negative offset (without writeback to base)
364 NegPreIndex = (8|0|1) << 21, // negative pre-indexed with writeback
365 NegPostIndex = (0|0|0) << 21 // negative post-indexed with writeback
366};
367
368
369// Load/store multiple addressing mode
370enum BlockAddrMode {
371 // bit encoding P U W
372 da = (0|0|0) << 21, // decrement after
373 ia = (0|4|0) << 21, // increment after
374 db = (8|0|0) << 21, // decrement before
375 ib = (8|4|0) << 21, // increment before
376 da_w = (0|0|1) << 21, // decrement after with writeback to base
377 ia_w = (0|4|1) << 21, // increment after with writeback to base
378 db_w = (8|0|1) << 21, // decrement before with writeback to base
379 ib_w = (8|4|1) << 21 // increment before with writeback to base
380};
381
382
383// Coprocessor load/store operand size
384enum LFlag {
385 Long = 1 << 22, // long load/store coprocessor
386 Short = 0 << 22 // short load/store coprocessor
387};
388
389
390// -----------------------------------------------------------------------------
391// Machine instruction Operands
392
393// Class Operand represents a shifter operand in data processing instructions
394class Operand BASE_EMBEDDED {
395 public:
396 // immediate
397 INLINE(explicit Operand(int32_t immediate,
398 RelocInfo::Mode rmode = RelocInfo::NONE));
399 INLINE(explicit Operand(const ExternalReference& f));
400 INLINE(explicit Operand(const char* s));
Steve Blocka7e24c12009-10-30 11:49:00 +0000401 explicit Operand(Handle<Object> handle);
402 INLINE(explicit Operand(Smi* value));
403
404 // rm
405 INLINE(explicit Operand(Register rm));
406
407 // rm <shift_op> shift_imm
408 explicit Operand(Register rm, ShiftOp shift_op, int shift_imm);
409
410 // rm <shift_op> rs
411 explicit Operand(Register rm, ShiftOp shift_op, Register rs);
412
413 // Return true if this is a register operand.
414 INLINE(bool is_reg() const);
415
416 Register rm() const { return rm_; }
417
418 private:
419 Register rm_;
420 Register rs_;
421 ShiftOp shift_op_;
422 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
423 int32_t imm32_; // valid if rm_ == no_reg
424 RelocInfo::Mode rmode_;
425
426 friend class Assembler;
427};
428
429
430// Class MemOperand represents a memory operand in load and store instructions
431class MemOperand BASE_EMBEDDED {
432 public:
433 // [rn +/- offset] Offset/NegOffset
434 // [rn +/- offset]! PreIndex/NegPreIndex
435 // [rn], +/- offset PostIndex/NegPostIndex
436 // offset is any signed 32-bit value; offset is first loaded to register ip if
437 // it does not fit the addressing mode (12-bit unsigned and sign bit)
438 explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset);
439
440 // [rn +/- rm] Offset/NegOffset
441 // [rn +/- rm]! PreIndex/NegPreIndex
442 // [rn], +/- rm PostIndex/NegPostIndex
443 explicit MemOperand(Register rn, Register rm, AddrMode am = Offset);
444
445 // [rn +/- rm <shift_op> shift_imm] Offset/NegOffset
446 // [rn +/- rm <shift_op> shift_imm]! PreIndex/NegPreIndex
447 // [rn], +/- rm <shift_op> shift_imm PostIndex/NegPostIndex
448 explicit MemOperand(Register rn, Register rm,
449 ShiftOp shift_op, int shift_imm, AddrMode am = Offset);
450
451 private:
452 Register rn_; // base
453 Register rm_; // register offset
454 int32_t offset_; // valid if rm_ == no_reg
455 ShiftOp shift_op_;
456 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
457 AddrMode am_; // bits P, U, and W
458
459 friend class Assembler;
460};
461
Steve Blockd0582a62009-12-15 09:54:21 +0000462// CpuFeatures keeps track of which features are supported by the target CPU.
463// Supported features must be enabled by a Scope before use.
464class CpuFeatures : public AllStatic {
465 public:
466 // Detect features of the target CPU. Set safe defaults if the serializer
467 // is enabled (snapshots must be portable).
468 static void Probe();
469
470 // Check whether a feature is supported by the target CPU.
471 static bool IsSupported(CpuFeature f) {
472 if (f == VFP3 && !FLAG_enable_vfp3) return false;
473 return (supported_ & (1u << f)) != 0;
474 }
475
476 // Check whether a feature is currently enabled.
477 static bool IsEnabled(CpuFeature f) {
478 return (enabled_ & (1u << f)) != 0;
479 }
480
481 // Enable a specified feature within a scope.
482 class Scope BASE_EMBEDDED {
483#ifdef DEBUG
484 public:
485 explicit Scope(CpuFeature f) {
486 ASSERT(CpuFeatures::IsSupported(f));
487 ASSERT(!Serializer::enabled() ||
488 (found_by_runtime_probing_ & (1u << f)) == 0);
489 old_enabled_ = CpuFeatures::enabled_;
490 CpuFeatures::enabled_ |= 1u << f;
491 }
492 ~Scope() { CpuFeatures::enabled_ = old_enabled_; }
493 private:
494 unsigned old_enabled_;
495#else
496 public:
497 explicit Scope(CpuFeature f) {}
498#endif
499 };
500
501 private:
502 static unsigned supported_;
503 static unsigned enabled_;
504 static unsigned found_by_runtime_probing_;
505};
506
Steve Blocka7e24c12009-10-30 11:49:00 +0000507
508typedef int32_t Instr;
509
510
511extern const Instr kMovLrPc;
Steve Block6ded16b2010-05-10 14:33:55 +0100512extern const Instr kLdrPCMask;
Steve Blocka7e24c12009-10-30 11:49:00 +0000513extern const Instr kLdrPCPattern;
Steve Block6ded16b2010-05-10 14:33:55 +0100514extern const Instr kBlxRegMask;
515extern const Instr kBlxRegPattern;
Steve Blocka7e24c12009-10-30 11:49:00 +0000516
517
518class Assembler : public Malloced {
519 public:
520 // Create an assembler. Instructions and relocation information are emitted
521 // into a buffer, with the instructions starting from the beginning and the
522 // relocation information starting from the end of the buffer. See CodeDesc
523 // for a detailed comment on the layout (globals.h).
524 //
525 // If the provided buffer is NULL, the assembler allocates and grows its own
526 // buffer, and buffer_size determines the initial buffer size. The buffer is
527 // owned by the assembler and deallocated upon destruction of the assembler.
528 //
529 // If the provided buffer is not NULL, the assembler uses the provided buffer
530 // for code generation and assumes its size to be buffer_size. If the buffer
531 // is too small, a fatal error occurs. No deallocation of the buffer is done
532 // upon destruction of the assembler.
533 Assembler(void* buffer, int buffer_size);
534 ~Assembler();
535
536 // GetCode emits any pending (non-emitted) code and fills the descriptor
537 // desc. GetCode() is idempotent; it returns the same result if no other
538 // Assembler functions are invoked in between GetCode() calls.
539 void GetCode(CodeDesc* desc);
540
541 // Label operations & relative jumps (PPUM Appendix D)
542 //
543 // Takes a branch opcode (cc) and a label (L) and generates
544 // either a backward branch or a forward branch and links it
545 // to the label fixup chain. Usage:
546 //
547 // Label L; // unbound label
548 // j(cc, &L); // forward branch to unbound label
549 // bind(&L); // bind label to the current pc
550 // j(cc, &L); // backward branch to bound label
551 // bind(&L); // illegal: a label may be bound only once
552 //
553 // Note: The same Label can be used for forward and backward branches
554 // but it may be bound only once.
555
556 void bind(Label* L); // binds an unbound label L to the current code position
557
558 // Returns the branch offset to the given label from the current code position
559 // Links the label to the current position if it is still unbound
560 // Manages the jump elimination optimization if the second parameter is true.
561 int branch_offset(Label* L, bool jump_elimination_allowed);
562
563 // Puts a labels target address at the given position.
564 // The high 8 bits are set to zero.
565 void label_at_put(Label* L, int at_offset);
566
567 // Return the address in the constant pool of the code target address used by
568 // the branch/call instruction at pc.
569 INLINE(static Address target_address_address_at(Address pc));
570
571 // Read/Modify the code target address in the branch/call instruction at pc.
572 INLINE(static Address target_address_at(Address pc));
573 INLINE(static void set_target_address_at(Address pc, Address target));
574
Steve Blockd0582a62009-12-15 09:54:21 +0000575 // This sets the branch destination (which is in the constant pool on ARM).
576 // This is for calls and branches within generated code.
577 inline static void set_target_at(Address constant_pool_entry, Address target);
578
579 // This sets the branch destination (which is in the constant pool on ARM).
580 // This is for calls and branches to runtime code.
581 inline static void set_external_target_at(Address constant_pool_entry,
582 Address target) {
583 set_target_at(constant_pool_entry, target);
584 }
585
586 // Here we are patching the address in the constant pool, not the actual call
587 // instruction. The address in the constant pool is the same size as a
588 // pointer.
589 static const int kCallTargetSize = kPointerSize;
590 static const int kExternalTargetSize = kPointerSize;
591
Steve Blocka7e24c12009-10-30 11:49:00 +0000592 // Size of an instruction.
593 static const int kInstrSize = sizeof(Instr);
594
595 // Distance between the instruction referring to the address of the call
Steve Block6ded16b2010-05-10 14:33:55 +0100596 // target and the return address.
597#ifdef USE_BLX
598 // Call sequence is:
599 // ldr ip, [pc, #...] @ call address
600 // blx ip
601 // @ return address
602 static const int kCallTargetAddressOffset = 2 * kInstrSize;
603#else
604 // Call sequence is:
605 // mov lr, pc
606 // ldr pc, [pc, #...] @ call address
607 // @ return address
Steve Blocka7e24c12009-10-30 11:49:00 +0000608 static const int kCallTargetAddressOffset = kInstrSize;
Steve Block6ded16b2010-05-10 14:33:55 +0100609#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000610
611 // Distance between start of patched return sequence and the emitted address
612 // to jump to.
Steve Block6ded16b2010-05-10 14:33:55 +0100613#ifdef USE_BLX
614 // Return sequence is:
615 // ldr ip, [pc, #0] @ emited address and start
616 // blx ip
617 static const int kPatchReturnSequenceAddressOffset = 0 * kInstrSize;
618#else
619 // Return sequence is:
620 // mov lr, pc @ start of sequence
621 // ldr pc, [pc, #-4] @ emited address
622 static const int kPatchReturnSequenceAddressOffset = kInstrSize;
623#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000624
625 // Difference between address of current opcode and value read from pc
626 // register.
627 static const int kPcLoadDelta = 8;
628
Steve Blockd0582a62009-12-15 09:54:21 +0000629 static const int kJSReturnSequenceLength = 4;
Steve Blocka7e24c12009-10-30 11:49:00 +0000630
631 // ---------------------------------------------------------------------------
632 // Code generation
633
634 // Insert the smallest number of nop instructions
635 // possible to align the pc offset to a multiple
636 // of m. m must be a power of 2 (>= 4).
637 void Align(int m);
638
639 // Branch instructions
640 void b(int branch_offset, Condition cond = al);
641 void bl(int branch_offset, Condition cond = al);
642 void blx(int branch_offset); // v5 and above
643 void blx(Register target, Condition cond = al); // v5 and above
644 void bx(Register target, Condition cond = al); // v5 and above, plus v4t
645
646 // Convenience branch instructions using labels
647 void b(Label* L, Condition cond = al) {
648 b(branch_offset(L, cond == al), cond);
649 }
650 void b(Condition cond, Label* L) { b(branch_offset(L, cond == al), cond); }
651 void bl(Label* L, Condition cond = al) { bl(branch_offset(L, false), cond); }
652 void bl(Condition cond, Label* L) { bl(branch_offset(L, false), cond); }
653 void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above
654
655 // Data-processing instructions
Andrei Popescu31002712010-02-23 13:46:05 +0000656 void ubfx(Register dst, Register src1, const Operand& src2,
657 const Operand& src3, Condition cond = al);
658
Steve Blocka7e24c12009-10-30 11:49:00 +0000659 void and_(Register dst, Register src1, const Operand& src2,
660 SBit s = LeaveCC, Condition cond = al);
661
662 void eor(Register dst, Register src1, const Operand& src2,
663 SBit s = LeaveCC, Condition cond = al);
664
665 void sub(Register dst, Register src1, const Operand& src2,
666 SBit s = LeaveCC, Condition cond = al);
667 void sub(Register dst, Register src1, Register src2,
668 SBit s = LeaveCC, Condition cond = al) {
669 sub(dst, src1, Operand(src2), s, cond);
670 }
671
672 void rsb(Register dst, Register src1, const Operand& src2,
673 SBit s = LeaveCC, Condition cond = al);
674
675 void add(Register dst, Register src1, const Operand& src2,
676 SBit s = LeaveCC, Condition cond = al);
677
678 void adc(Register dst, Register src1, const Operand& src2,
679 SBit s = LeaveCC, Condition cond = al);
680
681 void sbc(Register dst, Register src1, const Operand& src2,
682 SBit s = LeaveCC, Condition cond = al);
683
684 void rsc(Register dst, Register src1, const Operand& src2,
685 SBit s = LeaveCC, Condition cond = al);
686
687 void tst(Register src1, const Operand& src2, Condition cond = al);
688 void tst(Register src1, Register src2, Condition cond = al) {
689 tst(src1, Operand(src2), cond);
690 }
691
692 void teq(Register src1, const Operand& src2, Condition cond = al);
693
694 void cmp(Register src1, const Operand& src2, Condition cond = al);
695 void cmp(Register src1, Register src2, Condition cond = al) {
696 cmp(src1, Operand(src2), cond);
697 }
698
699 void cmn(Register src1, const Operand& src2, Condition cond = al);
700
701 void orr(Register dst, Register src1, const Operand& src2,
702 SBit s = LeaveCC, Condition cond = al);
703 void orr(Register dst, Register src1, Register src2,
704 SBit s = LeaveCC, Condition cond = al) {
705 orr(dst, src1, Operand(src2), s, cond);
706 }
707
708 void mov(Register dst, const Operand& src,
709 SBit s = LeaveCC, Condition cond = al);
710 void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
711 mov(dst, Operand(src), s, cond);
712 }
713
714 void bic(Register dst, Register src1, const Operand& src2,
715 SBit s = LeaveCC, Condition cond = al);
716
717 void mvn(Register dst, const Operand& src,
718 SBit s = LeaveCC, Condition cond = al);
719
720 // Multiply instructions
721
722 void mla(Register dst, Register src1, Register src2, Register srcA,
723 SBit s = LeaveCC, Condition cond = al);
724
725 void mul(Register dst, Register src1, Register src2,
726 SBit s = LeaveCC, Condition cond = al);
727
728 void smlal(Register dstL, Register dstH, Register src1, Register src2,
729 SBit s = LeaveCC, Condition cond = al);
730
731 void smull(Register dstL, Register dstH, Register src1, Register src2,
732 SBit s = LeaveCC, Condition cond = al);
733
734 void umlal(Register dstL, Register dstH, Register src1, Register src2,
735 SBit s = LeaveCC, Condition cond = al);
736
737 void umull(Register dstL, Register dstH, Register src1, Register src2,
738 SBit s = LeaveCC, Condition cond = al);
739
740 // Miscellaneous arithmetic instructions
741
742 void clz(Register dst, Register src, Condition cond = al); // v5 and above
743
744 // Status register access instructions
745
746 void mrs(Register dst, SRegister s, Condition cond = al);
747 void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al);
748
749 // Load/Store instructions
750 void ldr(Register dst, const MemOperand& src, Condition cond = al);
751 void str(Register src, const MemOperand& dst, Condition cond = al);
752 void ldrb(Register dst, const MemOperand& src, Condition cond = al);
753 void strb(Register src, const MemOperand& dst, Condition cond = al);
754 void ldrh(Register dst, const MemOperand& src, Condition cond = al);
755 void strh(Register src, const MemOperand& dst, Condition cond = al);
756 void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
757 void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
758
759 // Load/Store multiple instructions
760 void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
761 void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
762
763 // Semaphore instructions
764 void swp(Register dst, Register src, Register base, Condition cond = al);
765 void swpb(Register dst, Register src, Register base, Condition cond = al);
766
767 // Exception-generating instructions and debugging support
768 void stop(const char* msg);
769
770 void bkpt(uint32_t imm16); // v5 and above
771 void swi(uint32_t imm24, Condition cond = al);
772
773 // Coprocessor instructions
774
775 void cdp(Coprocessor coproc, int opcode_1,
776 CRegister crd, CRegister crn, CRegister crm,
777 int opcode_2, Condition cond = al);
778
779 void cdp2(Coprocessor coproc, int opcode_1,
780 CRegister crd, CRegister crn, CRegister crm,
781 int opcode_2); // v5 and above
782
783 void mcr(Coprocessor coproc, int opcode_1,
784 Register rd, CRegister crn, CRegister crm,
785 int opcode_2 = 0, Condition cond = al);
786
787 void mcr2(Coprocessor coproc, int opcode_1,
788 Register rd, CRegister crn, CRegister crm,
789 int opcode_2 = 0); // v5 and above
790
791 void mrc(Coprocessor coproc, int opcode_1,
792 Register rd, CRegister crn, CRegister crm,
793 int opcode_2 = 0, Condition cond = al);
794
795 void mrc2(Coprocessor coproc, int opcode_1,
796 Register rd, CRegister crn, CRegister crm,
797 int opcode_2 = 0); // v5 and above
798
799 void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src,
800 LFlag l = Short, Condition cond = al);
801 void ldc(Coprocessor coproc, CRegister crd, Register base, int option,
802 LFlag l = Short, Condition cond = al);
803
804 void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
805 LFlag l = Short); // v5 and above
806 void ldc2(Coprocessor coproc, CRegister crd, Register base, int option,
807 LFlag l = Short); // v5 and above
808
809 void stc(Coprocessor coproc, CRegister crd, const MemOperand& dst,
810 LFlag l = Short, Condition cond = al);
811 void stc(Coprocessor coproc, CRegister crd, Register base, int option,
812 LFlag l = Short, Condition cond = al);
813
814 void stc2(Coprocessor coproc, CRegister crd, const MemOperand& dst,
815 LFlag l = Short); // v5 and above
816 void stc2(Coprocessor coproc, CRegister crd, Register base, int option,
817 LFlag l = Short); // v5 and above
818
Steve Blockd0582a62009-12-15 09:54:21 +0000819 // Support for VFP.
820 // All these APIs support S0 to S31 and D0 to D15.
821 // Currently these APIs do not support extended D registers, i.e, D16 to D31.
822 // However, some simple modifications can allow
823 // these APIs to support D16 to D31.
824
Leon Clarked91b9f72010-01-27 17:25:45 +0000825 void vldr(const DwVfpRegister dst,
826 const Register base,
827 int offset, // Offset must be a multiple of 4.
828 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +0100829
830 void vldr(const SwVfpRegister dst,
831 const Register base,
832 int offset, // Offset must be a multiple of 4.
833 const Condition cond = al);
834
Leon Clarked91b9f72010-01-27 17:25:45 +0000835 void vstr(const DwVfpRegister src,
836 const Register base,
837 int offset, // Offset must be a multiple of 4.
838 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +0000839 void vmov(const DwVfpRegister dst,
840 const Register src1,
Steve Blockd0582a62009-12-15 09:54:21 +0000841 const Register src2,
Leon Clarkee46be812010-01-19 14:06:41 +0000842 const Condition cond = al);
843 void vmov(const Register dst1,
844 const Register dst2,
845 const DwVfpRegister src,
846 const Condition cond = al);
847 void vmov(const SwVfpRegister dst,
848 const Register src,
849 const Condition cond = al);
850 void vmov(const Register dst,
851 const SwVfpRegister src,
852 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +0100853 void vcvt_f64_s32(const DwVfpRegister dst,
854 const SwVfpRegister src,
855 const Condition cond = al);
856 void vcvt_f32_s32(const SwVfpRegister dst,
857 const SwVfpRegister src,
858 const Condition cond = al);
859 void vcvt_f64_u32(const DwVfpRegister dst,
860 const SwVfpRegister src,
861 const Condition cond = al);
862 void vcvt_s32_f64(const SwVfpRegister dst,
863 const DwVfpRegister src,
864 const Condition cond = al);
865 void vcvt_u32_f64(const SwVfpRegister dst,
866 const DwVfpRegister src,
867 const Condition cond = al);
868 void vcvt_f64_f32(const DwVfpRegister dst,
869 const SwVfpRegister src,
870 const Condition cond = al);
871 void vcvt_f32_f64(const SwVfpRegister dst,
872 const DwVfpRegister src,
873 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +0000874
875 void vadd(const DwVfpRegister dst,
876 const DwVfpRegister src1,
877 const DwVfpRegister src2,
878 const Condition cond = al);
879 void vsub(const DwVfpRegister dst,
880 const DwVfpRegister src1,
881 const DwVfpRegister src2,
882 const Condition cond = al);
883 void vmul(const DwVfpRegister dst,
884 const DwVfpRegister src1,
885 const DwVfpRegister src2,
886 const Condition cond = al);
887 void vdiv(const DwVfpRegister dst,
888 const DwVfpRegister src1,
889 const DwVfpRegister src2,
890 const Condition cond = al);
891 void vcmp(const DwVfpRegister src1,
892 const DwVfpRegister src2,
Steve Blockd0582a62009-12-15 09:54:21 +0000893 const SBit s = LeaveCC,
894 const Condition cond = al);
895 void vmrs(const Register dst,
896 const Condition cond = al);
897
Steve Blocka7e24c12009-10-30 11:49:00 +0000898 // Pseudo instructions
Steve Block6ded16b2010-05-10 14:33:55 +0100899 void nop(int type = 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000900
901 void push(Register src, Condition cond = al) {
902 str(src, MemOperand(sp, 4, NegPreIndex), cond);
903 }
904
905 void pop(Register dst, Condition cond = al) {
906 ldr(dst, MemOperand(sp, 4, PostIndex), cond);
907 }
908
909 void pop() {
910 add(sp, sp, Operand(kPointerSize));
911 }
912
913 // Load effective address of memory operand x into register dst
914 void lea(Register dst, const MemOperand& x,
915 SBit s = LeaveCC, Condition cond = al);
916
917 // Jump unconditionally to given label.
918 void jmp(Label* L) { b(L, al); }
919
920 // Check the code size generated from label to here.
921 int InstructionsGeneratedSince(Label* l) {
922 return (pc_offset() - l->pos()) / kInstrSize;
923 }
924
Steve Blockd0582a62009-12-15 09:54:21 +0000925 // Check whether an immediate fits an addressing mode 1 instruction.
926 bool ImmediateFitsAddrMode1Instruction(int32_t imm32);
927
Steve Block6ded16b2010-05-10 14:33:55 +0100928 // Class for scoping postponing the constant pool generation.
929 class BlockConstPoolScope {
930 public:
931 explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) {
932 assem_->StartBlockConstPool();
933 }
934 ~BlockConstPoolScope() {
935 assem_->EndBlockConstPool();
936 }
937
938 private:
939 Assembler* assem_;
940
941 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstPoolScope);
942 };
943
Steve Blockd0582a62009-12-15 09:54:21 +0000944 // Postpone the generation of the constant pool for the specified number of
945 // instructions.
946 void BlockConstPoolFor(int instructions);
947
Steve Blocka7e24c12009-10-30 11:49:00 +0000948 // Debugging
949
950 // Mark address of the ExitJSFrame code.
951 void RecordJSReturn();
952
953 // Record a comment relocation entry that can be used by a disassembler.
954 // Use --debug_code to enable.
955 void RecordComment(const char* msg);
956
957 void RecordPosition(int pos);
958 void RecordStatementPosition(int pos);
959 void WriteRecordedPositions();
960
961 int pc_offset() const { return pc_ - buffer_; }
962 int current_position() const { return current_position_; }
Steve Block6ded16b2010-05-10 14:33:55 +0100963 int current_statement_position() const { return current_statement_position_; }
964
965 // Read/patch instructions
966 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
967 static void instr_at_put(byte* pc, Instr instr) {
968 *reinterpret_cast<Instr*>(pc) = instr;
969 }
970 static bool IsNop(Instr instr, int type = 0);
971 static bool IsBranch(Instr instr);
972 static int GetBranchOffset(Instr instr);
973 static bool IsLdrRegisterImmediate(Instr instr);
974 static int GetLdrRegisterImmediateOffset(Instr instr);
975 static Instr SetLdrRegisterImmediateOffset(Instr instr, int offset);
976
Steve Blocka7e24c12009-10-30 11:49:00 +0000977
978 protected:
979 int buffer_space() const { return reloc_info_writer.pos() - pc_; }
980
981 // Read/patch instructions
Steve Blocka7e24c12009-10-30 11:49:00 +0000982 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
983 void instr_at_put(int pos, Instr instr) {
984 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
985 }
986
987 // Decode branch instruction at pos and return branch target pos
988 int target_at(int pos);
989
990 // Patch branch instruction at pos to branch to given branch target pos
991 void target_at_put(int pos, int target_pos);
992
993 // Check if is time to emit a constant pool for pending reloc info entries
994 void CheckConstPool(bool force_emit, bool require_jump);
995
996 // Block the emission of the constant pool before pc_offset
997 void BlockConstPoolBefore(int pc_offset) {
998 if (no_const_pool_before_ < pc_offset) no_const_pool_before_ = pc_offset;
999 }
1000
Steve Block6ded16b2010-05-10 14:33:55 +01001001 void StartBlockConstPool() {
1002 const_pool_blocked_nesting_++;
1003 }
1004 void EndBlockConstPool() {
1005 const_pool_blocked_nesting_--;
1006 }
1007
Steve Blocka7e24c12009-10-30 11:49:00 +00001008 private:
1009 // Code buffer:
1010 // The buffer into which code and relocation info are generated.
1011 byte* buffer_;
1012 int buffer_size_;
1013 // True if the assembler owns the buffer, false if buffer is external.
1014 bool own_buffer_;
1015
1016 // Buffer size and constant pool distance are checked together at regular
1017 // intervals of kBufferCheckInterval emitted bytes
1018 static const int kBufferCheckInterval = 1*KB/2;
1019 int next_buffer_check_; // pc offset of next buffer check
1020
1021 // Code generation
1022 // The relocation writer's position is at least kGap bytes below the end of
1023 // the generated instructions. This is so that multi-instruction sequences do
1024 // not have to check for overflow. The same is true for writes of large
1025 // relocation info entries.
1026 static const int kGap = 32;
1027 byte* pc_; // the program counter; moves forward
1028
1029 // Constant pool generation
1030 // Pools are emitted in the instruction stream, preferably after unconditional
1031 // jumps or after returns from functions (in dead code locations).
1032 // If a long code sequence does not contain unconditional jumps, it is
1033 // necessary to emit the constant pool before the pool gets too far from the
1034 // location it is accessed from. In this case, we emit a jump over the emitted
1035 // constant pool.
1036 // Constants in the pool may be addresses of functions that gets relocated;
1037 // if so, a relocation info entry is associated to the constant pool entry.
1038
1039 // Repeated checking whether the constant pool should be emitted is rather
1040 // expensive. By default we only check again once a number of instructions
1041 // has been generated. That also means that the sizing of the buffers is not
1042 // an exact science, and that we rely on some slop to not overrun buffers.
1043 static const int kCheckConstIntervalInst = 32;
1044 static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize;
1045
1046
1047 // Pools are emitted after function return and in dead code at (more or less)
1048 // regular intervals of kDistBetweenPools bytes
1049 static const int kDistBetweenPools = 1*KB;
1050
1051 // Constants in pools are accessed via pc relative addressing, which can
1052 // reach +/-4KB thereby defining a maximum distance between the instruction
1053 // and the accessed constant. We satisfy this constraint by limiting the
1054 // distance between pools.
1055 static const int kMaxDistBetweenPools = 4*KB - 2*kBufferCheckInterval;
1056
Steve Block6ded16b2010-05-10 14:33:55 +01001057 // Emission of the constant pool may be blocked in some code sequences.
1058 int const_pool_blocked_nesting_; // Block emission if this is not zero.
1059 int no_const_pool_before_; // Block emission before this pc offset.
Steve Blocka7e24c12009-10-30 11:49:00 +00001060
1061 // Keep track of the last emitted pool to guarantee a maximal distance
1062 int last_const_pool_end_; // pc offset following the last constant pool
1063
1064 // Relocation info generation
1065 // Each relocation is encoded as a variable size value
1066 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1067 RelocInfoWriter reloc_info_writer;
1068 // Relocation info records are also used during code generation as temporary
1069 // containers for constants and code target addresses until they are emitted
1070 // to the constant pool. These pending relocation info records are temporarily
1071 // stored in a separate buffer until a constant pool is emitted.
1072 // If every instruction in a long sequence is accessing the pool, we need one
1073 // pending relocation entry per instruction.
1074 static const int kMaxNumPRInfo = kMaxDistBetweenPools/kInstrSize;
1075 RelocInfo prinfo_[kMaxNumPRInfo]; // the buffer of pending relocation info
1076 int num_prinfo_; // number of pending reloc info entries in the buffer
1077
1078 // The bound position, before this we cannot do instruction elimination.
1079 int last_bound_pos_;
1080
1081 // source position information
1082 int current_position_;
1083 int current_statement_position_;
1084 int written_position_;
1085 int written_statement_position_;
1086
1087 // Code emission
1088 inline void CheckBuffer();
1089 void GrowBuffer();
1090 inline void emit(Instr x);
1091
1092 // Instruction generation
1093 void addrmod1(Instr instr, Register rn, Register rd, const Operand& x);
1094 void addrmod2(Instr instr, Register rd, const MemOperand& x);
1095 void addrmod3(Instr instr, Register rd, const MemOperand& x);
1096 void addrmod4(Instr instr, Register rn, RegList rl);
1097 void addrmod5(Instr instr, CRegister crd, const MemOperand& x);
1098
1099 // Labels
1100 void print(Label* L);
1101 void bind_to(Label* L, int pos);
1102 void link_to(Label* L, Label* appendix);
1103 void next(Label* L);
1104
1105 // Record reloc info for current pc_
1106 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
1107
1108 friend class RegExpMacroAssemblerARM;
1109 friend class RelocInfo;
1110 friend class CodePatcher;
Steve Block6ded16b2010-05-10 14:33:55 +01001111 friend class BlockConstPoolScope;
Steve Blocka7e24c12009-10-30 11:49:00 +00001112};
1113
1114} } // namespace v8::internal
1115
1116#endif // V8_ARM_ASSEMBLER_ARM_H_