blob: 3941c84b34bc1cc006a8e10c80ed7fb3387293fe [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 Block1e0659c2011-05-24 12:43:12 +010044#include "constants-arm.h"
Steve Blockd0582a62009-12-15 09:54:21 +000045#include "serialize.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000046
47namespace v8 {
48namespace internal {
49
50// CPU Registers.
51//
52// 1) We would prefer to use an enum, but enum values are assignment-
53// compatible with int, which has caused code-generation bugs.
54//
55// 2) We would prefer to use a class instead of a struct but we don't like
56// the register initialization to depend on the particular initialization
57// order (which appears to be different on OS X, Linux, and Windows for the
58// installed versions of C++ we tried). Using a struct permits C-style
59// "initialization". Also, the Register objects cannot be const as this
60// forces initialization stubs in MSVC, making us dependent on initialization
61// order.
62//
63// 3) By not using an enum, we are possibly preventing the compiler from
64// doing certain constant folds, which may significantly reduce the
65// code generated for some assembly instructions (because they boil down
66// to a few constants). If this is a problem, we could change the code
67// such that we use an enum in optimized mode, and the struct in debug
68// mode. This way we get the compile-time error checking in debug mode
69// and best performance in optimized code.
Steve Block9fac8402011-05-12 15:51:54 +010070
Steve Blocka7e24c12009-10-30 11:49:00 +000071// Core register
72struct Register {
Ben Murdochb0fe1622011-05-05 13:52:32 +010073 static const int kNumRegisters = 16;
74 static const int kNumAllocatableRegisters = 8;
75
76 static int ToAllocationIndex(Register reg) {
Steve Block9fac8402011-05-12 15:51:54 +010077 ASSERT(reg.code() < kNumAllocatableRegisters);
Ben Murdochb0fe1622011-05-05 13:52:32 +010078 return reg.code();
79 }
80
81 static Register FromAllocationIndex(int index) {
82 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
83 return from_code(index);
84 }
85
86 static const char* AllocationIndexToString(int index) {
87 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
88 const char* const names[] = {
89 "r0",
90 "r1",
91 "r2",
92 "r3",
93 "r4",
94 "r5",
95 "r6",
96 "r7",
97 };
98 return names[index];
99 }
100
101 static Register from_code(int code) {
102 Register r = { code };
103 return r;
104 }
105
106 bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100107 bool is(Register reg) const { return code_ == reg.code_; }
108 int code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000109 ASSERT(is_valid());
110 return code_;
111 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100112 int bit() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000113 ASSERT(is_valid());
114 return 1 << code_;
115 }
116
Leon Clarkef7060e22010-06-03 12:02:55 +0100117 void set_code(int code) {
118 code_ = code;
119 ASSERT(is_valid());
120 }
121
Andrei Popescu31002712010-02-23 13:46:05 +0000122 // Unfortunately we can't make this private in a struct.
Steve Blocka7e24c12009-10-30 11:49:00 +0000123 int code_;
124};
125
Steve Block6ded16b2010-05-10 14:33:55 +0100126const Register no_reg = { -1 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000127
Steve Block6ded16b2010-05-10 14:33:55 +0100128const Register r0 = { 0 };
129const Register r1 = { 1 };
130const Register r2 = { 2 };
131const Register r3 = { 3 };
132const Register r4 = { 4 };
133const Register r5 = { 5 };
134const Register r6 = { 6 };
135const Register r7 = { 7 };
136const Register r8 = { 8 }; // Used as context register.
Steve Block9fac8402011-05-12 15:51:54 +0100137const Register r9 = { 9 }; // Used as lithium codegen scratch register.
Steve Block6ded16b2010-05-10 14:33:55 +0100138const Register r10 = { 10 }; // Used as roots register.
139const Register fp = { 11 };
140const Register ip = { 12 };
141const Register sp = { 13 };
142const Register lr = { 14 };
143const Register pc = { 15 };
Steve Blockd0582a62009-12-15 09:54:21 +0000144
Leon Clarkee46be812010-01-19 14:06:41 +0000145// Single word VFP register.
146struct SwVfpRegister {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100147 bool is_valid() const { return 0 <= code_ && code_ < 32; }
148 bool is(SwVfpRegister reg) const { return code_ == reg.code_; }
149 int code() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000150 ASSERT(is_valid());
151 return code_;
152 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100153 int bit() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000154 ASSERT(is_valid());
155 return 1 << code_;
156 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100157 void split_code(int* vm, int* m) const {
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100158 ASSERT(is_valid());
159 *m = code_ & 0x1;
160 *vm = code_ >> 1;
161 }
Leon Clarkee46be812010-01-19 14:06:41 +0000162
163 int code_;
164};
165
166
167// Double word VFP register.
168struct DwVfpRegister {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100169 // d0 has been excluded from allocation. This is following ia32
170 // where xmm0 is excluded. This should be revisited.
Ben Murdochb8e0da22011-05-16 14:20:40 +0100171 // Currently d0 is used as a scratch register.
172 // d1 has also been excluded from allocation to be used as a scratch
173 // register as well.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100174 static const int kNumRegisters = 16;
175 static const int kNumAllocatableRegisters = 15;
176
177 static int ToAllocationIndex(DwVfpRegister reg) {
178 ASSERT(reg.code() != 0);
179 return reg.code() - 1;
180 }
181
182 static DwVfpRegister FromAllocationIndex(int index) {
183 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
184 return from_code(index + 1);
185 }
186
187 static const char* AllocationIndexToString(int index) {
188 ASSERT(index >= 0 && index < kNumAllocatableRegisters);
189 const char* const names[] = {
190 "d1",
191 "d2",
192 "d3",
193 "d4",
194 "d5",
195 "d6",
196 "d7",
197 "d8",
198 "d9",
199 "d10",
200 "d11",
201 "d12",
202 "d13",
203 "d14",
204 "d15"
205 };
206 return names[index];
207 }
208
209 static DwVfpRegister from_code(int code) {
210 DwVfpRegister r = { code };
211 return r;
212 }
213
Leon Clarkee46be812010-01-19 14:06:41 +0000214 // Supporting d0 to d15, can be later extended to d31.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100215 bool is_valid() const { return 0 <= code_ && code_ < 16; }
216 bool is(DwVfpRegister reg) const { return code_ == reg.code_; }
217 SwVfpRegister low() const {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100218 SwVfpRegister reg;
219 reg.code_ = code_ * 2;
220
221 ASSERT(reg.is_valid());
222 return reg;
223 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100224 SwVfpRegister high() const {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100225 SwVfpRegister reg;
226 reg.code_ = (code_ * 2) + 1;
227
228 ASSERT(reg.is_valid());
229 return reg;
230 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100231 int code() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000232 ASSERT(is_valid());
233 return code_;
234 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100235 int bit() const {
Leon Clarkee46be812010-01-19 14:06:41 +0000236 ASSERT(is_valid());
237 return 1 << code_;
238 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100239 void split_code(int* vm, int* m) const {
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100240 ASSERT(is_valid());
241 *m = (code_ & 0x10) >> 4;
242 *vm = code_ & 0x0F;
243 }
Leon Clarkee46be812010-01-19 14:06:41 +0000244
245 int code_;
246};
247
248
Ben Murdochb0fe1622011-05-05 13:52:32 +0100249typedef DwVfpRegister DoubleRegister;
250
251
Steve Block6ded16b2010-05-10 14:33:55 +0100252// Support for the VFP registers s0 to s31 (d0 to d15).
Leon Clarkee46be812010-01-19 14:06:41 +0000253// Note that "s(N):s(N+1)" is the same as "d(N/2)".
Steve Block6ded16b2010-05-10 14:33:55 +0100254const SwVfpRegister s0 = { 0 };
255const SwVfpRegister s1 = { 1 };
256const SwVfpRegister s2 = { 2 };
257const SwVfpRegister s3 = { 3 };
258const SwVfpRegister s4 = { 4 };
259const SwVfpRegister s5 = { 5 };
260const SwVfpRegister s6 = { 6 };
261const SwVfpRegister s7 = { 7 };
262const SwVfpRegister s8 = { 8 };
263const SwVfpRegister s9 = { 9 };
264const SwVfpRegister s10 = { 10 };
265const SwVfpRegister s11 = { 11 };
266const SwVfpRegister s12 = { 12 };
267const SwVfpRegister s13 = { 13 };
268const SwVfpRegister s14 = { 14 };
269const SwVfpRegister s15 = { 15 };
270const SwVfpRegister s16 = { 16 };
271const SwVfpRegister s17 = { 17 };
272const SwVfpRegister s18 = { 18 };
273const SwVfpRegister s19 = { 19 };
274const SwVfpRegister s20 = { 20 };
275const SwVfpRegister s21 = { 21 };
276const SwVfpRegister s22 = { 22 };
277const SwVfpRegister s23 = { 23 };
278const SwVfpRegister s24 = { 24 };
279const SwVfpRegister s25 = { 25 };
280const SwVfpRegister s26 = { 26 };
281const SwVfpRegister s27 = { 27 };
282const SwVfpRegister s28 = { 28 };
283const SwVfpRegister s29 = { 29 };
284const SwVfpRegister s30 = { 30 };
285const SwVfpRegister s31 = { 31 };
Leon Clarkee46be812010-01-19 14:06:41 +0000286
Steve Block6ded16b2010-05-10 14:33:55 +0100287const DwVfpRegister d0 = { 0 };
288const DwVfpRegister d1 = { 1 };
289const DwVfpRegister d2 = { 2 };
290const DwVfpRegister d3 = { 3 };
291const DwVfpRegister d4 = { 4 };
292const DwVfpRegister d5 = { 5 };
293const DwVfpRegister d6 = { 6 };
294const DwVfpRegister d7 = { 7 };
295const DwVfpRegister d8 = { 8 };
296const DwVfpRegister d9 = { 9 };
297const DwVfpRegister d10 = { 10 };
298const DwVfpRegister d11 = { 11 };
299const DwVfpRegister d12 = { 12 };
300const DwVfpRegister d13 = { 13 };
301const DwVfpRegister d14 = { 14 };
302const DwVfpRegister d15 = { 15 };
Leon Clarkee46be812010-01-19 14:06:41 +0000303
Steve Blocka7e24c12009-10-30 11:49:00 +0000304
305// Coprocessor register
306struct CRegister {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100307 bool is_valid() const { return 0 <= code_ && code_ < 16; }
308 bool is(CRegister creg) const { return code_ == creg.code_; }
309 int code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000310 ASSERT(is_valid());
311 return code_;
312 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100313 int bit() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000314 ASSERT(is_valid());
315 return 1 << code_;
316 }
317
Andrei Popescu31002712010-02-23 13:46:05 +0000318 // Unfortunately we can't make this private in a struct.
Steve Blocka7e24c12009-10-30 11:49:00 +0000319 int code_;
320};
321
322
Steve Block6ded16b2010-05-10 14:33:55 +0100323const CRegister no_creg = { -1 };
324
325const CRegister cr0 = { 0 };
326const CRegister cr1 = { 1 };
327const CRegister cr2 = { 2 };
328const CRegister cr3 = { 3 };
329const CRegister cr4 = { 4 };
330const CRegister cr5 = { 5 };
331const CRegister cr6 = { 6 };
332const CRegister cr7 = { 7 };
333const CRegister cr8 = { 8 };
334const CRegister cr9 = { 9 };
335const CRegister cr10 = { 10 };
336const CRegister cr11 = { 11 };
337const CRegister cr12 = { 12 };
338const CRegister cr13 = { 13 };
339const CRegister cr14 = { 14 };
340const CRegister cr15 = { 15 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000341
342
343// Coprocessor number
344enum Coprocessor {
345 p0 = 0,
346 p1 = 1,
347 p2 = 2,
348 p3 = 3,
349 p4 = 4,
350 p5 = 5,
351 p6 = 6,
352 p7 = 7,
353 p8 = 8,
354 p9 = 9,
355 p10 = 10,
356 p11 = 11,
357 p12 = 12,
358 p13 = 13,
359 p14 = 14,
360 p15 = 15
361};
362
363
Steve Blocka7e24c12009-10-30 11:49:00 +0000364// -----------------------------------------------------------------------------
365// Machine instruction Operands
366
367// Class Operand represents a shifter operand in data processing instructions
368class Operand BASE_EMBEDDED {
369 public:
370 // immediate
371 INLINE(explicit Operand(int32_t immediate,
372 RelocInfo::Mode rmode = RelocInfo::NONE));
373 INLINE(explicit Operand(const ExternalReference& f));
374 INLINE(explicit Operand(const char* s));
Steve Blocka7e24c12009-10-30 11:49:00 +0000375 explicit Operand(Handle<Object> handle);
376 INLINE(explicit Operand(Smi* value));
377
378 // rm
379 INLINE(explicit Operand(Register rm));
380
381 // rm <shift_op> shift_imm
382 explicit Operand(Register rm, ShiftOp shift_op, int shift_imm);
383
384 // rm <shift_op> rs
385 explicit Operand(Register rm, ShiftOp shift_op, Register rs);
386
387 // Return true if this is a register operand.
388 INLINE(bool is_reg() const);
389
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100390 // Return true of this operand fits in one instruction so that no
391 // 2-instruction solution with a load into the ip register is necessary.
392 bool is_single_instruction() const;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800393 bool must_use_constant_pool() const;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100394
395 inline int32_t immediate() const {
396 ASSERT(!rm_.is_valid());
397 return imm32_;
398 }
399
Steve Blocka7e24c12009-10-30 11:49:00 +0000400 Register rm() const { return rm_; }
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100401 Register rs() const { return rs_; }
402 ShiftOp shift_op() const { return shift_op_; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000403
404 private:
405 Register rm_;
406 Register rs_;
407 ShiftOp shift_op_;
408 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
409 int32_t imm32_; // valid if rm_ == no_reg
410 RelocInfo::Mode rmode_;
411
412 friend class Assembler;
413};
414
415
416// Class MemOperand represents a memory operand in load and store instructions
417class MemOperand BASE_EMBEDDED {
418 public:
419 // [rn +/- offset] Offset/NegOffset
420 // [rn +/- offset]! PreIndex/NegPreIndex
421 // [rn], +/- offset PostIndex/NegPostIndex
422 // offset is any signed 32-bit value; offset is first loaded to register ip if
423 // it does not fit the addressing mode (12-bit unsigned and sign bit)
424 explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset);
425
426 // [rn +/- rm] Offset/NegOffset
427 // [rn +/- rm]! PreIndex/NegPreIndex
428 // [rn], +/- rm PostIndex/NegPostIndex
429 explicit MemOperand(Register rn, Register rm, AddrMode am = Offset);
430
431 // [rn +/- rm <shift_op> shift_imm] Offset/NegOffset
432 // [rn +/- rm <shift_op> shift_imm]! PreIndex/NegPreIndex
433 // [rn], +/- rm <shift_op> shift_imm PostIndex/NegPostIndex
434 explicit MemOperand(Register rn, Register rm,
435 ShiftOp shift_op, int shift_imm, AddrMode am = Offset);
436
Kristian Monsen25f61362010-05-21 11:50:48 +0100437 void set_offset(int32_t offset) {
438 ASSERT(rm_.is(no_reg));
439 offset_ = offset;
440 }
441
442 uint32_t offset() {
443 ASSERT(rm_.is(no_reg));
444 return offset_;
445 }
446
Leon Clarkef7060e22010-06-03 12:02:55 +0100447 Register rn() const { return rn_; }
448 Register rm() const { return rm_; }
Kristian Monsen25f61362010-05-21 11:50:48 +0100449
Steve Blocka7e24c12009-10-30 11:49:00 +0000450 private:
451 Register rn_; // base
452 Register rm_; // register offset
453 int32_t offset_; // valid if rm_ == no_reg
454 ShiftOp shift_op_;
455 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
456 AddrMode am_; // bits P, U, and W
457
458 friend class Assembler;
459};
460
Steve Blockd0582a62009-12-15 09:54:21 +0000461// CpuFeatures keeps track of which features are supported by the target CPU.
462// Supported features must be enabled by a Scope before use.
463class CpuFeatures : public AllStatic {
464 public:
465 // Detect features of the target CPU. Set safe defaults if the serializer
466 // is enabled (snapshots must be portable).
Ben Murdochb0fe1622011-05-05 13:52:32 +0100467 static void Probe(bool portable);
Steve Blockd0582a62009-12-15 09:54:21 +0000468
469 // Check whether a feature is supported by the target CPU.
470 static bool IsSupported(CpuFeature f) {
471 if (f == VFP3 && !FLAG_enable_vfp3) return false;
472 return (supported_ & (1u << f)) != 0;
473 }
474
475 // Check whether a feature is currently enabled.
476 static bool IsEnabled(CpuFeature f) {
477 return (enabled_ & (1u << f)) != 0;
478 }
479
480 // Enable a specified feature within a scope.
481 class Scope BASE_EMBEDDED {
482#ifdef DEBUG
483 public:
484 explicit Scope(CpuFeature f) {
485 ASSERT(CpuFeatures::IsSupported(f));
486 ASSERT(!Serializer::enabled() ||
487 (found_by_runtime_probing_ & (1u << f)) == 0);
488 old_enabled_ = CpuFeatures::enabled_;
489 CpuFeatures::enabled_ |= 1u << f;
490 }
491 ~Scope() { CpuFeatures::enabled_ = old_enabled_; }
492 private:
493 unsigned old_enabled_;
494#else
495 public:
496 explicit Scope(CpuFeature f) {}
497#endif
498 };
499
500 private:
501 static unsigned supported_;
502 static unsigned enabled_;
503 static unsigned found_by_runtime_probing_;
504};
505
Steve Blocka7e24c12009-10-30 11:49:00 +0000506
Steve Blocka7e24c12009-10-30 11:49:00 +0000507extern const Instr kMovLrPc;
Steve Block6ded16b2010-05-10 14:33:55 +0100508extern const Instr kLdrPCMask;
Steve Blocka7e24c12009-10-30 11:49:00 +0000509extern const Instr kLdrPCPattern;
Steve Block6ded16b2010-05-10 14:33:55 +0100510extern const Instr kBlxRegMask;
511extern const Instr kBlxRegPattern;
Steve Blocka7e24c12009-10-30 11:49:00 +0000512
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100513extern const Instr kMovMvnMask;
514extern const Instr kMovMvnPattern;
515extern const Instr kMovMvnFlip;
516
517extern const Instr kMovLeaveCCMask;
518extern const Instr kMovLeaveCCPattern;
519extern const Instr kMovwMask;
520extern const Instr kMovwPattern;
521extern const Instr kMovwLeaveCCFlip;
522
523extern const Instr kCmpCmnMask;
524extern const Instr kCmpCmnPattern;
525extern const Instr kCmpCmnFlip;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100526extern const Instr kAddSubFlip;
527extern const Instr kAndBicFlip;
Steve Blocka7e24c12009-10-30 11:49:00 +0000528
Steve Block1e0659c2011-05-24 12:43:12 +0100529
530
Steve Blocka7e24c12009-10-30 11:49:00 +0000531class Assembler : public Malloced {
532 public:
533 // Create an assembler. Instructions and relocation information are emitted
534 // into a buffer, with the instructions starting from the beginning and the
535 // relocation information starting from the end of the buffer. See CodeDesc
536 // for a detailed comment on the layout (globals.h).
537 //
538 // If the provided buffer is NULL, the assembler allocates and grows its own
539 // buffer, and buffer_size determines the initial buffer size. The buffer is
540 // owned by the assembler and deallocated upon destruction of the assembler.
541 //
542 // If the provided buffer is not NULL, the assembler uses the provided buffer
543 // for code generation and assumes its size to be buffer_size. If the buffer
544 // is too small, a fatal error occurs. No deallocation of the buffer is done
545 // upon destruction of the assembler.
546 Assembler(void* buffer, int buffer_size);
547 ~Assembler();
548
549 // GetCode emits any pending (non-emitted) code and fills the descriptor
550 // desc. GetCode() is idempotent; it returns the same result if no other
551 // Assembler functions are invoked in between GetCode() calls.
552 void GetCode(CodeDesc* desc);
553
554 // Label operations & relative jumps (PPUM Appendix D)
555 //
556 // Takes a branch opcode (cc) and a label (L) and generates
557 // either a backward branch or a forward branch and links it
558 // to the label fixup chain. Usage:
559 //
560 // Label L; // unbound label
561 // j(cc, &L); // forward branch to unbound label
562 // bind(&L); // bind label to the current pc
563 // j(cc, &L); // backward branch to bound label
564 // bind(&L); // illegal: a label may be bound only once
565 //
566 // Note: The same Label can be used for forward and backward branches
567 // but it may be bound only once.
568
569 void bind(Label* L); // binds an unbound label L to the current code position
570
571 // Returns the branch offset to the given label from the current code position
572 // Links the label to the current position if it is still unbound
573 // Manages the jump elimination optimization if the second parameter is true.
574 int branch_offset(Label* L, bool jump_elimination_allowed);
575
576 // Puts a labels target address at the given position.
577 // The high 8 bits are set to zero.
578 void label_at_put(Label* L, int at_offset);
579
580 // Return the address in the constant pool of the code target address used by
581 // the branch/call instruction at pc.
582 INLINE(static Address target_address_address_at(Address pc));
583
584 // Read/Modify the code target address in the branch/call instruction at pc.
585 INLINE(static Address target_address_at(Address pc));
586 INLINE(static void set_target_address_at(Address pc, Address target));
587
Steve Blockd0582a62009-12-15 09:54:21 +0000588 // This sets the branch destination (which is in the constant pool on ARM).
589 // This is for calls and branches within generated code.
590 inline static void set_target_at(Address constant_pool_entry, Address target);
591
592 // This sets the branch destination (which is in the constant pool on ARM).
593 // This is for calls and branches to runtime code.
594 inline static void set_external_target_at(Address constant_pool_entry,
595 Address target) {
596 set_target_at(constant_pool_entry, target);
597 }
598
599 // Here we are patching the address in the constant pool, not the actual call
600 // instruction. The address in the constant pool is the same size as a
601 // pointer.
602 static const int kCallTargetSize = kPointerSize;
603 static const int kExternalTargetSize = kPointerSize;
604
Steve Blocka7e24c12009-10-30 11:49:00 +0000605 // Size of an instruction.
606 static const int kInstrSize = sizeof(Instr);
607
608 // Distance between the instruction referring to the address of the call
Steve Block6ded16b2010-05-10 14:33:55 +0100609 // target and the return address.
610#ifdef USE_BLX
611 // Call sequence is:
612 // ldr ip, [pc, #...] @ call address
613 // blx ip
614 // @ return address
615 static const int kCallTargetAddressOffset = 2 * kInstrSize;
616#else
617 // Call sequence is:
618 // mov lr, pc
619 // ldr pc, [pc, #...] @ call address
620 // @ return address
Steve Blocka7e24c12009-10-30 11:49:00 +0000621 static const int kCallTargetAddressOffset = kInstrSize;
Steve Block6ded16b2010-05-10 14:33:55 +0100622#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000623
624 // Distance between start of patched return sequence and the emitted address
625 // to jump to.
Steve Block6ded16b2010-05-10 14:33:55 +0100626#ifdef USE_BLX
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100627 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100628 // ldr ip, [pc, #0] @ emited address and start
629 // blx ip
630 static const int kPatchReturnSequenceAddressOffset = 0 * kInstrSize;
631#else
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100632 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100633 // mov lr, pc @ start of sequence
634 // ldr pc, [pc, #-4] @ emited address
635 static const int kPatchReturnSequenceAddressOffset = kInstrSize;
636#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000637
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100638 // Distance between start of patched debug break slot and the emitted address
639 // to jump to.
640#ifdef USE_BLX
641 // Patched debug break slot code is:
642 // ldr ip, [pc, #0] @ emited address and start
643 // blx ip
644 static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
645#else
646 // Patched debug break slot code is:
647 // mov lr, pc @ start of sequence
648 // ldr pc, [pc, #-4] @ emited address
649 static const int kPatchDebugBreakSlotAddressOffset = kInstrSize;
650#endif
651
Steve Blocka7e24c12009-10-30 11:49:00 +0000652 // Difference between address of current opcode and value read from pc
653 // register.
654 static const int kPcLoadDelta = 8;
655
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100656 static const int kJSReturnSequenceInstructions = 4;
657 static const int kDebugBreakSlotInstructions = 3;
658 static const int kDebugBreakSlotLength =
659 kDebugBreakSlotInstructions * kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +0000660
661 // ---------------------------------------------------------------------------
662 // Code generation
663
664 // Insert the smallest number of nop instructions
665 // possible to align the pc offset to a multiple
666 // of m. m must be a power of 2 (>= 4).
667 void Align(int m);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100668 // Aligns code to something that's optimal for a jump target for the platform.
669 void CodeTargetAlign();
Steve Blocka7e24c12009-10-30 11:49:00 +0000670
671 // Branch instructions
672 void b(int branch_offset, Condition cond = al);
673 void bl(int branch_offset, Condition cond = al);
674 void blx(int branch_offset); // v5 and above
675 void blx(Register target, Condition cond = al); // v5 and above
676 void bx(Register target, Condition cond = al); // v5 and above, plus v4t
677
678 // Convenience branch instructions using labels
679 void b(Label* L, Condition cond = al) {
680 b(branch_offset(L, cond == al), cond);
681 }
682 void b(Condition cond, Label* L) { b(branch_offset(L, cond == al), cond); }
683 void bl(Label* L, Condition cond = al) { bl(branch_offset(L, false), cond); }
684 void bl(Condition cond, Label* L) { bl(branch_offset(L, false), cond); }
685 void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above
686
687 // Data-processing instructions
Andrei Popescu31002712010-02-23 13:46:05 +0000688
Steve Blocka7e24c12009-10-30 11:49:00 +0000689 void and_(Register dst, Register src1, const Operand& src2,
690 SBit s = LeaveCC, Condition cond = al);
691
692 void eor(Register dst, Register src1, const Operand& src2,
693 SBit s = LeaveCC, Condition cond = al);
694
695 void sub(Register dst, Register src1, const Operand& src2,
696 SBit s = LeaveCC, Condition cond = al);
697 void sub(Register dst, Register src1, Register src2,
698 SBit s = LeaveCC, Condition cond = al) {
699 sub(dst, src1, Operand(src2), s, cond);
700 }
701
702 void rsb(Register dst, Register src1, const Operand& src2,
703 SBit s = LeaveCC, Condition cond = al);
704
705 void add(Register dst, Register src1, const Operand& src2,
706 SBit s = LeaveCC, Condition cond = al);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100707 void add(Register dst, Register src1, Register src2,
708 SBit s = LeaveCC, Condition cond = al) {
709 add(dst, src1, Operand(src2), s, cond);
710 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000711
712 void adc(Register dst, Register src1, const Operand& src2,
713 SBit s = LeaveCC, Condition cond = al);
714
715 void sbc(Register dst, Register src1, const Operand& src2,
716 SBit s = LeaveCC, Condition cond = al);
717
718 void rsc(Register dst, Register src1, const Operand& src2,
719 SBit s = LeaveCC, Condition cond = al);
720
721 void tst(Register src1, const Operand& src2, Condition cond = al);
722 void tst(Register src1, Register src2, Condition cond = al) {
723 tst(src1, Operand(src2), cond);
724 }
725
726 void teq(Register src1, const Operand& src2, Condition cond = al);
727
728 void cmp(Register src1, const Operand& src2, Condition cond = al);
729 void cmp(Register src1, Register src2, Condition cond = al) {
730 cmp(src1, Operand(src2), cond);
731 }
Steve Block1e0659c2011-05-24 12:43:12 +0100732 void cmp_raw_immediate(Register src1, int raw_immediate, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000733
734 void cmn(Register src1, const Operand& src2, Condition cond = al);
735
736 void orr(Register dst, Register src1, const Operand& src2,
737 SBit s = LeaveCC, Condition cond = al);
738 void orr(Register dst, Register src1, Register src2,
739 SBit s = LeaveCC, Condition cond = al) {
740 orr(dst, src1, Operand(src2), s, cond);
741 }
742
743 void mov(Register dst, const Operand& src,
744 SBit s = LeaveCC, Condition cond = al);
745 void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
746 mov(dst, Operand(src), s, cond);
747 }
748
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100749 // ARMv7 instructions for loading a 32 bit immediate in two instructions.
750 // This may actually emit a different mov instruction, but on an ARMv7 it
751 // is guaranteed to only emit one instruction.
752 void movw(Register reg, uint32_t immediate, Condition cond = al);
753 // The constant for movt should be in the range 0-0xffff.
754 void movt(Register reg, uint32_t immediate, Condition cond = al);
755
Steve Blocka7e24c12009-10-30 11:49:00 +0000756 void bic(Register dst, Register src1, const Operand& src2,
757 SBit s = LeaveCC, Condition cond = al);
758
759 void mvn(Register dst, const Operand& src,
760 SBit s = LeaveCC, Condition cond = al);
761
762 // Multiply instructions
763
764 void mla(Register dst, Register src1, Register src2, Register srcA,
765 SBit s = LeaveCC, Condition cond = al);
766
767 void mul(Register dst, Register src1, Register src2,
768 SBit s = LeaveCC, Condition cond = al);
769
770 void smlal(Register dstL, Register dstH, Register src1, Register src2,
771 SBit s = LeaveCC, Condition cond = al);
772
773 void smull(Register dstL, Register dstH, Register src1, Register src2,
774 SBit s = LeaveCC, Condition cond = al);
775
776 void umlal(Register dstL, Register dstH, Register src1, Register src2,
777 SBit s = LeaveCC, Condition cond = al);
778
779 void umull(Register dstL, Register dstH, Register src1, Register src2,
780 SBit s = LeaveCC, Condition cond = al);
781
782 // Miscellaneous arithmetic instructions
783
784 void clz(Register dst, Register src, Condition cond = al); // v5 and above
785
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100786 // Saturating instructions. v6 and above.
787
788 // Unsigned saturate.
789 //
790 // Saturate an optionally shifted signed value to an unsigned range.
791 //
792 // usat dst, #satpos, src
793 // usat dst, #satpos, src, lsl #sh
794 // usat dst, #satpos, src, asr #sh
795 //
796 // Register dst will contain:
797 //
798 // 0, if s < 0
799 // (1 << satpos) - 1, if s > ((1 << satpos) - 1)
800 // s, otherwise
801 //
802 // where s is the contents of src after shifting (if used.)
803 void usat(Register dst, int satpos, const Operand& src, Condition cond = al);
804
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100805 // Bitfield manipulation instructions. v7 and above.
806
807 void ubfx(Register dst, Register src, int lsb, int width,
808 Condition cond = al);
809
810 void sbfx(Register dst, Register src, int lsb, int width,
811 Condition cond = al);
812
813 void bfc(Register dst, int lsb, int width, Condition cond = al);
814
815 void bfi(Register dst, Register src, int lsb, int width,
816 Condition cond = al);
817
Steve Blocka7e24c12009-10-30 11:49:00 +0000818 // Status register access instructions
819
820 void mrs(Register dst, SRegister s, Condition cond = al);
821 void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al);
822
823 // Load/Store instructions
824 void ldr(Register dst, const MemOperand& src, Condition cond = al);
825 void str(Register src, const MemOperand& dst, Condition cond = al);
826 void ldrb(Register dst, const MemOperand& src, Condition cond = al);
827 void strb(Register src, const MemOperand& dst, Condition cond = al);
828 void ldrh(Register dst, const MemOperand& src, Condition cond = al);
829 void strh(Register src, const MemOperand& dst, Condition cond = al);
830 void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
831 void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
Leon Clarkef7060e22010-06-03 12:02:55 +0100832 void ldrd(Register dst1,
833 Register dst2,
834 const MemOperand& src, Condition cond = al);
835 void strd(Register src1,
836 Register src2,
837 const MemOperand& dst, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000838
839 // Load/Store multiple instructions
840 void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
841 void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
842
Steve Blocka7e24c12009-10-30 11:49:00 +0000843 // Exception-generating instructions and debugging support
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800844 void stop(const char* msg,
845 Condition cond = al,
846 int32_t code = kDefaultStopCode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000847
848 void bkpt(uint32_t imm16); // v5 and above
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800849 void svc(uint32_t imm24, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000850
851 // Coprocessor instructions
852
853 void cdp(Coprocessor coproc, int opcode_1,
854 CRegister crd, CRegister crn, CRegister crm,
855 int opcode_2, Condition cond = al);
856
857 void cdp2(Coprocessor coproc, int opcode_1,
858 CRegister crd, CRegister crn, CRegister crm,
859 int opcode_2); // v5 and above
860
861 void mcr(Coprocessor coproc, int opcode_1,
862 Register rd, CRegister crn, CRegister crm,
863 int opcode_2 = 0, Condition cond = al);
864
865 void mcr2(Coprocessor coproc, int opcode_1,
866 Register rd, CRegister crn, CRegister crm,
867 int opcode_2 = 0); // v5 and above
868
869 void mrc(Coprocessor coproc, int opcode_1,
870 Register rd, CRegister crn, CRegister crm,
871 int opcode_2 = 0, Condition cond = al);
872
873 void mrc2(Coprocessor coproc, int opcode_1,
874 Register rd, CRegister crn, CRegister crm,
875 int opcode_2 = 0); // v5 and above
876
877 void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src,
878 LFlag l = Short, Condition cond = al);
879 void ldc(Coprocessor coproc, CRegister crd, Register base, int option,
880 LFlag l = Short, Condition cond = al);
881
882 void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
883 LFlag l = Short); // v5 and above
884 void ldc2(Coprocessor coproc, CRegister crd, Register base, int option,
885 LFlag l = Short); // v5 and above
886
887 void stc(Coprocessor coproc, CRegister crd, const MemOperand& dst,
888 LFlag l = Short, Condition cond = al);
889 void stc(Coprocessor coproc, CRegister crd, Register base, int option,
890 LFlag l = Short, Condition cond = al);
891
892 void stc2(Coprocessor coproc, CRegister crd, const MemOperand& dst,
893 LFlag l = Short); // v5 and above
894 void stc2(Coprocessor coproc, CRegister crd, Register base, int option,
895 LFlag l = Short); // v5 and above
896
Steve Blockd0582a62009-12-15 09:54:21 +0000897 // Support for VFP.
898 // All these APIs support S0 to S31 and D0 to D15.
899 // Currently these APIs do not support extended D registers, i.e, D16 to D31.
900 // However, some simple modifications can allow
901 // these APIs to support D16 to D31.
902
Leon Clarked91b9f72010-01-27 17:25:45 +0000903 void vldr(const DwVfpRegister dst,
904 const Register base,
905 int offset, // Offset must be a multiple of 4.
906 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +0100907
908 void vldr(const SwVfpRegister dst,
909 const Register base,
910 int offset, // Offset must be a multiple of 4.
911 const Condition cond = al);
912
Leon Clarked91b9f72010-01-27 17:25:45 +0000913 void vstr(const DwVfpRegister src,
914 const Register base,
915 int offset, // Offset must be a multiple of 4.
916 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +0100917
Iain Merrick75681382010-08-19 15:07:18 +0100918 void vstr(const SwVfpRegister src,
919 const Register base,
920 int offset, // Offset must be a multiple of 4.
921 const Condition cond = al);
922
Steve Block8defd9f2010-07-08 12:39:36 +0100923 void vmov(const DwVfpRegister dst,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100924 double imm,
925 const Condition cond = al);
926 void vmov(const SwVfpRegister dst,
927 const SwVfpRegister src,
928 const Condition cond = al);
929 void vmov(const DwVfpRegister dst,
Steve Block8defd9f2010-07-08 12:39:36 +0100930 const DwVfpRegister src,
931 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +0000932 void vmov(const DwVfpRegister dst,
933 const Register src1,
Steve Blockd0582a62009-12-15 09:54:21 +0000934 const Register src2,
Leon Clarkee46be812010-01-19 14:06:41 +0000935 const Condition cond = al);
936 void vmov(const Register dst1,
937 const Register dst2,
938 const DwVfpRegister src,
939 const Condition cond = al);
940 void vmov(const SwVfpRegister dst,
941 const Register src,
942 const Condition cond = al);
943 void vmov(const Register dst,
944 const SwVfpRegister src,
945 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +0100946 void vcvt_f64_s32(const DwVfpRegister dst,
947 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +0100948 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +0100949 const Condition cond = al);
950 void vcvt_f32_s32(const SwVfpRegister dst,
951 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +0100952 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +0100953 const Condition cond = al);
954 void vcvt_f64_u32(const DwVfpRegister dst,
955 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +0100956 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +0100957 const Condition cond = al);
958 void vcvt_s32_f64(const SwVfpRegister dst,
959 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +0100960 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +0100961 const Condition cond = al);
962 void vcvt_u32_f64(const SwVfpRegister dst,
963 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +0100964 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +0100965 const Condition cond = al);
966 void vcvt_f64_f32(const DwVfpRegister dst,
967 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +0100968 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +0100969 const Condition cond = al);
970 void vcvt_f32_f64(const SwVfpRegister dst,
971 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +0100972 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +0100973 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +0000974
Steve Block1e0659c2011-05-24 12:43:12 +0100975 void vabs(const DwVfpRegister dst,
976 const DwVfpRegister src,
977 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +0000978 void vadd(const DwVfpRegister dst,
979 const DwVfpRegister src1,
980 const DwVfpRegister src2,
981 const Condition cond = al);
982 void vsub(const DwVfpRegister dst,
983 const DwVfpRegister src1,
984 const DwVfpRegister src2,
985 const Condition cond = al);
986 void vmul(const DwVfpRegister dst,
987 const DwVfpRegister src1,
988 const DwVfpRegister src2,
989 const Condition cond = al);
990 void vdiv(const DwVfpRegister dst,
991 const DwVfpRegister src1,
992 const DwVfpRegister src2,
993 const Condition cond = al);
994 void vcmp(const DwVfpRegister src1,
995 const DwVfpRegister src2,
Steve Blockd0582a62009-12-15 09:54:21 +0000996 const Condition cond = al);
Iain Merrick75681382010-08-19 15:07:18 +0100997 void vcmp(const DwVfpRegister src1,
998 const double src2,
Iain Merrick75681382010-08-19 15:07:18 +0100999 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001000 void vmrs(const Register dst,
1001 const Condition cond = al);
Russell Brenner90bac252010-11-18 13:33:46 -08001002 void vmsr(const Register dst,
1003 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +01001004 void vsqrt(const DwVfpRegister dst,
1005 const DwVfpRegister src,
1006 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001007
Steve Blocka7e24c12009-10-30 11:49:00 +00001008 // Pseudo instructions
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001009
1010 // Different nop operations are used by the code generator to detect certain
1011 // states of the generated code.
1012 enum NopMarkerTypes {
1013 NON_MARKING_NOP = 0,
1014 DEBUG_BREAK_NOP,
1015 // IC markers.
1016 PROPERTY_ACCESS_INLINED,
1017 PROPERTY_ACCESS_INLINED_CONTEXT,
1018 PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE,
1019 // Helper values.
1020 LAST_CODE_MARKER,
1021 FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED
1022 };
1023
1024 void nop(int type = 0); // 0 is the default non-marking type.
Steve Blocka7e24c12009-10-30 11:49:00 +00001025
1026 void push(Register src, Condition cond = al) {
1027 str(src, MemOperand(sp, 4, NegPreIndex), cond);
1028 }
1029
1030 void pop(Register dst, Condition cond = al) {
1031 ldr(dst, MemOperand(sp, 4, PostIndex), cond);
1032 }
1033
1034 void pop() {
1035 add(sp, sp, Operand(kPointerSize));
1036 }
1037
Steve Blocka7e24c12009-10-30 11:49:00 +00001038 // Jump unconditionally to given label.
1039 void jmp(Label* L) { b(L, al); }
1040
1041 // Check the code size generated from label to here.
1042 int InstructionsGeneratedSince(Label* l) {
1043 return (pc_offset() - l->pos()) / kInstrSize;
1044 }
1045
Steve Blockd0582a62009-12-15 09:54:21 +00001046 // Check whether an immediate fits an addressing mode 1 instruction.
1047 bool ImmediateFitsAddrMode1Instruction(int32_t imm32);
1048
Steve Block6ded16b2010-05-10 14:33:55 +01001049 // Class for scoping postponing the constant pool generation.
1050 class BlockConstPoolScope {
1051 public:
1052 explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) {
1053 assem_->StartBlockConstPool();
1054 }
1055 ~BlockConstPoolScope() {
1056 assem_->EndBlockConstPool();
1057 }
1058
1059 private:
1060 Assembler* assem_;
1061
1062 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstPoolScope);
1063 };
1064
Steve Blockd0582a62009-12-15 09:54:21 +00001065 // Postpone the generation of the constant pool for the specified number of
1066 // instructions.
1067 void BlockConstPoolFor(int instructions);
1068
Steve Blocka7e24c12009-10-30 11:49:00 +00001069 // Debugging
1070
1071 // Mark address of the ExitJSFrame code.
1072 void RecordJSReturn();
1073
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001074 // Mark address of a debug break slot.
1075 void RecordDebugBreakSlot();
1076
Steve Blocka7e24c12009-10-30 11:49:00 +00001077 // Record a comment relocation entry that can be used by a disassembler.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001078 // Use --code-comments to enable.
Steve Blocka7e24c12009-10-30 11:49:00 +00001079 void RecordComment(const char* msg);
1080
Ben Murdochb8e0da22011-05-16 14:20:40 +01001081 // Writes a single byte or word of data in the code stream. Used
1082 // for inline tables, e.g., jump-tables. The constant pool should be
1083 // emitted before any use of db and dd to ensure that constant pools
1084 // are not emitted as part of the tables generated.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001085 void db(uint8_t data);
1086 void dd(uint32_t data);
1087
Steve Blocka7e24c12009-10-30 11:49:00 +00001088 int pc_offset() const { return pc_ - buffer_; }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001089
1090 PositionsRecorder* positions_recorder() { return &positions_recorder_; }
Steve Block6ded16b2010-05-10 14:33:55 +01001091
Leon Clarkef7060e22010-06-03 12:02:55 +01001092 bool can_peephole_optimize(int instructions) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001093 if (!allow_peephole_optimization_) return false;
Leon Clarkef7060e22010-06-03 12:02:55 +01001094 if (last_bound_pos_ > pc_offset() - instructions * kInstrSize) return false;
1095 return reloc_info_writer.last_pc() <= pc_ - instructions * kInstrSize;
1096 }
1097
Steve Block6ded16b2010-05-10 14:33:55 +01001098 // Read/patch instructions
1099 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
1100 static void instr_at_put(byte* pc, Instr instr) {
1101 *reinterpret_cast<Instr*>(pc) = instr;
1102 }
Steve Block1e0659c2011-05-24 12:43:12 +01001103 static Condition GetCondition(Instr instr);
Steve Block6ded16b2010-05-10 14:33:55 +01001104 static bool IsBranch(Instr instr);
1105 static int GetBranchOffset(Instr instr);
1106 static bool IsLdrRegisterImmediate(Instr instr);
1107 static int GetLdrRegisterImmediateOffset(Instr instr);
1108 static Instr SetLdrRegisterImmediateOffset(Instr instr, int offset);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001109 static bool IsStrRegisterImmediate(Instr instr);
1110 static Instr SetStrRegisterImmediateOffset(Instr instr, int offset);
1111 static bool IsAddRegisterImmediate(Instr instr);
1112 static Instr SetAddRegisterImmediateOffset(Instr instr, int offset);
Leon Clarkef7060e22010-06-03 12:02:55 +01001113 static Register GetRd(Instr instr);
Steve Block1e0659c2011-05-24 12:43:12 +01001114 static Register GetRn(Instr instr);
1115 static Register GetRm(Instr instr);
Leon Clarkef7060e22010-06-03 12:02:55 +01001116 static bool IsPush(Instr instr);
1117 static bool IsPop(Instr instr);
1118 static bool IsStrRegFpOffset(Instr instr);
1119 static bool IsLdrRegFpOffset(Instr instr);
1120 static bool IsStrRegFpNegOffset(Instr instr);
1121 static bool IsLdrRegFpNegOffset(Instr instr);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001122 static bool IsLdrPcImmediateOffset(Instr instr);
Steve Block1e0659c2011-05-24 12:43:12 +01001123 static bool IsTstImmediate(Instr instr);
1124 static bool IsCmpRegister(Instr instr);
1125 static bool IsCmpImmediate(Instr instr);
1126 static Register GetCmpImmediateRegister(Instr instr);
1127 static int GetCmpImmediateRawImmediate(Instr instr);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001128 static bool IsNop(Instr instr, int type = NON_MARKING_NOP);
Steve Block6ded16b2010-05-10 14:33:55 +01001129
Ben Murdochb0fe1622011-05-05 13:52:32 +01001130 // Check if is time to emit a constant pool for pending reloc info entries
1131 void CheckConstPool(bool force_emit, bool require_jump);
Steve Blocka7e24c12009-10-30 11:49:00 +00001132
1133 protected:
1134 int buffer_space() const { return reloc_info_writer.pos() - pc_; }
1135
1136 // Read/patch instructions
Steve Blocka7e24c12009-10-30 11:49:00 +00001137 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
1138 void instr_at_put(int pos, Instr instr) {
1139 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
1140 }
1141
1142 // Decode branch instruction at pos and return branch target pos
1143 int target_at(int pos);
1144
1145 // Patch branch instruction at pos to branch to given branch target pos
1146 void target_at_put(int pos, int target_pos);
1147
Steve Blocka7e24c12009-10-30 11:49:00 +00001148 // Block the emission of the constant pool before pc_offset
1149 void BlockConstPoolBefore(int pc_offset) {
1150 if (no_const_pool_before_ < pc_offset) no_const_pool_before_ = pc_offset;
1151 }
1152
Steve Block6ded16b2010-05-10 14:33:55 +01001153 void StartBlockConstPool() {
1154 const_pool_blocked_nesting_++;
1155 }
1156 void EndBlockConstPool() {
1157 const_pool_blocked_nesting_--;
1158 }
Steve Block8defd9f2010-07-08 12:39:36 +01001159 bool is_const_pool_blocked() const { return const_pool_blocked_nesting_ > 0; }
Steve Block6ded16b2010-05-10 14:33:55 +01001160
Steve Blocka7e24c12009-10-30 11:49:00 +00001161 private:
1162 // Code buffer:
1163 // The buffer into which code and relocation info are generated.
1164 byte* buffer_;
1165 int buffer_size_;
1166 // True if the assembler owns the buffer, false if buffer is external.
1167 bool own_buffer_;
1168
1169 // Buffer size and constant pool distance are checked together at regular
1170 // intervals of kBufferCheckInterval emitted bytes
1171 static const int kBufferCheckInterval = 1*KB/2;
1172 int next_buffer_check_; // pc offset of next buffer check
1173
1174 // Code generation
1175 // The relocation writer's position is at least kGap bytes below the end of
1176 // the generated instructions. This is so that multi-instruction sequences do
1177 // not have to check for overflow. The same is true for writes of large
1178 // relocation info entries.
1179 static const int kGap = 32;
1180 byte* pc_; // the program counter; moves forward
1181
1182 // Constant pool generation
1183 // Pools are emitted in the instruction stream, preferably after unconditional
1184 // jumps or after returns from functions (in dead code locations).
1185 // If a long code sequence does not contain unconditional jumps, it is
1186 // necessary to emit the constant pool before the pool gets too far from the
1187 // location it is accessed from. In this case, we emit a jump over the emitted
1188 // constant pool.
1189 // Constants in the pool may be addresses of functions that gets relocated;
1190 // if so, a relocation info entry is associated to the constant pool entry.
1191
1192 // Repeated checking whether the constant pool should be emitted is rather
1193 // expensive. By default we only check again once a number of instructions
1194 // has been generated. That also means that the sizing of the buffers is not
1195 // an exact science, and that we rely on some slop to not overrun buffers.
1196 static const int kCheckConstIntervalInst = 32;
1197 static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize;
1198
1199
1200 // Pools are emitted after function return and in dead code at (more or less)
1201 // regular intervals of kDistBetweenPools bytes
1202 static const int kDistBetweenPools = 1*KB;
1203
1204 // Constants in pools are accessed via pc relative addressing, which can
1205 // reach +/-4KB thereby defining a maximum distance between the instruction
1206 // and the accessed constant. We satisfy this constraint by limiting the
1207 // distance between pools.
1208 static const int kMaxDistBetweenPools = 4*KB - 2*kBufferCheckInterval;
1209
Steve Block6ded16b2010-05-10 14:33:55 +01001210 // Emission of the constant pool may be blocked in some code sequences.
1211 int const_pool_blocked_nesting_; // Block emission if this is not zero.
1212 int no_const_pool_before_; // Block emission before this pc offset.
Steve Blocka7e24c12009-10-30 11:49:00 +00001213
1214 // Keep track of the last emitted pool to guarantee a maximal distance
1215 int last_const_pool_end_; // pc offset following the last constant pool
1216
1217 // Relocation info generation
1218 // Each relocation is encoded as a variable size value
1219 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1220 RelocInfoWriter reloc_info_writer;
1221 // Relocation info records are also used during code generation as temporary
1222 // containers for constants and code target addresses until they are emitted
1223 // to the constant pool. These pending relocation info records are temporarily
1224 // stored in a separate buffer until a constant pool is emitted.
1225 // If every instruction in a long sequence is accessing the pool, we need one
1226 // pending relocation entry per instruction.
1227 static const int kMaxNumPRInfo = kMaxDistBetweenPools/kInstrSize;
1228 RelocInfo prinfo_[kMaxNumPRInfo]; // the buffer of pending relocation info
1229 int num_prinfo_; // number of pending reloc info entries in the buffer
1230
1231 // The bound position, before this we cannot do instruction elimination.
1232 int last_bound_pos_;
1233
Steve Blocka7e24c12009-10-30 11:49:00 +00001234 // Code emission
1235 inline void CheckBuffer();
1236 void GrowBuffer();
1237 inline void emit(Instr x);
1238
1239 // Instruction generation
1240 void addrmod1(Instr instr, Register rn, Register rd, const Operand& x);
1241 void addrmod2(Instr instr, Register rd, const MemOperand& x);
1242 void addrmod3(Instr instr, Register rd, const MemOperand& x);
1243 void addrmod4(Instr instr, Register rn, RegList rl);
1244 void addrmod5(Instr instr, CRegister crd, const MemOperand& x);
1245
1246 // Labels
1247 void print(Label* L);
1248 void bind_to(Label* L, int pos);
1249 void link_to(Label* L, Label* appendix);
1250 void next(Label* L);
1251
1252 // Record reloc info for current pc_
1253 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
1254
1255 friend class RegExpMacroAssemblerARM;
1256 friend class RelocInfo;
1257 friend class CodePatcher;
Steve Block6ded16b2010-05-10 14:33:55 +01001258 friend class BlockConstPoolScope;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001259
1260 PositionsRecorder positions_recorder_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001261 bool allow_peephole_optimization_;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001262 friend class PositionsRecorder;
1263 friend class EnsureSpace;
Steve Blocka7e24c12009-10-30 11:49:00 +00001264};
1265
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001266
1267class EnsureSpace BASE_EMBEDDED {
1268 public:
1269 explicit EnsureSpace(Assembler* assembler) {
1270 assembler->CheckBuffer();
1271 }
1272};
1273
1274
Steve Blocka7e24c12009-10-30 11:49:00 +00001275} } // namespace v8::internal
1276
1277#endif // V8_ARM_ASSEMBLER_ARM_H_