blob: f5eb5075f6c4c98372d8ff2b94c754131155f134 [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
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100287const DwVfpRegister no_dreg = { -1 };
Steve Block6ded16b2010-05-10 14:33:55 +0100288const DwVfpRegister d0 = { 0 };
289const DwVfpRegister d1 = { 1 };
290const DwVfpRegister d2 = { 2 };
291const DwVfpRegister d3 = { 3 };
292const DwVfpRegister d4 = { 4 };
293const DwVfpRegister d5 = { 5 };
294const DwVfpRegister d6 = { 6 };
295const DwVfpRegister d7 = { 7 };
296const DwVfpRegister d8 = { 8 };
297const DwVfpRegister d9 = { 9 };
298const DwVfpRegister d10 = { 10 };
299const DwVfpRegister d11 = { 11 };
300const DwVfpRegister d12 = { 12 };
301const DwVfpRegister d13 = { 13 };
302const DwVfpRegister d14 = { 14 };
303const DwVfpRegister d15 = { 15 };
Leon Clarkee46be812010-01-19 14:06:41 +0000304
Steve Blocka7e24c12009-10-30 11:49:00 +0000305
306// Coprocessor register
307struct CRegister {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100308 bool is_valid() const { return 0 <= code_ && code_ < 16; }
309 bool is(CRegister creg) const { return code_ == creg.code_; }
310 int code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000311 ASSERT(is_valid());
312 return code_;
313 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100314 int bit() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000315 ASSERT(is_valid());
316 return 1 << code_;
317 }
318
Andrei Popescu31002712010-02-23 13:46:05 +0000319 // Unfortunately we can't make this private in a struct.
Steve Blocka7e24c12009-10-30 11:49:00 +0000320 int code_;
321};
322
323
Steve Block6ded16b2010-05-10 14:33:55 +0100324const CRegister no_creg = { -1 };
325
326const CRegister cr0 = { 0 };
327const CRegister cr1 = { 1 };
328const CRegister cr2 = { 2 };
329const CRegister cr3 = { 3 };
330const CRegister cr4 = { 4 };
331const CRegister cr5 = { 5 };
332const CRegister cr6 = { 6 };
333const CRegister cr7 = { 7 };
334const CRegister cr8 = { 8 };
335const CRegister cr9 = { 9 };
336const CRegister cr10 = { 10 };
337const CRegister cr11 = { 11 };
338const CRegister cr12 = { 12 };
339const CRegister cr13 = { 13 };
340const CRegister cr14 = { 14 };
341const CRegister cr15 = { 15 };
Steve Blocka7e24c12009-10-30 11:49:00 +0000342
343
344// Coprocessor number
345enum Coprocessor {
346 p0 = 0,
347 p1 = 1,
348 p2 = 2,
349 p3 = 3,
350 p4 = 4,
351 p5 = 5,
352 p6 = 6,
353 p7 = 7,
354 p8 = 8,
355 p9 = 9,
356 p10 = 10,
357 p11 = 11,
358 p12 = 12,
359 p13 = 13,
360 p14 = 14,
361 p15 = 15
362};
363
364
Steve Blocka7e24c12009-10-30 11:49:00 +0000365// -----------------------------------------------------------------------------
366// Machine instruction Operands
367
368// Class Operand represents a shifter operand in data processing instructions
369class Operand BASE_EMBEDDED {
370 public:
371 // immediate
372 INLINE(explicit Operand(int32_t immediate,
373 RelocInfo::Mode rmode = RelocInfo::NONE));
374 INLINE(explicit Operand(const ExternalReference& f));
375 INLINE(explicit Operand(const char* s));
Steve Blocka7e24c12009-10-30 11:49:00 +0000376 explicit Operand(Handle<Object> handle);
377 INLINE(explicit Operand(Smi* value));
378
379 // rm
380 INLINE(explicit Operand(Register rm));
381
382 // rm <shift_op> shift_imm
383 explicit Operand(Register rm, ShiftOp shift_op, int shift_imm);
384
385 // rm <shift_op> rs
386 explicit Operand(Register rm, ShiftOp shift_op, Register rs);
387
388 // Return true if this is a register operand.
389 INLINE(bool is_reg() const);
390
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100391 // Return true if this operand fits in one instruction so that no
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100392 // 2-instruction solution with a load into the ip register is necessary.
393 bool is_single_instruction() const;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800394 bool must_use_constant_pool() const;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100395
396 inline int32_t immediate() const {
397 ASSERT(!rm_.is_valid());
398 return imm32_;
399 }
400
Steve Blocka7e24c12009-10-30 11:49:00 +0000401 Register rm() const { return rm_; }
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100402 Register rs() const { return rs_; }
403 ShiftOp shift_op() const { return shift_op_; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000404
405 private:
406 Register rm_;
407 Register rs_;
408 ShiftOp shift_op_;
409 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
410 int32_t imm32_; // valid if rm_ == no_reg
411 RelocInfo::Mode rmode_;
412
413 friend class Assembler;
414};
415
416
417// Class MemOperand represents a memory operand in load and store instructions
418class MemOperand BASE_EMBEDDED {
419 public:
420 // [rn +/- offset] Offset/NegOffset
421 // [rn +/- offset]! PreIndex/NegPreIndex
422 // [rn], +/- offset PostIndex/NegPostIndex
423 // offset is any signed 32-bit value; offset is first loaded to register ip if
424 // it does not fit the addressing mode (12-bit unsigned and sign bit)
425 explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset);
426
427 // [rn +/- rm] Offset/NegOffset
428 // [rn +/- rm]! PreIndex/NegPreIndex
429 // [rn], +/- rm PostIndex/NegPostIndex
430 explicit MemOperand(Register rn, Register rm, AddrMode am = Offset);
431
432 // [rn +/- rm <shift_op> shift_imm] Offset/NegOffset
433 // [rn +/- rm <shift_op> shift_imm]! PreIndex/NegPreIndex
434 // [rn], +/- rm <shift_op> shift_imm PostIndex/NegPostIndex
435 explicit MemOperand(Register rn, Register rm,
436 ShiftOp shift_op, int shift_imm, AddrMode am = Offset);
437
Kristian Monsen25f61362010-05-21 11:50:48 +0100438 void set_offset(int32_t offset) {
439 ASSERT(rm_.is(no_reg));
440 offset_ = offset;
441 }
442
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100443 uint32_t offset() const {
Kristian Monsen25f61362010-05-21 11:50:48 +0100444 ASSERT(rm_.is(no_reg));
445 return offset_;
446 }
447
Leon Clarkef7060e22010-06-03 12:02:55 +0100448 Register rn() const { return rn_; }
449 Register rm() const { return rm_; }
Kristian Monsen25f61362010-05-21 11:50:48 +0100450
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100451 bool OffsetIsUint12Encodable() const {
452 return offset_ >= 0 ? is_uint12(offset_) : is_uint12(-offset_);
453 }
454
Steve Blocka7e24c12009-10-30 11:49:00 +0000455 private:
456 Register rn_; // base
457 Register rm_; // register offset
458 int32_t offset_; // valid if rm_ == no_reg
459 ShiftOp shift_op_;
460 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
461 AddrMode am_; // bits P, U, and W
462
463 friend class Assembler;
464};
465
Steve Blockd0582a62009-12-15 09:54:21 +0000466// CpuFeatures keeps track of which features are supported by the target CPU.
467// Supported features must be enabled by a Scope before use.
468class CpuFeatures : public AllStatic {
469 public:
470 // Detect features of the target CPU. Set safe defaults if the serializer
471 // is enabled (snapshots must be portable).
Ben Murdochb0fe1622011-05-05 13:52:32 +0100472 static void Probe(bool portable);
Steve Blockd0582a62009-12-15 09:54:21 +0000473
474 // Check whether a feature is supported by the target CPU.
475 static bool IsSupported(CpuFeature f) {
476 if (f == VFP3 && !FLAG_enable_vfp3) return false;
477 return (supported_ & (1u << f)) != 0;
478 }
479
480 // Check whether a feature is currently enabled.
481 static bool IsEnabled(CpuFeature f) {
482 return (enabled_ & (1u << f)) != 0;
483 }
484
485 // Enable a specified feature within a scope.
486 class Scope BASE_EMBEDDED {
487#ifdef DEBUG
488 public:
489 explicit Scope(CpuFeature f) {
490 ASSERT(CpuFeatures::IsSupported(f));
491 ASSERT(!Serializer::enabled() ||
492 (found_by_runtime_probing_ & (1u << f)) == 0);
493 old_enabled_ = CpuFeatures::enabled_;
494 CpuFeatures::enabled_ |= 1u << f;
495 }
496 ~Scope() { CpuFeatures::enabled_ = old_enabled_; }
497 private:
498 unsigned old_enabled_;
499#else
500 public:
501 explicit Scope(CpuFeature f) {}
502#endif
503 };
504
505 private:
506 static unsigned supported_;
507 static unsigned enabled_;
508 static unsigned found_by_runtime_probing_;
509};
510
Steve Blocka7e24c12009-10-30 11:49:00 +0000511
Steve Blocka7e24c12009-10-30 11:49:00 +0000512extern const Instr kMovLrPc;
Steve Block6ded16b2010-05-10 14:33:55 +0100513extern const Instr kLdrPCMask;
Steve Blocka7e24c12009-10-30 11:49:00 +0000514extern const Instr kLdrPCPattern;
Steve Block6ded16b2010-05-10 14:33:55 +0100515extern const Instr kBlxRegMask;
516extern const Instr kBlxRegPattern;
Steve Blocka7e24c12009-10-30 11:49:00 +0000517
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100518extern const Instr kMovMvnMask;
519extern const Instr kMovMvnPattern;
520extern const Instr kMovMvnFlip;
521
522extern const Instr kMovLeaveCCMask;
523extern const Instr kMovLeaveCCPattern;
524extern const Instr kMovwMask;
525extern const Instr kMovwPattern;
526extern const Instr kMovwLeaveCCFlip;
527
528extern const Instr kCmpCmnMask;
529extern const Instr kCmpCmnPattern;
530extern const Instr kCmpCmnFlip;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100531extern const Instr kAddSubFlip;
532extern const Instr kAndBicFlip;
Steve Blocka7e24c12009-10-30 11:49:00 +0000533
Steve Block1e0659c2011-05-24 12:43:12 +0100534
535
Steve Blocka7e24c12009-10-30 11:49:00 +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
556 // Assembler functions are invoked in between GetCode() calls.
557 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
578 // Manages the jump elimination optimization if the second parameter is true.
579 int branch_offset(Label* L, bool jump_elimination_allowed);
580
581 // 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
585 // 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
Steve Blockd0582a62009-12-15 09:54:21 +0000593 // This sets the branch destination (which is in the constant pool on ARM).
594 // This is for calls and branches within generated code.
595 inline static void set_target_at(Address constant_pool_entry, Address target);
596
597 // 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
604 // 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;
608 static const int kExternalTargetSize = kPointerSize;
609
Steve Blocka7e24c12009-10-30 11:49:00 +0000610 // Size of an instruction.
611 static const int kInstrSize = sizeof(Instr);
612
613 // Distance between the instruction referring to the address of the call
Steve Block6ded16b2010-05-10 14:33:55 +0100614 // 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
Steve Blocka7e24c12009-10-30 11:49:00 +0000626 static const int kCallTargetAddressOffset = kInstrSize;
Steve Block6ded16b2010-05-10 14:33:55 +0100627#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000628
629 // Distance between start of patched return sequence and the emitted address
630 // to jump to.
Steve Block6ded16b2010-05-10 14:33:55 +0100631#ifdef USE_BLX
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100632 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100633 // ldr ip, [pc, #0] @ emited address and start
634 // blx ip
635 static const int kPatchReturnSequenceAddressOffset = 0 * kInstrSize;
636#else
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100637 // Patched return sequence is:
Steve Block6ded16b2010-05-10 14:33:55 +0100638 // mov lr, pc @ start of sequence
639 // ldr pc, [pc, #-4] @ emited address
640 static const int kPatchReturnSequenceAddressOffset = kInstrSize;
641#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000642
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100643 // Distance between start of patched debug break slot and the emitted address
644 // to jump to.
645#ifdef USE_BLX
646 // Patched debug break slot code is:
647 // ldr ip, [pc, #0] @ emited address and start
648 // blx ip
649 static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
650#else
651 // Patched debug break slot code is:
652 // mov lr, pc @ start of sequence
653 // ldr pc, [pc, #-4] @ emited address
654 static const int kPatchDebugBreakSlotAddressOffset = kInstrSize;
655#endif
656
Steve Blocka7e24c12009-10-30 11:49:00 +0000657 // Difference between address of current opcode and value read from pc
658 // register.
659 static const int kPcLoadDelta = 8;
660
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100661 static const int kJSReturnSequenceInstructions = 4;
662 static const int kDebugBreakSlotInstructions = 3;
663 static const int kDebugBreakSlotLength =
664 kDebugBreakSlotInstructions * kInstrSize;
Steve Blocka7e24c12009-10-30 11:49:00 +0000665
666 // ---------------------------------------------------------------------------
667 // Code generation
668
669 // Insert the smallest number of nop instructions
670 // possible to align the pc offset to a multiple
671 // of m. m must be a power of 2 (>= 4).
672 void Align(int m);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100673 // Aligns code to something that's optimal for a jump target for the platform.
674 void CodeTargetAlign();
Steve Blocka7e24c12009-10-30 11:49:00 +0000675
676 // Branch instructions
677 void b(int branch_offset, Condition cond = al);
678 void bl(int branch_offset, Condition cond = al);
679 void blx(int branch_offset); // v5 and above
680 void blx(Register target, Condition cond = al); // v5 and above
681 void bx(Register target, Condition cond = al); // v5 and above, plus v4t
682
683 // Convenience branch instructions using labels
684 void b(Label* L, Condition cond = al) {
685 b(branch_offset(L, cond == al), cond);
686 }
687 void b(Condition cond, Label* L) { b(branch_offset(L, cond == al), cond); }
688 void bl(Label* L, Condition cond = al) { bl(branch_offset(L, false), cond); }
689 void bl(Condition cond, Label* L) { bl(branch_offset(L, false), cond); }
690 void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above
691
692 // Data-processing instructions
Andrei Popescu31002712010-02-23 13:46:05 +0000693
Steve Blocka7e24c12009-10-30 11:49:00 +0000694 void and_(Register dst, Register src1, const Operand& src2,
695 SBit s = LeaveCC, Condition cond = al);
696
697 void eor(Register dst, Register src1, const Operand& src2,
698 SBit s = LeaveCC, Condition cond = al);
699
700 void sub(Register dst, Register src1, const Operand& src2,
701 SBit s = LeaveCC, Condition cond = al);
702 void sub(Register dst, Register src1, Register src2,
703 SBit s = LeaveCC, Condition cond = al) {
704 sub(dst, src1, Operand(src2), s, cond);
705 }
706
707 void rsb(Register dst, Register src1, const Operand& src2,
708 SBit s = LeaveCC, Condition cond = al);
709
710 void add(Register dst, Register src1, const Operand& src2,
711 SBit s = LeaveCC, Condition cond = al);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100712 void add(Register dst, Register src1, Register src2,
713 SBit s = LeaveCC, Condition cond = al) {
714 add(dst, src1, Operand(src2), s, cond);
715 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000716
717 void adc(Register dst, Register src1, const Operand& src2,
718 SBit s = LeaveCC, Condition cond = al);
719
720 void sbc(Register dst, Register src1, const Operand& src2,
721 SBit s = LeaveCC, Condition cond = al);
722
723 void rsc(Register dst, Register src1, const Operand& src2,
724 SBit s = LeaveCC, Condition cond = al);
725
726 void tst(Register src1, const Operand& src2, Condition cond = al);
727 void tst(Register src1, Register src2, Condition cond = al) {
728 tst(src1, Operand(src2), cond);
729 }
730
731 void teq(Register src1, const Operand& src2, Condition cond = al);
732
733 void cmp(Register src1, const Operand& src2, Condition cond = al);
734 void cmp(Register src1, Register src2, Condition cond = al) {
735 cmp(src1, Operand(src2), cond);
736 }
Steve Block1e0659c2011-05-24 12:43:12 +0100737 void cmp_raw_immediate(Register src1, int raw_immediate, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000738
739 void cmn(Register src1, const Operand& src2, Condition cond = al);
740
741 void orr(Register dst, Register src1, const Operand& src2,
742 SBit s = LeaveCC, Condition cond = al);
743 void orr(Register dst, Register src1, Register src2,
744 SBit s = LeaveCC, Condition cond = al) {
745 orr(dst, src1, Operand(src2), s, cond);
746 }
747
748 void mov(Register dst, const Operand& src,
749 SBit s = LeaveCC, Condition cond = al);
750 void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
751 mov(dst, Operand(src), s, cond);
752 }
753
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100754 // ARMv7 instructions for loading a 32 bit immediate in two instructions.
755 // This may actually emit a different mov instruction, but on an ARMv7 it
756 // is guaranteed to only emit one instruction.
757 void movw(Register reg, uint32_t immediate, Condition cond = al);
758 // The constant for movt should be in the range 0-0xffff.
759 void movt(Register reg, uint32_t immediate, Condition cond = al);
760
Steve Blocka7e24c12009-10-30 11:49:00 +0000761 void bic(Register dst, Register src1, const Operand& src2,
762 SBit s = LeaveCC, Condition cond = al);
763
764 void mvn(Register dst, const Operand& src,
765 SBit s = LeaveCC, Condition cond = al);
766
767 // Multiply instructions
768
769 void mla(Register dst, Register src1, Register src2, Register srcA,
770 SBit s = LeaveCC, Condition cond = al);
771
772 void mul(Register dst, Register src1, Register src2,
773 SBit s = LeaveCC, Condition cond = al);
774
775 void smlal(Register dstL, Register dstH, Register src1, Register src2,
776 SBit s = LeaveCC, Condition cond = al);
777
778 void smull(Register dstL, Register dstH, Register src1, Register src2,
779 SBit s = LeaveCC, Condition cond = al);
780
781 void umlal(Register dstL, Register dstH, Register src1, Register src2,
782 SBit s = LeaveCC, Condition cond = al);
783
784 void umull(Register dstL, Register dstH, Register src1, Register src2,
785 SBit s = LeaveCC, Condition cond = al);
786
787 // Miscellaneous arithmetic instructions
788
789 void clz(Register dst, Register src, Condition cond = al); // v5 and above
790
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100791 // Saturating instructions. v6 and above.
792
793 // Unsigned saturate.
794 //
795 // Saturate an optionally shifted signed value to an unsigned range.
796 //
797 // usat dst, #satpos, src
798 // usat dst, #satpos, src, lsl #sh
799 // usat dst, #satpos, src, asr #sh
800 //
801 // Register dst will contain:
802 //
803 // 0, if s < 0
804 // (1 << satpos) - 1, if s > ((1 << satpos) - 1)
805 // s, otherwise
806 //
807 // where s is the contents of src after shifting (if used.)
808 void usat(Register dst, int satpos, const Operand& src, Condition cond = al);
809
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100810 // Bitfield manipulation instructions. v7 and above.
811
812 void ubfx(Register dst, Register src, int lsb, int width,
813 Condition cond = al);
814
815 void sbfx(Register dst, Register src, int lsb, int width,
816 Condition cond = al);
817
818 void bfc(Register dst, int lsb, int width, Condition cond = al);
819
820 void bfi(Register dst, Register src, int lsb, int width,
821 Condition cond = al);
822
Steve Blocka7e24c12009-10-30 11:49:00 +0000823 // Status register access instructions
824
825 void mrs(Register dst, SRegister s, Condition cond = al);
826 void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al);
827
828 // Load/Store instructions
829 void ldr(Register dst, const MemOperand& src, Condition cond = al);
830 void str(Register src, const MemOperand& dst, Condition cond = al);
831 void ldrb(Register dst, const MemOperand& src, Condition cond = al);
832 void strb(Register src, const MemOperand& dst, Condition cond = al);
833 void ldrh(Register dst, const MemOperand& src, Condition cond = al);
834 void strh(Register src, const MemOperand& dst, Condition cond = al);
835 void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
836 void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
Leon Clarkef7060e22010-06-03 12:02:55 +0100837 void ldrd(Register dst1,
838 Register dst2,
839 const MemOperand& src, Condition cond = al);
840 void strd(Register src1,
841 Register src2,
842 const MemOperand& dst, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000843
844 // Load/Store multiple instructions
845 void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
846 void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
847
Steve Blocka7e24c12009-10-30 11:49:00 +0000848 // Exception-generating instructions and debugging support
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800849 void stop(const char* msg,
850 Condition cond = al,
851 int32_t code = kDefaultStopCode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000852
853 void bkpt(uint32_t imm16); // v5 and above
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800854 void svc(uint32_t imm24, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000855
856 // Coprocessor instructions
857
858 void cdp(Coprocessor coproc, int opcode_1,
859 CRegister crd, CRegister crn, CRegister crm,
860 int opcode_2, Condition cond = al);
861
862 void cdp2(Coprocessor coproc, int opcode_1,
863 CRegister crd, CRegister crn, CRegister crm,
864 int opcode_2); // v5 and above
865
866 void mcr(Coprocessor coproc, int opcode_1,
867 Register rd, CRegister crn, CRegister crm,
868 int opcode_2 = 0, Condition cond = al);
869
870 void mcr2(Coprocessor coproc, int opcode_1,
871 Register rd, CRegister crn, CRegister crm,
872 int opcode_2 = 0); // v5 and above
873
874 void mrc(Coprocessor coproc, int opcode_1,
875 Register rd, CRegister crn, CRegister crm,
876 int opcode_2 = 0, Condition cond = al);
877
878 void mrc2(Coprocessor coproc, int opcode_1,
879 Register rd, CRegister crn, CRegister crm,
880 int opcode_2 = 0); // v5 and above
881
882 void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src,
883 LFlag l = Short, Condition cond = al);
884 void ldc(Coprocessor coproc, CRegister crd, Register base, int option,
885 LFlag l = Short, Condition cond = al);
886
887 void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
888 LFlag l = Short); // v5 and above
889 void ldc2(Coprocessor coproc, CRegister crd, Register base, int option,
890 LFlag l = Short); // v5 and above
891
892 void stc(Coprocessor coproc, CRegister crd, const MemOperand& dst,
893 LFlag l = Short, Condition cond = al);
894 void stc(Coprocessor coproc, CRegister crd, Register base, int option,
895 LFlag l = Short, Condition cond = al);
896
897 void stc2(Coprocessor coproc, CRegister crd, const MemOperand& dst,
898 LFlag l = Short); // v5 and above
899 void stc2(Coprocessor coproc, CRegister crd, Register base, int option,
900 LFlag l = Short); // v5 and above
901
Steve Blockd0582a62009-12-15 09:54:21 +0000902 // Support for VFP.
903 // All these APIs support S0 to S31 and D0 to D15.
904 // Currently these APIs do not support extended D registers, i.e, D16 to D31.
905 // However, some simple modifications can allow
906 // these APIs to support D16 to D31.
907
Leon Clarked91b9f72010-01-27 17:25:45 +0000908 void vldr(const DwVfpRegister dst,
909 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100910 int offset,
911 const Condition cond = al);
912 void vldr(const DwVfpRegister dst,
913 const MemOperand& src,
Leon Clarked91b9f72010-01-27 17:25:45 +0000914 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +0100915
916 void vldr(const SwVfpRegister dst,
917 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100918 int offset,
919 const Condition cond = al);
920 void vldr(const SwVfpRegister dst,
921 const MemOperand& src,
Steve Block6ded16b2010-05-10 14:33:55 +0100922 const Condition cond = al);
923
Leon Clarked91b9f72010-01-27 17:25:45 +0000924 void vstr(const DwVfpRegister src,
925 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100926 int offset,
927 const Condition cond = al);
928 void vstr(const DwVfpRegister src,
929 const MemOperand& dst,
Leon Clarked91b9f72010-01-27 17:25:45 +0000930 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +0100931
Iain Merrick75681382010-08-19 15:07:18 +0100932 void vstr(const SwVfpRegister src,
933 const Register base,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100934 int offset,
935 const Condition cond = al);
936 void vstr(const SwVfpRegister src,
937 const MemOperand& dst,
Iain Merrick75681382010-08-19 15:07:18 +0100938 const Condition cond = al);
939
Steve Block8defd9f2010-07-08 12:39:36 +0100940 void vmov(const DwVfpRegister dst,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100941 double imm,
942 const Condition cond = al);
943 void vmov(const SwVfpRegister dst,
944 const SwVfpRegister src,
945 const Condition cond = al);
946 void vmov(const DwVfpRegister dst,
Steve Block8defd9f2010-07-08 12:39:36 +0100947 const DwVfpRegister src,
948 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +0000949 void vmov(const DwVfpRegister dst,
950 const Register src1,
Steve Blockd0582a62009-12-15 09:54:21 +0000951 const Register src2,
Leon Clarkee46be812010-01-19 14:06:41 +0000952 const Condition cond = al);
953 void vmov(const Register dst1,
954 const Register dst2,
955 const DwVfpRegister src,
956 const Condition cond = al);
957 void vmov(const SwVfpRegister dst,
958 const Register src,
959 const Condition cond = al);
960 void vmov(const Register dst,
961 const SwVfpRegister src,
962 const Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +0100963 void vcvt_f64_s32(const DwVfpRegister dst,
964 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +0100965 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +0100966 const Condition cond = al);
967 void vcvt_f32_s32(const SwVfpRegister dst,
968 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +0100969 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +0100970 const Condition cond = al);
971 void vcvt_f64_u32(const DwVfpRegister dst,
972 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +0100973 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +0100974 const Condition cond = al);
975 void vcvt_s32_f64(const SwVfpRegister dst,
976 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +0100977 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +0100978 const Condition cond = al);
979 void vcvt_u32_f64(const SwVfpRegister dst,
980 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +0100981 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +0100982 const Condition cond = al);
983 void vcvt_f64_f32(const DwVfpRegister dst,
984 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +0100985 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +0100986 const Condition cond = al);
987 void vcvt_f32_f64(const SwVfpRegister dst,
988 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +0100989 VFPConversionMode mode = kDefaultRoundToZero,
Steve Block6ded16b2010-05-10 14:33:55 +0100990 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +0000991
Steve Block1e0659c2011-05-24 12:43:12 +0100992 void vabs(const DwVfpRegister dst,
993 const DwVfpRegister src,
994 const Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +0000995 void vadd(const DwVfpRegister dst,
996 const DwVfpRegister src1,
997 const DwVfpRegister src2,
998 const Condition cond = al);
999 void vsub(const DwVfpRegister dst,
1000 const DwVfpRegister src1,
1001 const DwVfpRegister src2,
1002 const Condition cond = al);
1003 void vmul(const DwVfpRegister dst,
1004 const DwVfpRegister src1,
1005 const DwVfpRegister src2,
1006 const Condition cond = al);
1007 void vdiv(const DwVfpRegister dst,
1008 const DwVfpRegister src1,
1009 const DwVfpRegister src2,
1010 const Condition cond = al);
1011 void vcmp(const DwVfpRegister src1,
1012 const DwVfpRegister src2,
Steve Blockd0582a62009-12-15 09:54:21 +00001013 const Condition cond = al);
Iain Merrick75681382010-08-19 15:07:18 +01001014 void vcmp(const DwVfpRegister src1,
1015 const double src2,
Iain Merrick75681382010-08-19 15:07:18 +01001016 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001017 void vmrs(const Register dst,
1018 const Condition cond = al);
Russell Brenner90bac252010-11-18 13:33:46 -08001019 void vmsr(const Register dst,
1020 const Condition cond = al);
Steve Block8defd9f2010-07-08 12:39:36 +01001021 void vsqrt(const DwVfpRegister dst,
1022 const DwVfpRegister src,
1023 const Condition cond = al);
Steve Blockd0582a62009-12-15 09:54:21 +00001024
Steve Blocka7e24c12009-10-30 11:49:00 +00001025 // Pseudo instructions
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001026
1027 // Different nop operations are used by the code generator to detect certain
1028 // states of the generated code.
1029 enum NopMarkerTypes {
1030 NON_MARKING_NOP = 0,
1031 DEBUG_BREAK_NOP,
1032 // IC markers.
1033 PROPERTY_ACCESS_INLINED,
1034 PROPERTY_ACCESS_INLINED_CONTEXT,
1035 PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE,
1036 // Helper values.
1037 LAST_CODE_MARKER,
1038 FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED
1039 };
1040
1041 void nop(int type = 0); // 0 is the default non-marking type.
Steve Blocka7e24c12009-10-30 11:49:00 +00001042
1043 void push(Register src, Condition cond = al) {
1044 str(src, MemOperand(sp, 4, NegPreIndex), cond);
1045 }
1046
1047 void pop(Register dst, Condition cond = al) {
1048 ldr(dst, MemOperand(sp, 4, PostIndex), cond);
1049 }
1050
1051 void pop() {
1052 add(sp, sp, Operand(kPointerSize));
1053 }
1054
Steve Blocka7e24c12009-10-30 11:49:00 +00001055 // Jump unconditionally to given label.
1056 void jmp(Label* L) { b(L, al); }
1057
1058 // Check the code size generated from label to here.
1059 int InstructionsGeneratedSince(Label* l) {
1060 return (pc_offset() - l->pos()) / kInstrSize;
1061 }
1062
Steve Blockd0582a62009-12-15 09:54:21 +00001063 // Check whether an immediate fits an addressing mode 1 instruction.
1064 bool ImmediateFitsAddrMode1Instruction(int32_t imm32);
1065
Steve Block6ded16b2010-05-10 14:33:55 +01001066 // Class for scoping postponing the constant pool generation.
1067 class BlockConstPoolScope {
1068 public:
1069 explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) {
1070 assem_->StartBlockConstPool();
1071 }
1072 ~BlockConstPoolScope() {
1073 assem_->EndBlockConstPool();
1074 }
1075
1076 private:
1077 Assembler* assem_;
1078
1079 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstPoolScope);
1080 };
1081
Steve Blockd0582a62009-12-15 09:54:21 +00001082 // Postpone the generation of the constant pool for the specified number of
1083 // instructions.
1084 void BlockConstPoolFor(int instructions);
1085
Steve Blocka7e24c12009-10-30 11:49:00 +00001086 // Debugging
1087
1088 // Mark address of the ExitJSFrame code.
1089 void RecordJSReturn();
1090
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001091 // Mark address of a debug break slot.
1092 void RecordDebugBreakSlot();
1093
Steve Blocka7e24c12009-10-30 11:49:00 +00001094 // Record a comment relocation entry that can be used by a disassembler.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001095 // Use --code-comments to enable.
Steve Blocka7e24c12009-10-30 11:49:00 +00001096 void RecordComment(const char* msg);
1097
Ben Murdochb8e0da22011-05-16 14:20:40 +01001098 // Writes a single byte or word of data in the code stream. Used
1099 // for inline tables, e.g., jump-tables. The constant pool should be
1100 // emitted before any use of db and dd to ensure that constant pools
1101 // are not emitted as part of the tables generated.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001102 void db(uint8_t data);
1103 void dd(uint32_t data);
1104
Steve Blocka7e24c12009-10-30 11:49:00 +00001105 int pc_offset() const { return pc_ - buffer_; }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001106
1107 PositionsRecorder* positions_recorder() { return &positions_recorder_; }
Steve Block6ded16b2010-05-10 14:33:55 +01001108
Leon Clarkef7060e22010-06-03 12:02:55 +01001109 bool can_peephole_optimize(int instructions) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001110 if (!allow_peephole_optimization_) return false;
Leon Clarkef7060e22010-06-03 12:02:55 +01001111 if (last_bound_pos_ > pc_offset() - instructions * kInstrSize) return false;
1112 return reloc_info_writer.last_pc() <= pc_ - instructions * kInstrSize;
1113 }
1114
Steve Block6ded16b2010-05-10 14:33:55 +01001115 // Read/patch instructions
1116 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
1117 static void instr_at_put(byte* pc, Instr instr) {
1118 *reinterpret_cast<Instr*>(pc) = instr;
1119 }
Steve Block1e0659c2011-05-24 12:43:12 +01001120 static Condition GetCondition(Instr instr);
Steve Block6ded16b2010-05-10 14:33:55 +01001121 static bool IsBranch(Instr instr);
1122 static int GetBranchOffset(Instr instr);
1123 static bool IsLdrRegisterImmediate(Instr instr);
1124 static int GetLdrRegisterImmediateOffset(Instr instr);
1125 static Instr SetLdrRegisterImmediateOffset(Instr instr, int offset);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001126 static bool IsStrRegisterImmediate(Instr instr);
1127 static Instr SetStrRegisterImmediateOffset(Instr instr, int offset);
1128 static bool IsAddRegisterImmediate(Instr instr);
1129 static Instr SetAddRegisterImmediateOffset(Instr instr, int offset);
Leon Clarkef7060e22010-06-03 12:02:55 +01001130 static Register GetRd(Instr instr);
Steve Block1e0659c2011-05-24 12:43:12 +01001131 static Register GetRn(Instr instr);
1132 static Register GetRm(Instr instr);
Leon Clarkef7060e22010-06-03 12:02:55 +01001133 static bool IsPush(Instr instr);
1134 static bool IsPop(Instr instr);
1135 static bool IsStrRegFpOffset(Instr instr);
1136 static bool IsLdrRegFpOffset(Instr instr);
1137 static bool IsStrRegFpNegOffset(Instr instr);
1138 static bool IsLdrRegFpNegOffset(Instr instr);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001139 static bool IsLdrPcImmediateOffset(Instr instr);
Steve Block1e0659c2011-05-24 12:43:12 +01001140 static bool IsTstImmediate(Instr instr);
1141 static bool IsCmpRegister(Instr instr);
1142 static bool IsCmpImmediate(Instr instr);
1143 static Register GetCmpImmediateRegister(Instr instr);
1144 static int GetCmpImmediateRawImmediate(Instr instr);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001145 static bool IsNop(Instr instr, int type = NON_MARKING_NOP);
Steve Block6ded16b2010-05-10 14:33:55 +01001146
Ben Murdochb0fe1622011-05-05 13:52:32 +01001147 // Check if is time to emit a constant pool for pending reloc info entries
1148 void CheckConstPool(bool force_emit, bool require_jump);
Steve Blocka7e24c12009-10-30 11:49:00 +00001149
1150 protected:
1151 int buffer_space() const { return reloc_info_writer.pos() - pc_; }
1152
1153 // Read/patch instructions
Steve Blocka7e24c12009-10-30 11:49:00 +00001154 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
1155 void instr_at_put(int pos, Instr instr) {
1156 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
1157 }
1158
1159 // Decode branch instruction at pos and return branch target pos
1160 int target_at(int pos);
1161
1162 // Patch branch instruction at pos to branch to given branch target pos
1163 void target_at_put(int pos, int target_pos);
1164
Steve Blocka7e24c12009-10-30 11:49:00 +00001165 // Block the emission of the constant pool before pc_offset
1166 void BlockConstPoolBefore(int pc_offset) {
1167 if (no_const_pool_before_ < pc_offset) no_const_pool_before_ = pc_offset;
1168 }
1169
Steve Block6ded16b2010-05-10 14:33:55 +01001170 void StartBlockConstPool() {
1171 const_pool_blocked_nesting_++;
1172 }
1173 void EndBlockConstPool() {
1174 const_pool_blocked_nesting_--;
1175 }
Steve Block8defd9f2010-07-08 12:39:36 +01001176 bool is_const_pool_blocked() const { return const_pool_blocked_nesting_ > 0; }
Steve Block6ded16b2010-05-10 14:33:55 +01001177
Steve Blocka7e24c12009-10-30 11:49:00 +00001178 private:
1179 // Code buffer:
1180 // The buffer into which code and relocation info are generated.
1181 byte* buffer_;
1182 int buffer_size_;
1183 // True if the assembler owns the buffer, false if buffer is external.
1184 bool own_buffer_;
1185
1186 // Buffer size and constant pool distance are checked together at regular
1187 // intervals of kBufferCheckInterval emitted bytes
1188 static const int kBufferCheckInterval = 1*KB/2;
1189 int next_buffer_check_; // pc offset of next buffer check
1190
1191 // Code generation
1192 // The relocation writer's position is at least kGap bytes below the end of
1193 // the generated instructions. This is so that multi-instruction sequences do
1194 // not have to check for overflow. The same is true for writes of large
1195 // relocation info entries.
1196 static const int kGap = 32;
1197 byte* pc_; // the program counter; moves forward
1198
1199 // Constant pool generation
1200 // Pools are emitted in the instruction stream, preferably after unconditional
1201 // jumps or after returns from functions (in dead code locations).
1202 // If a long code sequence does not contain unconditional jumps, it is
1203 // necessary to emit the constant pool before the pool gets too far from the
1204 // location it is accessed from. In this case, we emit a jump over the emitted
1205 // constant pool.
1206 // Constants in the pool may be addresses of functions that gets relocated;
1207 // if so, a relocation info entry is associated to the constant pool entry.
1208
1209 // Repeated checking whether the constant pool should be emitted is rather
1210 // expensive. By default we only check again once a number of instructions
1211 // has been generated. That also means that the sizing of the buffers is not
1212 // an exact science, and that we rely on some slop to not overrun buffers.
1213 static const int kCheckConstIntervalInst = 32;
1214 static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize;
1215
1216
1217 // Pools are emitted after function return and in dead code at (more or less)
1218 // regular intervals of kDistBetweenPools bytes
1219 static const int kDistBetweenPools = 1*KB;
1220
1221 // Constants in pools are accessed via pc relative addressing, which can
1222 // reach +/-4KB thereby defining a maximum distance between the instruction
1223 // and the accessed constant. We satisfy this constraint by limiting the
1224 // distance between pools.
1225 static const int kMaxDistBetweenPools = 4*KB - 2*kBufferCheckInterval;
1226
Steve Block6ded16b2010-05-10 14:33:55 +01001227 // Emission of the constant pool may be blocked in some code sequences.
1228 int const_pool_blocked_nesting_; // Block emission if this is not zero.
1229 int no_const_pool_before_; // Block emission before this pc offset.
Steve Blocka7e24c12009-10-30 11:49:00 +00001230
1231 // Keep track of the last emitted pool to guarantee a maximal distance
1232 int last_const_pool_end_; // pc offset following the last constant pool
1233
1234 // Relocation info generation
1235 // Each relocation is encoded as a variable size value
1236 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1237 RelocInfoWriter reloc_info_writer;
1238 // Relocation info records are also used during code generation as temporary
1239 // containers for constants and code target addresses until they are emitted
1240 // to the constant pool. These pending relocation info records are temporarily
1241 // stored in a separate buffer until a constant pool is emitted.
1242 // If every instruction in a long sequence is accessing the pool, we need one
1243 // pending relocation entry per instruction.
1244 static const int kMaxNumPRInfo = kMaxDistBetweenPools/kInstrSize;
1245 RelocInfo prinfo_[kMaxNumPRInfo]; // the buffer of pending relocation info
1246 int num_prinfo_; // number of pending reloc info entries in the buffer
1247
1248 // The bound position, before this we cannot do instruction elimination.
1249 int last_bound_pos_;
1250
Steve Blocka7e24c12009-10-30 11:49:00 +00001251 // Code emission
1252 inline void CheckBuffer();
1253 void GrowBuffer();
1254 inline void emit(Instr x);
1255
1256 // Instruction generation
1257 void addrmod1(Instr instr, Register rn, Register rd, const Operand& x);
1258 void addrmod2(Instr instr, Register rd, const MemOperand& x);
1259 void addrmod3(Instr instr, Register rd, const MemOperand& x);
1260 void addrmod4(Instr instr, Register rn, RegList rl);
1261 void addrmod5(Instr instr, CRegister crd, const MemOperand& x);
1262
1263 // Labels
1264 void print(Label* L);
1265 void bind_to(Label* L, int pos);
1266 void link_to(Label* L, Label* appendix);
1267 void next(Label* L);
1268
1269 // Record reloc info for current pc_
1270 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
1271
1272 friend class RegExpMacroAssemblerARM;
1273 friend class RelocInfo;
1274 friend class CodePatcher;
Steve Block6ded16b2010-05-10 14:33:55 +01001275 friend class BlockConstPoolScope;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001276
1277 PositionsRecorder positions_recorder_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001278 bool allow_peephole_optimization_;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001279 friend class PositionsRecorder;
1280 friend class EnsureSpace;
Steve Blocka7e24c12009-10-30 11:49:00 +00001281};
1282
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001283
1284class EnsureSpace BASE_EMBEDDED {
1285 public:
1286 explicit EnsureSpace(Assembler* assembler) {
1287 assembler->CheckBuffer();
1288 }
1289};
1290
1291
Steve Blocka7e24c12009-10-30 11:49:00 +00001292} } // namespace v8::internal
1293
1294#endif // V8_ARM_ASSEMBLER_ARM_H_