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