blob: d0dee561cf25c5dda510eb649115ec4a9a40a4b5 [file] [log] [blame]
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001// Copyright (c) 1994-2006 Sun Microsystems Inc.
2// All Rights Reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003//
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004// 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.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000019//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000022// 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
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +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.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036
37// A light-weight ARM Assembler
38// Generates user mode instructions for the ARM architecture up to version 5
39
ager@chromium.org5ec48922009-05-05 07:25:34 +000040#ifndef V8_ARM_ASSEMBLER_ARM_H_
41#define V8_ARM_ASSEMBLER_ARM_H_
ager@chromium.org18ad94b2009-09-02 08:22:29 +000042#include <stdio.h>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "assembler.h"
ager@chromium.orgc4c92722009-11-18 14:12:51 +000044#include "serialize.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000045
kasperl@chromium.org71affb52009-05-26 05:44:31 +000046namespace v8 {
47namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000048
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
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000083 void set_code(int code) {
84 code_ = code;
85 ASSERT(is_valid());
86 }
87
ager@chromium.org5c838252010-02-19 08:53:10 +000088 // Unfortunately we can't make this private in a struct.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000089 int code_;
90};
91
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000092const Register no_reg = { -1 };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000093
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000094const Register r0 = { 0 };
95const Register r1 = { 1 };
96const Register r2 = { 2 };
97const Register r3 = { 3 };
98const Register r4 = { 4 };
99const Register r5 = { 5 };
100const Register r6 = { 6 };
101const Register r7 = { 7 };
102const Register r8 = { 8 }; // Used as context register.
103const Register r9 = { 9 };
104const Register r10 = { 10 }; // Used as roots register.
105const Register fp = { 11 };
106const Register ip = { 12 };
107const Register sp = { 13 };
108const Register lr = { 14 };
109const Register pc = { 15 };
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000110
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000111// Single word VFP register.
112struct SwVfpRegister {
113 bool is_valid() const { return 0 <= code_ && code_ < 32; }
114 bool is(SwVfpRegister reg) const { return code_ == reg.code_; }
115 int code() const {
116 ASSERT(is_valid());
117 return code_;
118 }
119 int bit() const {
120 ASSERT(is_valid());
121 return 1 << code_;
122 }
123
124 int code_;
125};
126
127
128// Double word VFP register.
129struct DwVfpRegister {
130 // Supporting d0 to d15, can be later extended to d31.
131 bool is_valid() const { return 0 <= code_ && code_ < 16; }
132 bool is(DwVfpRegister reg) const { return code_ == reg.code_; }
133 int code() const {
134 ASSERT(is_valid());
135 return code_;
136 }
137 int bit() const {
138 ASSERT(is_valid());
139 return 1 << code_;
140 }
141
142 int code_;
143};
144
145
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000146// Support for the VFP registers s0 to s31 (d0 to d15).
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000147// Note that "s(N):s(N+1)" is the same as "d(N/2)".
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000148const SwVfpRegister s0 = { 0 };
149const SwVfpRegister s1 = { 1 };
150const SwVfpRegister s2 = { 2 };
151const SwVfpRegister s3 = { 3 };
152const SwVfpRegister s4 = { 4 };
153const SwVfpRegister s5 = { 5 };
154const SwVfpRegister s6 = { 6 };
155const SwVfpRegister s7 = { 7 };
156const SwVfpRegister s8 = { 8 };
157const SwVfpRegister s9 = { 9 };
158const SwVfpRegister s10 = { 10 };
159const SwVfpRegister s11 = { 11 };
160const SwVfpRegister s12 = { 12 };
161const SwVfpRegister s13 = { 13 };
162const SwVfpRegister s14 = { 14 };
163const SwVfpRegister s15 = { 15 };
164const SwVfpRegister s16 = { 16 };
165const SwVfpRegister s17 = { 17 };
166const SwVfpRegister s18 = { 18 };
167const SwVfpRegister s19 = { 19 };
168const SwVfpRegister s20 = { 20 };
169const SwVfpRegister s21 = { 21 };
170const SwVfpRegister s22 = { 22 };
171const SwVfpRegister s23 = { 23 };
172const SwVfpRegister s24 = { 24 };
173const SwVfpRegister s25 = { 25 };
174const SwVfpRegister s26 = { 26 };
175const SwVfpRegister s27 = { 27 };
176const SwVfpRegister s28 = { 28 };
177const SwVfpRegister s29 = { 29 };
178const SwVfpRegister s30 = { 30 };
179const SwVfpRegister s31 = { 31 };
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000180
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000181const DwVfpRegister d0 = { 0 };
182const DwVfpRegister d1 = { 1 };
183const DwVfpRegister d2 = { 2 };
184const DwVfpRegister d3 = { 3 };
185const DwVfpRegister d4 = { 4 };
186const DwVfpRegister d5 = { 5 };
187const DwVfpRegister d6 = { 6 };
188const DwVfpRegister d7 = { 7 };
189const DwVfpRegister d8 = { 8 };
190const DwVfpRegister d9 = { 9 };
191const DwVfpRegister d10 = { 10 };
192const DwVfpRegister d11 = { 11 };
193const DwVfpRegister d12 = { 12 };
194const DwVfpRegister d13 = { 13 };
195const DwVfpRegister d14 = { 14 };
196const DwVfpRegister d15 = { 15 };
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000197
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000198
199// Coprocessor register
200struct CRegister {
201 bool is_valid() const { return 0 <= code_ && code_ < 16; }
202 bool is(CRegister creg) const { return code_ == creg.code_; }
203 int code() const {
204 ASSERT(is_valid());
205 return code_;
206 }
207 int bit() const {
208 ASSERT(is_valid());
209 return 1 << code_;
210 }
211
ager@chromium.org5c838252010-02-19 08:53:10 +0000212 // Unfortunately we can't make this private in a struct.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000213 int code_;
214};
215
216
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000217const CRegister no_creg = { -1 };
218
219const CRegister cr0 = { 0 };
220const CRegister cr1 = { 1 };
221const CRegister cr2 = { 2 };
222const CRegister cr3 = { 3 };
223const CRegister cr4 = { 4 };
224const CRegister cr5 = { 5 };
225const CRegister cr6 = { 6 };
226const CRegister cr7 = { 7 };
227const CRegister cr8 = { 8 };
228const CRegister cr9 = { 9 };
229const CRegister cr10 = { 10 };
230const CRegister cr11 = { 11 };
231const CRegister cr12 = { 12 };
232const CRegister cr13 = { 13 };
233const CRegister cr14 = { 14 };
234const CRegister cr15 = { 15 };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000235
236
237// Coprocessor number
238enum Coprocessor {
239 p0 = 0,
240 p1 = 1,
241 p2 = 2,
242 p3 = 3,
243 p4 = 4,
244 p5 = 5,
245 p6 = 6,
246 p7 = 7,
247 p8 = 8,
248 p9 = 9,
249 p10 = 10,
250 p11 = 11,
251 p12 = 12,
252 p13 = 13,
253 p14 = 14,
254 p15 = 15
255};
256
257
ager@chromium.org5c838252010-02-19 08:53:10 +0000258// Condition field in instructions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000259enum Condition {
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000260 eq = 0 << 28, // Z set equal.
261 ne = 1 << 28, // Z clear not equal.
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000262 nz = 1 << 28, // Z clear not zero.
263 cs = 2 << 28, // C set carry set.
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000264 hs = 2 << 28, // C set unsigned higher or same.
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000265 cc = 3 << 28, // C clear carry clear.
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000266 lo = 3 << 28, // C clear unsigned lower.
267 mi = 4 << 28, // N set negative.
268 pl = 5 << 28, // N clear positive or zero.
269 vs = 6 << 28, // V set overflow.
270 vc = 7 << 28, // V clear no overflow.
271 hi = 8 << 28, // C set, Z clear unsigned higher.
272 ls = 9 << 28, // C clear or Z set unsigned lower or same.
273 ge = 10 << 28, // N == V greater or equal.
274 lt = 11 << 28, // N != V less than.
275 gt = 12 << 28, // Z clear, N == V greater than.
276 le = 13 << 28, // Z set or N != V less then or equal
277 al = 14 << 28 // always.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000278};
279
280
281// Returns the equivalent of !cc.
282INLINE(Condition NegateCondition(Condition cc));
283
284
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000285// Corresponds to transposing the operands of a comparison.
286inline Condition ReverseCondition(Condition cc) {
287 switch (cc) {
288 case lo:
289 return hi;
290 case hi:
291 return lo;
292 case hs:
293 return ls;
294 case ls:
295 return hs;
296 case lt:
297 return gt;
298 case gt:
299 return lt;
300 case ge:
301 return le;
302 case le:
303 return ge;
304 default:
305 return cc;
306 };
307}
308
309
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000310// Branch hints are not used on the ARM. They are defined so that they can
311// appear in shared function signatures, but will be ignored in ARM
312// implementations.
313enum Hint { no_hint };
314
315// Hints are not used on the arm. Negating is trivial.
316inline Hint NegateHint(Hint ignored) { return no_hint; }
317
318
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000319// -----------------------------------------------------------------------------
320// Addressing modes and instruction variants
321
322// Shifter operand shift operation
323enum ShiftOp {
324 LSL = 0 << 5,
325 LSR = 1 << 5,
326 ASR = 2 << 5,
327 ROR = 3 << 5,
328 RRX = -1
329};
330
331
332// Condition code updating mode
333enum SBit {
334 SetCC = 1 << 20, // set condition code
335 LeaveCC = 0 << 20 // leave condition code unchanged
336};
337
338
339// Status register selection
340enum SRegister {
341 CPSR = 0 << 22,
342 SPSR = 1 << 22
343};
344
345
346// Status register fields
347enum SRegisterField {
348 CPSR_c = CPSR | 1 << 16,
349 CPSR_x = CPSR | 1 << 17,
350 CPSR_s = CPSR | 1 << 18,
351 CPSR_f = CPSR | 1 << 19,
352 SPSR_c = SPSR | 1 << 16,
353 SPSR_x = SPSR | 1 << 17,
354 SPSR_s = SPSR | 1 << 18,
355 SPSR_f = SPSR | 1 << 19
356};
357
358// Status register field mask (or'ed SRegisterField enum values)
359typedef uint32_t SRegisterFieldMask;
360
361
362// Memory operand addressing mode
363enum AddrMode {
364 // bit encoding P U W
365 Offset = (8|4|0) << 21, // offset (without writeback to base)
366 PreIndex = (8|4|1) << 21, // pre-indexed addressing with writeback
367 PostIndex = (0|4|0) << 21, // post-indexed addressing with writeback
368 NegOffset = (8|0|0) << 21, // negative offset (without writeback to base)
369 NegPreIndex = (8|0|1) << 21, // negative pre-indexed with writeback
370 NegPostIndex = (0|0|0) << 21 // negative post-indexed with writeback
371};
372
373
374// Load/store multiple addressing mode
375enum BlockAddrMode {
376 // bit encoding P U W
377 da = (0|0|0) << 21, // decrement after
378 ia = (0|4|0) << 21, // increment after
379 db = (8|0|0) << 21, // decrement before
380 ib = (8|4|0) << 21, // increment before
381 da_w = (0|0|1) << 21, // decrement after with writeback to base
382 ia_w = (0|4|1) << 21, // increment after with writeback to base
383 db_w = (8|0|1) << 21, // decrement before with writeback to base
384 ib_w = (8|4|1) << 21 // increment before with writeback to base
385};
386
387
388// Coprocessor load/store operand size
389enum LFlag {
390 Long = 1 << 22, // long load/store coprocessor
391 Short = 0 << 22 // short load/store coprocessor
392};
393
394
395// -----------------------------------------------------------------------------
396// Machine instruction Operands
397
398// Class Operand represents a shifter operand in data processing instructions
399class Operand BASE_EMBEDDED {
400 public:
401 // immediate
ager@chromium.org236ad962008-09-25 09:45:57 +0000402 INLINE(explicit Operand(int32_t immediate,
403 RelocInfo::Mode rmode = RelocInfo::NONE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000404 INLINE(explicit Operand(const ExternalReference& f));
405 INLINE(explicit Operand(const char* s));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000406 explicit Operand(Handle<Object> handle);
407 INLINE(explicit Operand(Smi* value));
408
409 // rm
410 INLINE(explicit Operand(Register rm));
411
412 // rm <shift_op> shift_imm
413 explicit Operand(Register rm, ShiftOp shift_op, int shift_imm);
414
415 // rm <shift_op> rs
416 explicit Operand(Register rm, ShiftOp shift_op, Register rs);
417
mads.s.ager31e71382008-08-13 09:32:07 +0000418 // Return true if this is a register operand.
419 INLINE(bool is_reg() const);
420
421 Register rm() const { return rm_; }
422
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000423 private:
424 Register rm_;
425 Register rs_;
426 ShiftOp shift_op_;
427 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
428 int32_t imm32_; // valid if rm_ == no_reg
ager@chromium.org236ad962008-09-25 09:45:57 +0000429 RelocInfo::Mode rmode_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000430
431 friend class Assembler;
432};
433
434
435// Class MemOperand represents a memory operand in load and store instructions
436class MemOperand BASE_EMBEDDED {
437 public:
438 // [rn +/- offset] Offset/NegOffset
439 // [rn +/- offset]! PreIndex/NegPreIndex
440 // [rn], +/- offset PostIndex/NegPostIndex
441 // offset is any signed 32-bit value; offset is first loaded to register ip if
442 // it does not fit the addressing mode (12-bit unsigned and sign bit)
443 explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset);
444
445 // [rn +/- rm] Offset/NegOffset
446 // [rn +/- rm]! PreIndex/NegPreIndex
447 // [rn], +/- rm PostIndex/NegPostIndex
448 explicit MemOperand(Register rn, Register rm, AddrMode am = Offset);
449
450 // [rn +/- rm <shift_op> shift_imm] Offset/NegOffset
451 // [rn +/- rm <shift_op> shift_imm]! PreIndex/NegPreIndex
452 // [rn], +/- rm <shift_op> shift_imm PostIndex/NegPostIndex
453 explicit MemOperand(Register rn, Register rm,
454 ShiftOp shift_op, int shift_imm, AddrMode am = Offset);
455
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000456 void set_offset(int32_t offset) {
457 ASSERT(rm_.is(no_reg));
458 offset_ = offset;
459 }
460
461 uint32_t offset() {
462 ASSERT(rm_.is(no_reg));
463 return offset_;
464 }
465
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000466 Register rn() const { return rn_; }
467 Register rm() const { return rm_; }
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000468
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000469 private:
470 Register rn_; // base
471 Register rm_; // register offset
472 int32_t offset_; // valid if rm_ == no_reg
473 ShiftOp shift_op_;
474 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
475 AddrMode am_; // bits P, U, and W
476
477 friend class Assembler;
478};
479
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000480// CpuFeatures keeps track of which features are supported by the target CPU.
481// Supported features must be enabled by a Scope before use.
482class CpuFeatures : public AllStatic {
483 public:
484 // Detect features of the target CPU. Set safe defaults if the serializer
485 // is enabled (snapshots must be portable).
486 static void Probe();
487
488 // Check whether a feature is supported by the target CPU.
489 static bool IsSupported(CpuFeature f) {
490 if (f == VFP3 && !FLAG_enable_vfp3) return false;
491 return (supported_ & (1u << f)) != 0;
492 }
493
494 // Check whether a feature is currently enabled.
495 static bool IsEnabled(CpuFeature f) {
496 return (enabled_ & (1u << f)) != 0;
497 }
498
499 // Enable a specified feature within a scope.
500 class Scope BASE_EMBEDDED {
501#ifdef DEBUG
502 public:
503 explicit Scope(CpuFeature f) {
504 ASSERT(CpuFeatures::IsSupported(f));
505 ASSERT(!Serializer::enabled() ||
506 (found_by_runtime_probing_ & (1u << f)) == 0);
507 old_enabled_ = CpuFeatures::enabled_;
508 CpuFeatures::enabled_ |= 1u << f;
509 }
510 ~Scope() { CpuFeatures::enabled_ = old_enabled_; }
511 private:
512 unsigned old_enabled_;
513#else
514 public:
515 explicit Scope(CpuFeature f) {}
516#endif
517 };
518
519 private:
520 static unsigned supported_;
521 static unsigned enabled_;
522 static unsigned found_by_runtime_probing_;
523};
524
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000525
526typedef int32_t Instr;
527
528
ager@chromium.org4af710e2009-09-15 12:20:11 +0000529extern const Instr kMovLrPc;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000530extern const Instr kLdrPCMask;
ager@chromium.org4af710e2009-09-15 12:20:11 +0000531extern const Instr kLdrPCPattern;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000532extern const Instr kBlxRegMask;
533extern const Instr kBlxRegPattern;
ager@chromium.org4af710e2009-09-15 12:20:11 +0000534
535
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000536class Assembler : public Malloced {
537 public:
538 // Create an assembler. Instructions and relocation information are emitted
539 // into a buffer, with the instructions starting from the beginning and the
540 // relocation information starting from the end of the buffer. See CodeDesc
541 // for a detailed comment on the layout (globals.h).
542 //
543 // If the provided buffer is NULL, the assembler allocates and grows its own
544 // buffer, and buffer_size determines the initial buffer size. The buffer is
545 // owned by the assembler and deallocated upon destruction of the assembler.
546 //
547 // If the provided buffer is not NULL, the assembler uses the provided buffer
548 // for code generation and assumes its size to be buffer_size. If the buffer
549 // is too small, a fatal error occurs. No deallocation of the buffer is done
550 // upon destruction of the assembler.
551 Assembler(void* buffer, int buffer_size);
552 ~Assembler();
553
554 // GetCode emits any pending (non-emitted) code and fills the descriptor
555 // desc. GetCode() is idempotent; it returns the same result if no other
ager@chromium.org32912102009-01-16 10:38:43 +0000556 // Assembler functions are invoked in between GetCode() calls.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000557 void GetCode(CodeDesc* desc);
558
559 // Label operations & relative jumps (PPUM Appendix D)
560 //
561 // Takes a branch opcode (cc) and a label (L) and generates
562 // either a backward branch or a forward branch and links it
563 // to the label fixup chain. Usage:
564 //
565 // Label L; // unbound label
566 // j(cc, &L); // forward branch to unbound label
567 // bind(&L); // bind label to the current pc
568 // j(cc, &L); // backward branch to bound label
569 // bind(&L); // illegal: a label may be bound only once
570 //
571 // Note: The same Label can be used for forward and backward branches
572 // but it may be bound only once.
573
574 void bind(Label* L); // binds an unbound label L to the current code position
575
576 // Returns the branch offset to the given label from the current code position
577 // Links the label to the current position if it is still unbound
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000578 // Manages the jump elimination optimization if the second parameter is true.
579 int branch_offset(Label* L, bool jump_elimination_allowed);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000580
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000581 // Puts a labels target address at the given position.
582 // The high 8 bits are set to zero.
583 void label_at_put(Label* L, int at_offset);
584
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000585 // Return the address in the constant pool of the code target address used by
586 // the branch/call instruction at pc.
587 INLINE(static Address target_address_address_at(Address pc));
588
589 // Read/Modify the code target address in the branch/call instruction at pc.
590 INLINE(static Address target_address_at(Address pc));
591 INLINE(static void set_target_address_at(Address pc, Address target));
592
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000593 // This sets the branch destination (which is in the constant pool on ARM).
594 // This is for calls and branches within generated code.
ager@chromium.org3811b432009-10-28 14:53:37 +0000595 inline static void set_target_at(Address constant_pool_entry, Address target);
596
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000597 // This sets the branch destination (which is in the constant pool on ARM).
598 // This is for calls and branches to runtime code.
599 inline static void set_external_target_at(Address constant_pool_entry,
600 Address target) {
601 set_target_at(constant_pool_entry, target);
602 }
603
ager@chromium.org3811b432009-10-28 14:53:37 +0000604 // Here we are patching the address in the constant pool, not the actual call
605 // instruction. The address in the constant pool is the same size as a
606 // pointer.
607 static const int kCallTargetSize = kPointerSize;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000608 static const int kExternalTargetSize = kPointerSize;
ager@chromium.org3811b432009-10-28 14:53:37 +0000609
ager@chromium.org4af710e2009-09-15 12:20:11 +0000610 // Size of an instruction.
611 static const int kInstrSize = sizeof(Instr);
612
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000613 // Distance between the instruction referring to the address of the call
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000614 // target and the return address.
615#ifdef USE_BLX
616 // Call sequence is:
617 // ldr ip, [pc, #...] @ call address
618 // blx ip
619 // @ return address
620 static const int kCallTargetAddressOffset = 2 * kInstrSize;
621#else
622 // Call sequence is:
623 // mov lr, pc
624 // ldr pc, [pc, #...] @ call address
625 // @ return address
ager@chromium.org4af710e2009-09-15 12:20:11 +0000626 static const int kCallTargetAddressOffset = kInstrSize;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000627#endif
ager@chromium.org4af710e2009-09-15 12:20:11 +0000628
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000629 // Distance between start of patched return sequence and the emitted address
630 // to jump to.
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000631#ifdef USE_BLX
632 // Return sequence is:
633 // ldr ip, [pc, #0] @ emited address and start
634 // blx ip
635 static const int kPatchReturnSequenceAddressOffset = 0 * kInstrSize;
636#else
637 // Return sequence is:
638 // mov lr, pc @ start of sequence
639 // ldr pc, [pc, #-4] @ emited address
640 static const int kPatchReturnSequenceAddressOffset = kInstrSize;
641#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000642
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000643 // Difference between address of current opcode and value read from pc
644 // register.
645 static const int kPcLoadDelta = 8;
646
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000647 static const int kJSReturnSequenceLength = 4;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000648
649 // ---------------------------------------------------------------------------
650 // Code generation
651
652 // Insert the smallest number of nop instructions
653 // possible to align the pc offset to a multiple
654 // of m. m must be a power of 2 (>= 4).
655 void Align(int m);
656
657 // Branch instructions
658 void b(int branch_offset, Condition cond = al);
659 void bl(int branch_offset, Condition cond = al);
660 void blx(int branch_offset); // v5 and above
661 void blx(Register target, Condition cond = al); // v5 and above
662 void bx(Register target, Condition cond = al); // v5 and above, plus v4t
663
664 // Convenience branch instructions using labels
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000665 void b(Label* L, Condition cond = al) {
666 b(branch_offset(L, cond == al), cond);
667 }
668 void b(Condition cond, Label* L) { b(branch_offset(L, cond == al), cond); }
669 void bl(Label* L, Condition cond = al) { bl(branch_offset(L, false), cond); }
670 void bl(Condition cond, Label* L) { bl(branch_offset(L, false), cond); }
671 void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000672
673 // Data-processing instructions
ager@chromium.org5c838252010-02-19 08:53:10 +0000674
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000675 void and_(Register dst, Register src1, const Operand& src2,
676 SBit s = LeaveCC, Condition cond = al);
677
678 void eor(Register dst, Register src1, const Operand& src2,
679 SBit s = LeaveCC, Condition cond = al);
680
681 void sub(Register dst, Register src1, const Operand& src2,
682 SBit s = LeaveCC, Condition cond = al);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000683 void sub(Register dst, Register src1, Register src2,
684 SBit s = LeaveCC, Condition cond = al) {
685 sub(dst, src1, Operand(src2), s, cond);
686 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000687
688 void rsb(Register dst, Register src1, const Operand& src2,
689 SBit s = LeaveCC, Condition cond = al);
690
691 void add(Register dst, Register src1, const Operand& src2,
692 SBit s = LeaveCC, Condition cond = al);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000693 void add(Register dst, Register src1, Register src2,
694 SBit s = LeaveCC, Condition cond = al) {
695 add(dst, src1, Operand(src2), s, cond);
696 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000697
698 void adc(Register dst, Register src1, const Operand& src2,
699 SBit s = LeaveCC, Condition cond = al);
700
701 void sbc(Register dst, Register src1, const Operand& src2,
702 SBit s = LeaveCC, Condition cond = al);
703
704 void rsc(Register dst, Register src1, const Operand& src2,
705 SBit s = LeaveCC, Condition cond = al);
706
707 void tst(Register src1, const Operand& src2, Condition cond = al);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000708 void tst(Register src1, Register src2, Condition cond = al) {
709 tst(src1, Operand(src2), cond);
710 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000711
712 void teq(Register src1, const Operand& src2, Condition cond = al);
713
714 void cmp(Register src1, const Operand& src2, Condition cond = al);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000715 void cmp(Register src1, Register src2, Condition cond = al) {
716 cmp(src1, Operand(src2), cond);
717 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000718
719 void cmn(Register src1, const Operand& src2, Condition cond = al);
720
721 void orr(Register dst, Register src1, const Operand& src2,
722 SBit s = LeaveCC, Condition cond = al);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000723 void orr(Register dst, Register src1, Register src2,
724 SBit s = LeaveCC, Condition cond = al) {
725 orr(dst, src1, Operand(src2), s, cond);
726 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000727
728 void mov(Register dst, const Operand& src,
729 SBit s = LeaveCC, Condition cond = al);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000730 void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
731 mov(dst, Operand(src), s, cond);
732 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000733
734 void bic(Register dst, Register src1, const Operand& src2,
735 SBit s = LeaveCC, Condition cond = al);
736
737 void mvn(Register dst, const Operand& src,
738 SBit s = LeaveCC, Condition cond = al);
739
740 // Multiply instructions
741
742 void mla(Register dst, Register src1, Register src2, Register srcA,
743 SBit s = LeaveCC, Condition cond = al);
744
745 void mul(Register dst, Register src1, Register src2,
746 SBit s = LeaveCC, Condition cond = al);
747
748 void smlal(Register dstL, Register dstH, Register src1, Register src2,
749 SBit s = LeaveCC, Condition cond = al);
750
751 void smull(Register dstL, Register dstH, Register src1, Register src2,
752 SBit s = LeaveCC, Condition cond = al);
753
754 void umlal(Register dstL, Register dstH, Register src1, Register src2,
755 SBit s = LeaveCC, Condition cond = al);
756
757 void umull(Register dstL, Register dstH, Register src1, Register src2,
758 SBit s = LeaveCC, Condition cond = al);
759
760 // Miscellaneous arithmetic instructions
761
762 void clz(Register dst, Register src, Condition cond = al); // v5 and above
763
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000764 // Bitfield manipulation instructions. v7 and above.
765
766 void ubfx(Register dst, Register src, int lsb, int width,
767 Condition cond = al);
768
769 void sbfx(Register dst, Register src, int lsb, int width,
770 Condition cond = al);
771
772 void bfc(Register dst, int lsb, int width, Condition cond = al);
773
774 void bfi(Register dst, Register src, int lsb, int width,
775 Condition cond = al);
776
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000777 // Status register access instructions
778
779 void mrs(Register dst, SRegister s, Condition cond = al);
780 void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al);
781
782 // Load/Store instructions
783 void ldr(Register dst, const MemOperand& src, Condition cond = al);
784 void str(Register src, const MemOperand& dst, Condition cond = al);
785 void ldrb(Register dst, const MemOperand& src, Condition cond = al);
786 void strb(Register src, const MemOperand& dst, Condition cond = al);
787 void ldrh(Register dst, const MemOperand& src, Condition cond = al);
788 void strh(Register src, const MemOperand& dst, Condition cond = al);
789 void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
790 void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000791 void ldrd(Register dst1,
792 Register dst2,
793 const MemOperand& src, Condition cond = al);
794 void strd(Register src1,
795 Register src2,
796 const MemOperand& dst, Condition cond = al);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000797
798 // Load/Store multiple instructions
799 void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
800 void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
801
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000802 // Exception-generating instructions and debugging support
803 void stop(const char* msg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000804
805 void bkpt(uint32_t imm16); // v5 and above
806 void swi(uint32_t imm24, Condition cond = al);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000807
808 // Coprocessor instructions
809
810 void cdp(Coprocessor coproc, int opcode_1,
811 CRegister crd, CRegister crn, CRegister crm,
812 int opcode_2, Condition cond = al);
813
814 void cdp2(Coprocessor coproc, int opcode_1,
815 CRegister crd, CRegister crn, CRegister crm,
816 int opcode_2); // v5 and above
817
818 void mcr(Coprocessor coproc, int opcode_1,
819 Register rd, CRegister crn, CRegister crm,
820 int opcode_2 = 0, Condition cond = al);
821
822 void mcr2(Coprocessor coproc, int opcode_1,
823 Register rd, CRegister crn, CRegister crm,
824 int opcode_2 = 0); // v5 and above
825
826 void mrc(Coprocessor coproc, int opcode_1,
827 Register rd, CRegister crn, CRegister crm,
828 int opcode_2 = 0, Condition cond = al);
829
830 void mrc2(Coprocessor coproc, int opcode_1,
831 Register rd, CRegister crn, CRegister crm,
832 int opcode_2 = 0); // v5 and above
833
834 void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src,
835 LFlag l = Short, Condition cond = al);
836 void ldc(Coprocessor coproc, CRegister crd, Register base, int option,
837 LFlag l = Short, Condition cond = al);
838
839 void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
840 LFlag l = Short); // v5 and above
841 void ldc2(Coprocessor coproc, CRegister crd, Register base, int option,
842 LFlag l = Short); // v5 and above
843
844 void stc(Coprocessor coproc, CRegister crd, const MemOperand& dst,
845 LFlag l = Short, Condition cond = al);
846 void stc(Coprocessor coproc, CRegister crd, Register base, int option,
847 LFlag l = Short, Condition cond = al);
848
849 void stc2(Coprocessor coproc, CRegister crd, const MemOperand& dst,
850 LFlag l = Short); // v5 and above
851 void stc2(Coprocessor coproc, CRegister crd, Register base, int option,
852 LFlag l = Short); // v5 and above
853
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000854 // Support for VFP.
855 // All these APIs support S0 to S31 and D0 to D15.
856 // Currently these APIs do not support extended D registers, i.e, D16 to D31.
857 // However, some simple modifications can allow
858 // these APIs to support D16 to D31.
859
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000860 void vldr(const DwVfpRegister dst,
861 const Register base,
862 int offset, // Offset must be a multiple of 4.
863 const Condition cond = al);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000864
865 void vldr(const SwVfpRegister dst,
866 const Register base,
867 int offset, // Offset must be a multiple of 4.
868 const Condition cond = al);
869
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000870 void vstr(const DwVfpRegister src,
871 const Register base,
872 int offset, // Offset must be a multiple of 4.
873 const Condition cond = al);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000874 void vmov(const DwVfpRegister dst,
875 const Register src1,
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000876 const Register src2,
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000877 const Condition cond = al);
878 void vmov(const Register dst1,
879 const Register dst2,
880 const DwVfpRegister src,
881 const Condition cond = al);
882 void vmov(const SwVfpRegister dst,
883 const Register src,
884 const Condition cond = al);
885 void vmov(const Register dst,
886 const SwVfpRegister src,
887 const Condition cond = al);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000888 void vcvt_f64_s32(const DwVfpRegister dst,
889 const SwVfpRegister src,
890 const Condition cond = al);
891 void vcvt_f32_s32(const SwVfpRegister dst,
892 const SwVfpRegister src,
893 const Condition cond = al);
894 void vcvt_f64_u32(const DwVfpRegister dst,
895 const SwVfpRegister src,
896 const Condition cond = al);
897 void vcvt_s32_f64(const SwVfpRegister dst,
898 const DwVfpRegister src,
899 const Condition cond = al);
900 void vcvt_u32_f64(const SwVfpRegister dst,
901 const DwVfpRegister src,
902 const Condition cond = al);
903 void vcvt_f64_f32(const DwVfpRegister dst,
904 const SwVfpRegister src,
905 const Condition cond = al);
906 void vcvt_f32_f64(const SwVfpRegister dst,
907 const DwVfpRegister src,
908 const Condition cond = al);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000909
910 void vadd(const DwVfpRegister dst,
911 const DwVfpRegister src1,
912 const DwVfpRegister src2,
913 const Condition cond = al);
914 void vsub(const DwVfpRegister dst,
915 const DwVfpRegister src1,
916 const DwVfpRegister src2,
917 const Condition cond = al);
918 void vmul(const DwVfpRegister dst,
919 const DwVfpRegister src1,
920 const DwVfpRegister src2,
921 const Condition cond = al);
922 void vdiv(const DwVfpRegister dst,
923 const DwVfpRegister src1,
924 const DwVfpRegister src2,
925 const Condition cond = al);
926 void vcmp(const DwVfpRegister src1,
927 const DwVfpRegister src2,
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000928 const SBit s = LeaveCC,
929 const Condition cond = al);
930 void vmrs(const Register dst,
931 const Condition cond = al);
932
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000933 // Pseudo instructions
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000934 void nop(int type = 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000935
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000936 void push(Register src, Condition cond = al) {
937 str(src, MemOperand(sp, 4, NegPreIndex), cond);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000938 }
939
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000940 void pop(Register dst, Condition cond = al) {
941 ldr(dst, MemOperand(sp, 4, PostIndex), cond);
mads.s.ager31e71382008-08-13 09:32:07 +0000942 }
943
944 void pop() {
945 add(sp, sp, Operand(kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000946 }
947
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000948 // Jump unconditionally to given label.
949 void jmp(Label* L) { b(L, al); }
950
ager@chromium.org4af710e2009-09-15 12:20:11 +0000951 // Check the code size generated from label to here.
952 int InstructionsGeneratedSince(Label* l) {
953 return (pc_offset() - l->pos()) / kInstrSize;
954 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000955
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000956 // Check whether an immediate fits an addressing mode 1 instruction.
957 bool ImmediateFitsAddrMode1Instruction(int32_t imm32);
958
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000959 // Class for scoping postponing the constant pool generation.
960 class BlockConstPoolScope {
961 public:
962 explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) {
963 assem_->StartBlockConstPool();
964 }
965 ~BlockConstPoolScope() {
966 assem_->EndBlockConstPool();
967 }
968
969 private:
970 Assembler* assem_;
971
972 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstPoolScope);
973 };
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000974
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000975 // Postpone the generation of the constant pool for the specified number of
976 // instructions.
977 void BlockConstPoolFor(int instructions);
978
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000979 // Debugging
980
ager@chromium.org4af710e2009-09-15 12:20:11 +0000981 // Mark address of the ExitJSFrame code.
982 void RecordJSReturn();
983
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000984 // Record a comment relocation entry that can be used by a disassembler.
985 // Use --debug_code to enable.
986 void RecordComment(const char* msg);
987
988 void RecordPosition(int pos);
989 void RecordStatementPosition(int pos);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000990 void WriteRecordedPositions();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000991
992 int pc_offset() const { return pc_ - buffer_; }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000993 int current_position() const { return current_position_; }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000994 int current_statement_position() const { return current_statement_position_; }
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000995
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000996 bool can_peephole_optimize(int instructions) {
997 if (!FLAG_peephole_optimization) return false;
998 if (last_bound_pos_ > pc_offset() - instructions * kInstrSize) return false;
999 return reloc_info_writer.last_pc() <= pc_ - instructions * kInstrSize;
1000 }
1001
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001002 // Read/patch instructions
1003 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
1004 static void instr_at_put(byte* pc, Instr instr) {
1005 *reinterpret_cast<Instr*>(pc) = instr;
1006 }
1007 static bool IsNop(Instr instr, int type = 0);
1008 static bool IsBranch(Instr instr);
1009 static int GetBranchOffset(Instr instr);
1010 static bool IsLdrRegisterImmediate(Instr instr);
1011 static int GetLdrRegisterImmediateOffset(Instr instr);
1012 static Instr SetLdrRegisterImmediateOffset(Instr instr, int offset);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001013 static Register GetRd(Instr instr);
1014 static bool IsPush(Instr instr);
1015 static bool IsPop(Instr instr);
1016 static bool IsStrRegFpOffset(Instr instr);
1017 static bool IsLdrRegFpOffset(Instr instr);
1018 static bool IsStrRegFpNegOffset(Instr instr);
1019 static bool IsLdrRegFpNegOffset(Instr instr);
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001020
1021
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001022 protected:
1023 int buffer_space() const { return reloc_info_writer.pos() - pc_; }
1024
1025 // Read/patch instructions
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001026 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
1027 void instr_at_put(int pos, Instr instr) {
1028 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
1029 }
1030
1031 // Decode branch instruction at pos and return branch target pos
1032 int target_at(int pos);
1033
1034 // Patch branch instruction at pos to branch to given branch target pos
1035 void target_at_put(int pos, int target_pos);
1036
ager@chromium.org8bb60582008-12-11 12:02:20 +00001037 // Check if is time to emit a constant pool for pending reloc info entries
1038 void CheckConstPool(bool force_emit, bool require_jump);
1039
1040 // Block the emission of the constant pool before pc_offset
1041 void BlockConstPoolBefore(int pc_offset) {
1042 if (no_const_pool_before_ < pc_offset) no_const_pool_before_ = pc_offset;
1043 }
1044
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001045 void StartBlockConstPool() {
1046 const_pool_blocked_nesting_++;
1047 }
1048 void EndBlockConstPool() {
1049 const_pool_blocked_nesting_--;
1050 }
1051
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001052 private:
1053 // Code buffer:
1054 // The buffer into which code and relocation info are generated.
1055 byte* buffer_;
1056 int buffer_size_;
1057 // True if the assembler owns the buffer, false if buffer is external.
1058 bool own_buffer_;
1059
1060 // Buffer size and constant pool distance are checked together at regular
1061 // intervals of kBufferCheckInterval emitted bytes
1062 static const int kBufferCheckInterval = 1*KB/2;
1063 int next_buffer_check_; // pc offset of next buffer check
1064
1065 // Code generation
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001066 // The relocation writer's position is at least kGap bytes below the end of
1067 // the generated instructions. This is so that multi-instruction sequences do
1068 // not have to check for overflow. The same is true for writes of large
1069 // relocation info entries.
1070 static const int kGap = 32;
1071 byte* pc_; // the program counter; moves forward
1072
1073 // Constant pool generation
1074 // Pools are emitted in the instruction stream, preferably after unconditional
1075 // jumps or after returns from functions (in dead code locations).
1076 // If a long code sequence does not contain unconditional jumps, it is
1077 // necessary to emit the constant pool before the pool gets too far from the
1078 // location it is accessed from. In this case, we emit a jump over the emitted
1079 // constant pool.
1080 // Constants in the pool may be addresses of functions that gets relocated;
1081 // if so, a relocation info entry is associated to the constant pool entry.
1082
1083 // Repeated checking whether the constant pool should be emitted is rather
1084 // expensive. By default we only check again once a number of instructions
1085 // has been generated. That also means that the sizing of the buffers is not
1086 // an exact science, and that we rely on some slop to not overrun buffers.
1087 static const int kCheckConstIntervalInst = 32;
1088 static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize;
1089
1090
1091 // Pools are emitted after function return and in dead code at (more or less)
1092 // regular intervals of kDistBetweenPools bytes
1093 static const int kDistBetweenPools = 1*KB;
1094
1095 // Constants in pools are accessed via pc relative addressing, which can
1096 // reach +/-4KB thereby defining a maximum distance between the instruction
1097 // and the accessed constant. We satisfy this constraint by limiting the
1098 // distance between pools.
1099 static const int kMaxDistBetweenPools = 4*KB - 2*kBufferCheckInterval;
1100
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001101 // Emission of the constant pool may be blocked in some code sequences.
1102 int const_pool_blocked_nesting_; // Block emission if this is not zero.
1103 int no_const_pool_before_; // Block emission before this pc offset.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001104
1105 // Keep track of the last emitted pool to guarantee a maximal distance
1106 int last_const_pool_end_; // pc offset following the last constant pool
1107
1108 // Relocation info generation
1109 // Each relocation is encoded as a variable size value
1110 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1111 RelocInfoWriter reloc_info_writer;
1112 // Relocation info records are also used during code generation as temporary
1113 // containers for constants and code target addresses until they are emitted
1114 // to the constant pool. These pending relocation info records are temporarily
1115 // stored in a separate buffer until a constant pool is emitted.
1116 // If every instruction in a long sequence is accessing the pool, we need one
1117 // pending relocation entry per instruction.
1118 static const int kMaxNumPRInfo = kMaxDistBetweenPools/kInstrSize;
1119 RelocInfo prinfo_[kMaxNumPRInfo]; // the buffer of pending relocation info
1120 int num_prinfo_; // number of pending reloc info entries in the buffer
1121
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001122 // The bound position, before this we cannot do instruction elimination.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001123 int last_bound_pos_;
1124
1125 // source position information
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001126 int current_position_;
1127 int current_statement_position_;
1128 int written_position_;
1129 int written_statement_position_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001130
1131 // Code emission
1132 inline void CheckBuffer();
1133 void GrowBuffer();
1134 inline void emit(Instr x);
1135
1136 // Instruction generation
1137 void addrmod1(Instr instr, Register rn, Register rd, const Operand& x);
1138 void addrmod2(Instr instr, Register rd, const MemOperand& x);
1139 void addrmod3(Instr instr, Register rd, const MemOperand& x);
1140 void addrmod4(Instr instr, Register rn, RegList rl);
1141 void addrmod5(Instr instr, CRegister crd, const MemOperand& x);
1142
1143 // Labels
1144 void print(Label* L);
1145 void bind_to(Label* L, int pos);
1146 void link_to(Label* L, Label* appendix);
1147 void next(Label* L);
1148
1149 // Record reloc info for current pc_
ager@chromium.org236ad962008-09-25 09:45:57 +00001150 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001151
1152 friend class RegExpMacroAssemblerARM;
ager@chromium.org4af710e2009-09-15 12:20:11 +00001153 friend class RelocInfo;
1154 friend class CodePatcher;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001155 friend class BlockConstPoolScope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001156};
1157
1158} } // namespace v8::internal
1159
ager@chromium.org5ec48922009-05-05 07:25:34 +00001160#endif // V8_ARM_ASSEMBLER_ARM_H_