]> git.saurik.com Git - apple/javascriptcore.git/blob - assembler/ARMv7Assembler.h
ffc30900ce3704f5ae1e31bc20a7e783a5dd8ba9
[apple/javascriptcore.git] / assembler / ARMv7Assembler.h
1 /*
2 * Copyright (C) 2009, 2010, 2012, 2013, 2014 Apple Inc. All rights reserved.
3 * Copyright (C) 2010 University of Szeged
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #ifndef ARMAssembler_h
28 #define ARMAssembler_h
29
30 #if ENABLE(ASSEMBLER) && CPU(ARM_THUMB2)
31
32 #include "AssemblerBuffer.h"
33 #include <limits.h>
34 #include <wtf/Assertions.h>
35 #include <wtf/Vector.h>
36 #include <stdint.h>
37
38 namespace JSC {
39
40 namespace ARMRegisters {
41 typedef enum {
42 r0,
43 r1,
44 r2,
45 r3,
46 r4,
47 r5,
48 r6,
49 r7, fp = r7, // frame pointer
50 r8,
51 r9, sb = r9, // static base
52 r10, sl = r10, // stack limit
53 r11,
54 r12, ip = r12,
55 r13, sp = r13,
56 r14, lr = r14,
57 r15, pc = r15,
58 } RegisterID;
59
60 typedef enum {
61 s0,
62 s1,
63 s2,
64 s3,
65 s4,
66 s5,
67 s6,
68 s7,
69 s8,
70 s9,
71 s10,
72 s11,
73 s12,
74 s13,
75 s14,
76 s15,
77 s16,
78 s17,
79 s18,
80 s19,
81 s20,
82 s21,
83 s22,
84 s23,
85 s24,
86 s25,
87 s26,
88 s27,
89 s28,
90 s29,
91 s30,
92 s31,
93 } FPSingleRegisterID;
94
95 typedef enum {
96 d0,
97 d1,
98 d2,
99 d3,
100 d4,
101 d5,
102 d6,
103 d7,
104 d8,
105 d9,
106 d10,
107 d11,
108 d12,
109 d13,
110 d14,
111 d15,
112 d16,
113 d17,
114 d18,
115 d19,
116 d20,
117 d21,
118 d22,
119 d23,
120 d24,
121 d25,
122 d26,
123 d27,
124 d28,
125 d29,
126 d30,
127 d31,
128 } FPDoubleRegisterID;
129
130 typedef enum {
131 q0,
132 q1,
133 q2,
134 q3,
135 q4,
136 q5,
137 q6,
138 q7,
139 q8,
140 q9,
141 q10,
142 q11,
143 q12,
144 q13,
145 q14,
146 q15,
147 q16,
148 q17,
149 q18,
150 q19,
151 q20,
152 q21,
153 q22,
154 q23,
155 q24,
156 q25,
157 q26,
158 q27,
159 q28,
160 q29,
161 q30,
162 q31,
163 } FPQuadRegisterID;
164
165 inline FPSingleRegisterID asSingle(FPDoubleRegisterID reg)
166 {
167 ASSERT(reg < d16);
168 return (FPSingleRegisterID)(reg << 1);
169 }
170
171 inline FPDoubleRegisterID asDouble(FPSingleRegisterID reg)
172 {
173 ASSERT(!(reg & 1));
174 return (FPDoubleRegisterID)(reg >> 1);
175 }
176
177 #if USE(MASM_PROBE)
178 #define FOR_EACH_CPU_REGISTER(V) \
179 FOR_EACH_CPU_GPREGISTER(V) \
180 FOR_EACH_CPU_SPECIAL_REGISTER(V) \
181 FOR_EACH_CPU_FPREGISTER(V)
182
183 #define FOR_EACH_CPU_GPREGISTER(V) \
184 V(void*, r0) \
185 V(void*, r1) \
186 V(void*, r2) \
187 V(void*, r3) \
188 V(void*, r4) \
189 V(void*, r5) \
190 V(void*, r6) \
191 V(void*, r7) \
192 V(void*, r8) \
193 V(void*, r9) \
194 V(void*, r10) \
195 V(void*, r11) \
196 V(void*, ip) \
197 V(void*, sp) \
198 V(void*, lr) \
199 V(void*, pc)
200
201 #define FOR_EACH_CPU_SPECIAL_REGISTER(V) \
202 V(void*, apsr) \
203 V(void*, fpscr) \
204
205 #define FOR_EACH_CPU_FPREGISTER(V) \
206 V(double, d0) \
207 V(double, d1) \
208 V(double, d2) \
209 V(double, d3) \
210 V(double, d4) \
211 V(double, d5) \
212 V(double, d6) \
213 V(double, d7) \
214 V(double, d8) \
215 V(double, d9) \
216 V(double, d10) \
217 V(double, d11) \
218 V(double, d12) \
219 V(double, d13) \
220 V(double, d14) \
221 V(double, d15) \
222 FOR_EACH_CPU_FPREGISTER_EXTENSION(V)
223
224 #if CPU(APPLE_ARMV7S)
225 #define FOR_EACH_CPU_FPREGISTER_EXTENSION(V) \
226 V(double, d16) \
227 V(double, d17) \
228 V(double, d18) \
229 V(double, d19) \
230 V(double, d20) \
231 V(double, d21) \
232 V(double, d22) \
233 V(double, d23) \
234 V(double, d24) \
235 V(double, d25) \
236 V(double, d26) \
237 V(double, d27) \
238 V(double, d28) \
239 V(double, d29) \
240 V(double, d30) \
241 V(double, d31)
242 #else
243 #define FOR_EACH_CPU_FPREGISTER_EXTENSION(V) // Nothing to add.
244 #endif // CPU(APPLE_ARMV7S)
245
246 #endif // USE(MASM_PROBE)
247 }
248
249 class ARMv7Assembler;
250 class ARMThumbImmediate {
251 friend class ARMv7Assembler;
252
253 typedef uint8_t ThumbImmediateType;
254 static const ThumbImmediateType TypeInvalid = 0;
255 static const ThumbImmediateType TypeEncoded = 1;
256 static const ThumbImmediateType TypeUInt16 = 2;
257
258 typedef union {
259 int16_t asInt;
260 struct {
261 unsigned imm8 : 8;
262 unsigned imm3 : 3;
263 unsigned i : 1;
264 unsigned imm4 : 4;
265 };
266 // If this is an encoded immediate, then it may describe a shift, or a pattern.
267 struct {
268 unsigned shiftValue7 : 7;
269 unsigned shiftAmount : 5;
270 };
271 struct {
272 unsigned immediate : 8;
273 unsigned pattern : 4;
274 };
275 } ThumbImmediateValue;
276
277 // byte0 contains least significant bit; not using an array to make client code endian agnostic.
278 typedef union {
279 int32_t asInt;
280 struct {
281 uint8_t byte0;
282 uint8_t byte1;
283 uint8_t byte2;
284 uint8_t byte3;
285 };
286 } PatternBytes;
287
288 ALWAYS_INLINE static void countLeadingZerosPartial(uint32_t& value, int32_t& zeros, const int N)
289 {
290 if (value & ~((1 << N) - 1)) /* check for any of the top N bits (of 2N bits) are set */
291 value >>= N; /* if any were set, lose the bottom N */
292 else /* if none of the top N bits are set, */
293 zeros += N; /* then we have identified N leading zeros */
294 }
295
296 static int32_t countLeadingZeros(uint32_t value)
297 {
298 if (!value)
299 return 32;
300
301 int32_t zeros = 0;
302 countLeadingZerosPartial(value, zeros, 16);
303 countLeadingZerosPartial(value, zeros, 8);
304 countLeadingZerosPartial(value, zeros, 4);
305 countLeadingZerosPartial(value, zeros, 2);
306 countLeadingZerosPartial(value, zeros, 1);
307 return zeros;
308 }
309
310 ARMThumbImmediate()
311 : m_type(TypeInvalid)
312 {
313 m_value.asInt = 0;
314 }
315
316 ARMThumbImmediate(ThumbImmediateType type, ThumbImmediateValue value)
317 : m_type(type)
318 , m_value(value)
319 {
320 }
321
322 ARMThumbImmediate(ThumbImmediateType type, uint16_t value)
323 : m_type(TypeUInt16)
324 {
325 // Make sure this constructor is only reached with type TypeUInt16;
326 // this extra parameter makes the code a little clearer by making it
327 // explicit at call sites which type is being constructed
328 ASSERT_UNUSED(type, type == TypeUInt16);
329
330 m_value.asInt = value;
331 }
332
333 public:
334 static ARMThumbImmediate makeEncodedImm(uint32_t value)
335 {
336 ThumbImmediateValue encoding;
337 encoding.asInt = 0;
338
339 // okay, these are easy.
340 if (value < 256) {
341 encoding.immediate = value;
342 encoding.pattern = 0;
343 return ARMThumbImmediate(TypeEncoded, encoding);
344 }
345
346 int32_t leadingZeros = countLeadingZeros(value);
347 // if there were 24 or more leading zeros, then we'd have hit the (value < 256) case.
348 ASSERT(leadingZeros < 24);
349
350 // Given a number with bit fields Z:B:C, where count(Z)+count(B)+count(C) == 32,
351 // Z are the bits known zero, B is the 8-bit immediate, C are the bits to check for
352 // zero. count(B) == 8, so the count of bits to be checked is 24 - count(Z).
353 int32_t rightShiftAmount = 24 - leadingZeros;
354 if (value == ((value >> rightShiftAmount) << rightShiftAmount)) {
355 // Shift the value down to the low byte position. The assign to
356 // shiftValue7 drops the implicit top bit.
357 encoding.shiftValue7 = value >> rightShiftAmount;
358 // The endoded shift amount is the magnitude of a right rotate.
359 encoding.shiftAmount = 8 + leadingZeros;
360 return ARMThumbImmediate(TypeEncoded, encoding);
361 }
362
363 PatternBytes bytes;
364 bytes.asInt = value;
365
366 if ((bytes.byte0 == bytes.byte1) && (bytes.byte0 == bytes.byte2) && (bytes.byte0 == bytes.byte3)) {
367 encoding.immediate = bytes.byte0;
368 encoding.pattern = 3;
369 return ARMThumbImmediate(TypeEncoded, encoding);
370 }
371
372 if ((bytes.byte0 == bytes.byte2) && !(bytes.byte1 | bytes.byte3)) {
373 encoding.immediate = bytes.byte0;
374 encoding.pattern = 1;
375 return ARMThumbImmediate(TypeEncoded, encoding);
376 }
377
378 if ((bytes.byte1 == bytes.byte3) && !(bytes.byte0 | bytes.byte2)) {
379 encoding.immediate = bytes.byte1;
380 encoding.pattern = 2;
381 return ARMThumbImmediate(TypeEncoded, encoding);
382 }
383
384 return ARMThumbImmediate();
385 }
386
387 static ARMThumbImmediate makeUInt12(int32_t value)
388 {
389 return (!(value & 0xfffff000))
390 ? ARMThumbImmediate(TypeUInt16, (uint16_t)value)
391 : ARMThumbImmediate();
392 }
393
394 static ARMThumbImmediate makeUInt12OrEncodedImm(int32_t value)
395 {
396 // If this is not a 12-bit unsigned it, try making an encoded immediate.
397 return (!(value & 0xfffff000))
398 ? ARMThumbImmediate(TypeUInt16, (uint16_t)value)
399 : makeEncodedImm(value);
400 }
401
402 // The 'make' methods, above, return a !isValid() value if the argument
403 // cannot be represented as the requested type. This methods is called
404 // 'get' since the argument can always be represented.
405 static ARMThumbImmediate makeUInt16(uint16_t value)
406 {
407 return ARMThumbImmediate(TypeUInt16, value);
408 }
409
410 bool isValid()
411 {
412 return m_type != TypeInvalid;
413 }
414
415 uint16_t asUInt16() const { return m_value.asInt; }
416
417 // These methods rely on the format of encoded byte values.
418 bool isUInt3() { return !(m_value.asInt & 0xfff8); }
419 bool isUInt4() { return !(m_value.asInt & 0xfff0); }
420 bool isUInt5() { return !(m_value.asInt & 0xffe0); }
421 bool isUInt6() { return !(m_value.asInt & 0xffc0); }
422 bool isUInt7() { return !(m_value.asInt & 0xff80); }
423 bool isUInt8() { return !(m_value.asInt & 0xff00); }
424 bool isUInt9() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xfe00); }
425 bool isUInt10() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xfc00); }
426 bool isUInt12() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xf000); }
427 bool isUInt16() { return m_type == TypeUInt16; }
428 uint8_t getUInt3() { ASSERT(isUInt3()); return m_value.asInt; }
429 uint8_t getUInt4() { ASSERT(isUInt4()); return m_value.asInt; }
430 uint8_t getUInt5() { ASSERT(isUInt5()); return m_value.asInt; }
431 uint8_t getUInt6() { ASSERT(isUInt6()); return m_value.asInt; }
432 uint8_t getUInt7() { ASSERT(isUInt7()); return m_value.asInt; }
433 uint8_t getUInt8() { ASSERT(isUInt8()); return m_value.asInt; }
434 uint16_t getUInt9() { ASSERT(isUInt9()); return m_value.asInt; }
435 uint16_t getUInt10() { ASSERT(isUInt10()); return m_value.asInt; }
436 uint16_t getUInt12() { ASSERT(isUInt12()); return m_value.asInt; }
437 uint16_t getUInt16() { ASSERT(isUInt16()); return m_value.asInt; }
438
439 bool isEncodedImm() { return m_type == TypeEncoded; }
440
441 private:
442 ThumbImmediateType m_type;
443 ThumbImmediateValue m_value;
444 };
445
446 typedef enum {
447 SRType_LSL,
448 SRType_LSR,
449 SRType_ASR,
450 SRType_ROR,
451
452 SRType_RRX = SRType_ROR
453 } ARMShiftType;
454
455 class ShiftTypeAndAmount {
456 friend class ARMv7Assembler;
457
458 public:
459 ShiftTypeAndAmount()
460 {
461 m_u.type = (ARMShiftType)0;
462 m_u.amount = 0;
463 }
464
465 ShiftTypeAndAmount(ARMShiftType type, unsigned amount)
466 {
467 m_u.type = type;
468 m_u.amount = amount & 31;
469 }
470
471 unsigned lo4() { return m_u.lo4; }
472 unsigned hi4() { return m_u.hi4; }
473
474 private:
475 union {
476 struct {
477 unsigned lo4 : 4;
478 unsigned hi4 : 4;
479 };
480 struct {
481 unsigned type : 2;
482 unsigned amount : 6;
483 };
484 } m_u;
485 };
486
487 class ARMv7Assembler {
488 public:
489 typedef ARMRegisters::RegisterID RegisterID;
490 typedef ARMRegisters::FPSingleRegisterID FPSingleRegisterID;
491 typedef ARMRegisters::FPDoubleRegisterID FPDoubleRegisterID;
492 typedef ARMRegisters::FPQuadRegisterID FPQuadRegisterID;
493 typedef FPDoubleRegisterID FPRegisterID;
494
495 static RegisterID firstRegister() { return ARMRegisters::r0; }
496 static RegisterID lastRegister() { return ARMRegisters::r13; }
497
498 static FPRegisterID firstFPRegister() { return ARMRegisters::d0; }
499 static FPRegisterID lastFPRegister() { return ARMRegisters::d31; }
500
501 // (HS, LO, HI, LS) -> (AE, B, A, BE)
502 // (VS, VC) -> (O, NO)
503 typedef enum {
504 ConditionEQ, // Zero / Equal.
505 ConditionNE, // Non-zero / Not equal.
506 ConditionHS, ConditionCS = ConditionHS, // Unsigned higher or same.
507 ConditionLO, ConditionCC = ConditionLO, // Unsigned lower.
508 ConditionMI, // Negative.
509 ConditionPL, // Positive or zero.
510 ConditionVS, // Overflowed.
511 ConditionVC, // Not overflowed.
512 ConditionHI, // Unsigned higher.
513 ConditionLS, // Unsigned lower or same.
514 ConditionGE, // Signed greater than or equal.
515 ConditionLT, // Signed less than.
516 ConditionGT, // Signed greater than.
517 ConditionLE, // Signed less than or equal.
518 ConditionAL, // Unconditional / Always execute.
519 ConditionInvalid
520 } Condition;
521
522 #define JUMP_ENUM_WITH_SIZE(index, value) (((value) << 3) | (index))
523 #define JUMP_ENUM_SIZE(jump) ((jump) >> 3)
524 enum JumpType { JumpFixed = JUMP_ENUM_WITH_SIZE(0, 0),
525 JumpNoCondition = JUMP_ENUM_WITH_SIZE(1, 5 * sizeof(uint16_t)),
526 JumpCondition = JUMP_ENUM_WITH_SIZE(2, 6 * sizeof(uint16_t)),
527 JumpNoConditionFixedSize = JUMP_ENUM_WITH_SIZE(3, 5 * sizeof(uint16_t)),
528 JumpConditionFixedSize = JUMP_ENUM_WITH_SIZE(4, 6 * sizeof(uint16_t))
529 };
530 enum JumpLinkType {
531 LinkInvalid = JUMP_ENUM_WITH_SIZE(0, 0),
532 LinkJumpT1 = JUMP_ENUM_WITH_SIZE(1, sizeof(uint16_t)),
533 LinkJumpT2 = JUMP_ENUM_WITH_SIZE(2, sizeof(uint16_t)),
534 LinkJumpT3 = JUMP_ENUM_WITH_SIZE(3, 2 * sizeof(uint16_t)),
535 LinkJumpT4 = JUMP_ENUM_WITH_SIZE(4, 2 * sizeof(uint16_t)),
536 LinkConditionalJumpT4 = JUMP_ENUM_WITH_SIZE(5, 3 * sizeof(uint16_t)),
537 LinkBX = JUMP_ENUM_WITH_SIZE(6, 5 * sizeof(uint16_t)),
538 LinkConditionalBX = JUMP_ENUM_WITH_SIZE(7, 6 * sizeof(uint16_t))
539 };
540
541 class LinkRecord {
542 public:
543 LinkRecord(intptr_t from, intptr_t to, JumpType type, Condition condition)
544 {
545 data.realTypes.m_from = from;
546 data.realTypes.m_to = to;
547 data.realTypes.m_type = type;
548 data.realTypes.m_linkType = LinkInvalid;
549 data.realTypes.m_condition = condition;
550 }
551 void operator=(const LinkRecord& other)
552 {
553 data.copyTypes.content[0] = other.data.copyTypes.content[0];
554 data.copyTypes.content[1] = other.data.copyTypes.content[1];
555 data.copyTypes.content[2] = other.data.copyTypes.content[2];
556 }
557 intptr_t from() const { return data.realTypes.m_from; }
558 void setFrom(intptr_t from) { data.realTypes.m_from = from; }
559 intptr_t to() const { return data.realTypes.m_to; }
560 JumpType type() const { return data.realTypes.m_type; }
561 JumpLinkType linkType() const { return data.realTypes.m_linkType; }
562 void setLinkType(JumpLinkType linkType) { ASSERT(data.realTypes.m_linkType == LinkInvalid); data.realTypes.m_linkType = linkType; }
563 Condition condition() const { return data.realTypes.m_condition; }
564 private:
565 union {
566 struct RealTypes {
567 intptr_t m_from : 31;
568 intptr_t m_to : 31;
569 JumpType m_type : 8;
570 JumpLinkType m_linkType : 8;
571 Condition m_condition : 16;
572 } realTypes;
573 struct CopyTypes {
574 uint32_t content[3];
575 } copyTypes;
576 COMPILE_ASSERT(sizeof(RealTypes) == sizeof(CopyTypes), LinkRecordCopyStructSizeEqualsRealStruct);
577 } data;
578 };
579
580 ARMv7Assembler()
581 : m_indexOfLastWatchpoint(INT_MIN)
582 , m_indexOfTailOfLastWatchpoint(INT_MIN)
583 {
584 }
585
586 AssemblerBuffer& buffer() { return m_formatter.m_buffer; }
587
588 private:
589
590 // ARMv7, Appx-A.6.3
591 static bool BadReg(RegisterID reg)
592 {
593 return (reg == ARMRegisters::sp) || (reg == ARMRegisters::pc);
594 }
595
596 uint32_t singleRegisterMask(FPSingleRegisterID rdNum, int highBitsShift, int lowBitShift)
597 {
598 uint32_t rdMask = (rdNum >> 1) << highBitsShift;
599 if (rdNum & 1)
600 rdMask |= 1 << lowBitShift;
601 return rdMask;
602 }
603
604 uint32_t doubleRegisterMask(FPDoubleRegisterID rdNum, int highBitShift, int lowBitsShift)
605 {
606 uint32_t rdMask = (rdNum & 0xf) << lowBitsShift;
607 if (rdNum & 16)
608 rdMask |= 1 << highBitShift;
609 return rdMask;
610 }
611
612 typedef enum {
613 OP_ADD_reg_T1 = 0x1800,
614 OP_SUB_reg_T1 = 0x1A00,
615 OP_ADD_imm_T1 = 0x1C00,
616 OP_SUB_imm_T1 = 0x1E00,
617 OP_MOV_imm_T1 = 0x2000,
618 OP_CMP_imm_T1 = 0x2800,
619 OP_ADD_imm_T2 = 0x3000,
620 OP_SUB_imm_T2 = 0x3800,
621 OP_AND_reg_T1 = 0x4000,
622 OP_EOR_reg_T1 = 0x4040,
623 OP_TST_reg_T1 = 0x4200,
624 OP_RSB_imm_T1 = 0x4240,
625 OP_CMP_reg_T1 = 0x4280,
626 OP_ORR_reg_T1 = 0x4300,
627 OP_MVN_reg_T1 = 0x43C0,
628 OP_ADD_reg_T2 = 0x4400,
629 OP_MOV_reg_T1 = 0x4600,
630 OP_BLX = 0x4700,
631 OP_BX = 0x4700,
632 OP_STR_reg_T1 = 0x5000,
633 OP_STRH_reg_T1 = 0x5200,
634 OP_STRB_reg_T1 = 0x5400,
635 OP_LDRSB_reg_T1 = 0x5600,
636 OP_LDR_reg_T1 = 0x5800,
637 OP_LDRH_reg_T1 = 0x5A00,
638 OP_LDRB_reg_T1 = 0x5C00,
639 OP_LDRSH_reg_T1 = 0x5E00,
640 OP_STR_imm_T1 = 0x6000,
641 OP_LDR_imm_T1 = 0x6800,
642 OP_STRB_imm_T1 = 0x7000,
643 OP_LDRB_imm_T1 = 0x7800,
644 OP_STRH_imm_T1 = 0x8000,
645 OP_LDRH_imm_T1 = 0x8800,
646 OP_STR_imm_T2 = 0x9000,
647 OP_LDR_imm_T2 = 0x9800,
648 OP_ADD_SP_imm_T1 = 0xA800,
649 OP_ADD_SP_imm_T2 = 0xB000,
650 OP_SUB_SP_imm_T1 = 0xB080,
651 OP_PUSH_T1 = 0xB400,
652 OP_POP_T1 = 0xBC00,
653 OP_BKPT = 0xBE00,
654 OP_IT = 0xBF00,
655 OP_NOP_T1 = 0xBF00,
656 } OpcodeID;
657
658 typedef enum {
659 OP_B_T1 = 0xD000,
660 OP_B_T2 = 0xE000,
661 OP_POP_T2 = 0xE8BD,
662 OP_PUSH_T2 = 0xE92D,
663 OP_AND_reg_T2 = 0xEA00,
664 OP_TST_reg_T2 = 0xEA10,
665 OP_ORR_reg_T2 = 0xEA40,
666 OP_ORR_S_reg_T2 = 0xEA50,
667 OP_ASR_imm_T1 = 0xEA4F,
668 OP_LSL_imm_T1 = 0xEA4F,
669 OP_LSR_imm_T1 = 0xEA4F,
670 OP_ROR_imm_T1 = 0xEA4F,
671 OP_MVN_reg_T2 = 0xEA6F,
672 OP_EOR_reg_T2 = 0xEA80,
673 OP_ADD_reg_T3 = 0xEB00,
674 OP_ADD_S_reg_T3 = 0xEB10,
675 OP_SUB_reg_T2 = 0xEBA0,
676 OP_SUB_S_reg_T2 = 0xEBB0,
677 OP_CMP_reg_T2 = 0xEBB0,
678 OP_VMOV_CtoD = 0xEC00,
679 OP_VMOV_DtoC = 0xEC10,
680 OP_FSTS = 0xED00,
681 OP_VSTR = 0xED00,
682 OP_FLDS = 0xED10,
683 OP_VLDR = 0xED10,
684 OP_VMOV_CtoS = 0xEE00,
685 OP_VMOV_StoC = 0xEE10,
686 OP_VMUL_T2 = 0xEE20,
687 OP_VADD_T2 = 0xEE30,
688 OP_VSUB_T2 = 0xEE30,
689 OP_VDIV = 0xEE80,
690 OP_VABS_T2 = 0xEEB0,
691 OP_VCMP = 0xEEB0,
692 OP_VCVT_FPIVFP = 0xEEB0,
693 OP_VMOV_T2 = 0xEEB0,
694 OP_VMOV_IMM_T2 = 0xEEB0,
695 OP_VMRS = 0xEEB0,
696 OP_VNEG_T2 = 0xEEB0,
697 OP_VSQRT_T1 = 0xEEB0,
698 OP_VCVTSD_T1 = 0xEEB0,
699 OP_VCVTDS_T1 = 0xEEB0,
700 OP_B_T3a = 0xF000,
701 OP_B_T4a = 0xF000,
702 OP_AND_imm_T1 = 0xF000,
703 OP_TST_imm = 0xF010,
704 OP_ORR_imm_T1 = 0xF040,
705 OP_MOV_imm_T2 = 0xF040,
706 OP_MVN_imm = 0xF060,
707 OP_EOR_imm_T1 = 0xF080,
708 OP_ADD_imm_T3 = 0xF100,
709 OP_ADD_S_imm_T3 = 0xF110,
710 OP_CMN_imm = 0xF110,
711 OP_ADC_imm = 0xF140,
712 OP_SUB_imm_T3 = 0xF1A0,
713 OP_SUB_S_imm_T3 = 0xF1B0,
714 OP_CMP_imm_T2 = 0xF1B0,
715 OP_RSB_imm_T2 = 0xF1C0,
716 OP_RSB_S_imm_T2 = 0xF1D0,
717 OP_ADD_imm_T4 = 0xF200,
718 OP_MOV_imm_T3 = 0xF240,
719 OP_SUB_imm_T4 = 0xF2A0,
720 OP_MOVT = 0xF2C0,
721 OP_UBFX_T1 = 0xF3C0,
722 OP_NOP_T2a = 0xF3AF,
723 OP_DMB_SY_T2a = 0xF3BF,
724 OP_STRB_imm_T3 = 0xF800,
725 OP_STRB_reg_T2 = 0xF800,
726 OP_LDRB_imm_T3 = 0xF810,
727 OP_LDRB_reg_T2 = 0xF810,
728 OP_STRH_imm_T3 = 0xF820,
729 OP_STRH_reg_T2 = 0xF820,
730 OP_LDRH_reg_T2 = 0xF830,
731 OP_LDRH_imm_T3 = 0xF830,
732 OP_STR_imm_T4 = 0xF840,
733 OP_STR_reg_T2 = 0xF840,
734 OP_LDR_imm_T4 = 0xF850,
735 OP_LDR_reg_T2 = 0xF850,
736 OP_STRB_imm_T2 = 0xF880,
737 OP_LDRB_imm_T2 = 0xF890,
738 OP_STRH_imm_T2 = 0xF8A0,
739 OP_LDRH_imm_T2 = 0xF8B0,
740 OP_STR_imm_T3 = 0xF8C0,
741 OP_LDR_imm_T3 = 0xF8D0,
742 OP_LDRSB_reg_T2 = 0xF910,
743 OP_LDRSH_reg_T2 = 0xF930,
744 OP_LSL_reg_T2 = 0xFA00,
745 OP_LSR_reg_T2 = 0xFA20,
746 OP_ASR_reg_T2 = 0xFA40,
747 OP_ROR_reg_T2 = 0xFA60,
748 OP_CLZ = 0xFAB0,
749 OP_SMULL_T1 = 0xFB80,
750 #if CPU(APPLE_ARMV7S)
751 OP_SDIV_T1 = 0xFB90,
752 OP_UDIV_T1 = 0xFBB0,
753 #endif
754 } OpcodeID1;
755
756 typedef enum {
757 OP_VADD_T2b = 0x0A00,
758 OP_VDIVb = 0x0A00,
759 OP_FLDSb = 0x0A00,
760 OP_VLDRb = 0x0A00,
761 OP_VMOV_IMM_T2b = 0x0A00,
762 OP_VMOV_T2b = 0x0A40,
763 OP_VMUL_T2b = 0x0A00,
764 OP_FSTSb = 0x0A00,
765 OP_VSTRb = 0x0A00,
766 OP_VMOV_StoCb = 0x0A10,
767 OP_VMOV_CtoSb = 0x0A10,
768 OP_VMOV_DtoCb = 0x0A10,
769 OP_VMOV_CtoDb = 0x0A10,
770 OP_VMRSb = 0x0A10,
771 OP_VABS_T2b = 0x0A40,
772 OP_VCMPb = 0x0A40,
773 OP_VCVT_FPIVFPb = 0x0A40,
774 OP_VNEG_T2b = 0x0A40,
775 OP_VSUB_T2b = 0x0A40,
776 OP_VSQRT_T1b = 0x0A40,
777 OP_VCVTSD_T1b = 0x0A40,
778 OP_VCVTDS_T1b = 0x0A40,
779 OP_NOP_T2b = 0x8000,
780 OP_DMB_SY_T2b = 0x8F5F,
781 OP_B_T3b = 0x8000,
782 OP_B_T4b = 0x9000,
783 } OpcodeID2;
784
785 struct FourFours {
786 FourFours(unsigned f3, unsigned f2, unsigned f1, unsigned f0)
787 {
788 m_u.f0 = f0;
789 m_u.f1 = f1;
790 m_u.f2 = f2;
791 m_u.f3 = f3;
792 }
793
794 union {
795 unsigned value;
796 struct {
797 unsigned f0 : 4;
798 unsigned f1 : 4;
799 unsigned f2 : 4;
800 unsigned f3 : 4;
801 };
802 } m_u;
803 };
804
805 class ARMInstructionFormatter;
806
807 // false means else!
808 static bool ifThenElseConditionBit(Condition condition, bool isIf)
809 {
810 return isIf ? (condition & 1) : !(condition & 1);
811 }
812 static uint8_t ifThenElse(Condition condition, bool inst2if, bool inst3if, bool inst4if)
813 {
814 int mask = (ifThenElseConditionBit(condition, inst2if) << 3)
815 | (ifThenElseConditionBit(condition, inst3if) << 2)
816 | (ifThenElseConditionBit(condition, inst4if) << 1)
817 | 1;
818 ASSERT((condition != ConditionAL) || !(mask & (mask - 1)));
819 return (condition << 4) | mask;
820 }
821 static uint8_t ifThenElse(Condition condition, bool inst2if, bool inst3if)
822 {
823 int mask = (ifThenElseConditionBit(condition, inst2if) << 3)
824 | (ifThenElseConditionBit(condition, inst3if) << 2)
825 | 2;
826 ASSERT((condition != ConditionAL) || !(mask & (mask - 1)));
827 return (condition << 4) | mask;
828 }
829 static uint8_t ifThenElse(Condition condition, bool inst2if)
830 {
831 int mask = (ifThenElseConditionBit(condition, inst2if) << 3)
832 | 4;
833 ASSERT((condition != ConditionAL) || !(mask & (mask - 1)));
834 return (condition << 4) | mask;
835 }
836
837 static uint8_t ifThenElse(Condition condition)
838 {
839 int mask = 8;
840 return (condition << 4) | mask;
841 }
842
843 public:
844
845 void adc(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
846 {
847 // Rd can only be SP if Rn is also SP.
848 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
849 ASSERT(rd != ARMRegisters::pc);
850 ASSERT(rn != ARMRegisters::pc);
851 ASSERT(imm.isEncodedImm());
852
853 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADC_imm, rn, rd, imm);
854 }
855
856 void add(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
857 {
858 // Rd can only be SP if Rn is also SP.
859 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
860 ASSERT(rd != ARMRegisters::pc);
861 ASSERT(rn != ARMRegisters::pc);
862 ASSERT(imm.isValid());
863
864 if (rn == ARMRegisters::sp && imm.isUInt16()) {
865 ASSERT(!(imm.getUInt16() & 3));
866 if (!(rd & 8) && imm.isUInt10()) {
867 m_formatter.oneWordOp5Reg3Imm8(OP_ADD_SP_imm_T1, rd, static_cast<uint8_t>(imm.getUInt10() >> 2));
868 return;
869 } else if ((rd == ARMRegisters::sp) && imm.isUInt9()) {
870 m_formatter.oneWordOp9Imm7(OP_ADD_SP_imm_T2, static_cast<uint8_t>(imm.getUInt9() >> 2));
871 return;
872 }
873 } else if (!((rd | rn) & 8)) {
874 if (imm.isUInt3()) {
875 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_imm_T1, (RegisterID)imm.getUInt3(), rn, rd);
876 return;
877 } else if ((rd == rn) && imm.isUInt8()) {
878 m_formatter.oneWordOp5Reg3Imm8(OP_ADD_imm_T2, rd, imm.getUInt8());
879 return;
880 }
881 }
882
883 if (imm.isEncodedImm())
884 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T3, rn, rd, imm);
885 else {
886 ASSERT(imm.isUInt12());
887 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T4, rn, rd, imm);
888 }
889 }
890
891 ALWAYS_INLINE void add(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
892 {
893 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
894 ASSERT(rd != ARMRegisters::pc);
895 ASSERT(rn != ARMRegisters::pc);
896 ASSERT(!BadReg(rm));
897 m_formatter.twoWordOp12Reg4FourFours(OP_ADD_reg_T3, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
898 }
899
900 // NOTE: In an IT block, add doesn't modify the flags register.
901 ALWAYS_INLINE void add(RegisterID rd, RegisterID rn, RegisterID rm)
902 {
903 if (rd == ARMRegisters::sp) {
904 mov(rd, rn);
905 rn = rd;
906 }
907
908 if (rd == rn)
909 m_formatter.oneWordOp8RegReg143(OP_ADD_reg_T2, rm, rd);
910 else if (rd == rm)
911 m_formatter.oneWordOp8RegReg143(OP_ADD_reg_T2, rn, rd);
912 else if (!((rd | rn | rm) & 8))
913 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_reg_T1, rm, rn, rd);
914 else
915 add(rd, rn, rm, ShiftTypeAndAmount());
916 }
917
918 // Not allowed in an IT (if then) block.
919 ALWAYS_INLINE void add_S(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
920 {
921 // Rd can only be SP if Rn is also SP.
922 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
923 ASSERT(rd != ARMRegisters::pc);
924 ASSERT(rn != ARMRegisters::pc);
925 ASSERT(imm.isEncodedImm());
926
927 if (!((rd | rn) & 8)) {
928 if (imm.isUInt3()) {
929 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_imm_T1, (RegisterID)imm.getUInt3(), rn, rd);
930 return;
931 } else if ((rd == rn) && imm.isUInt8()) {
932 m_formatter.oneWordOp5Reg3Imm8(OP_ADD_imm_T2, rd, imm.getUInt8());
933 return;
934 }
935 }
936
937 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_S_imm_T3, rn, rd, imm);
938 }
939
940 // Not allowed in an IT (if then) block?
941 ALWAYS_INLINE void add_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
942 {
943 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
944 ASSERT(rd != ARMRegisters::pc);
945 ASSERT(rn != ARMRegisters::pc);
946 ASSERT(!BadReg(rm));
947 m_formatter.twoWordOp12Reg4FourFours(OP_ADD_S_reg_T3, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
948 }
949
950 // Not allowed in an IT (if then) block.
951 ALWAYS_INLINE void add_S(RegisterID rd, RegisterID rn, RegisterID rm)
952 {
953 if (!((rd | rn | rm) & 8))
954 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_reg_T1, rm, rn, rd);
955 else
956 add_S(rd, rn, rm, ShiftTypeAndAmount());
957 }
958
959 ALWAYS_INLINE void ARM_and(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
960 {
961 ASSERT(!BadReg(rd));
962 ASSERT(!BadReg(rn));
963 ASSERT(imm.isEncodedImm());
964 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_AND_imm_T1, rn, rd, imm);
965 }
966
967 ALWAYS_INLINE void ARM_and(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
968 {
969 ASSERT(!BadReg(rd));
970 ASSERT(!BadReg(rn));
971 ASSERT(!BadReg(rm));
972 m_formatter.twoWordOp12Reg4FourFours(OP_AND_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
973 }
974
975 ALWAYS_INLINE void ARM_and(RegisterID rd, RegisterID rn, RegisterID rm)
976 {
977 if ((rd == rn) && !((rd | rm) & 8))
978 m_formatter.oneWordOp10Reg3Reg3(OP_AND_reg_T1, rm, rd);
979 else if ((rd == rm) && !((rd | rn) & 8))
980 m_formatter.oneWordOp10Reg3Reg3(OP_AND_reg_T1, rn, rd);
981 else
982 ARM_and(rd, rn, rm, ShiftTypeAndAmount());
983 }
984
985 ALWAYS_INLINE void asr(RegisterID rd, RegisterID rm, int32_t shiftAmount)
986 {
987 ASSERT(!BadReg(rd));
988 ASSERT(!BadReg(rm));
989 ShiftTypeAndAmount shift(SRType_ASR, shiftAmount);
990 m_formatter.twoWordOp16FourFours(OP_ASR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
991 }
992
993 ALWAYS_INLINE void asr(RegisterID rd, RegisterID rn, RegisterID rm)
994 {
995 ASSERT(!BadReg(rd));
996 ASSERT(!BadReg(rn));
997 ASSERT(!BadReg(rm));
998 m_formatter.twoWordOp12Reg4FourFours(OP_ASR_reg_T2, rn, FourFours(0xf, rd, 0, rm));
999 }
1000
1001 // Only allowed in IT (if then) block if last instruction.
1002 ALWAYS_INLINE AssemblerLabel b()
1003 {
1004 m_formatter.twoWordOp16Op16(OP_B_T4a, OP_B_T4b);
1005 return m_formatter.label();
1006 }
1007
1008 // Only allowed in IT (if then) block if last instruction.
1009 ALWAYS_INLINE AssemblerLabel blx(RegisterID rm)
1010 {
1011 ASSERT(rm != ARMRegisters::pc);
1012 m_formatter.oneWordOp8RegReg143(OP_BLX, rm, (RegisterID)8);
1013 return m_formatter.label();
1014 }
1015
1016 // Only allowed in IT (if then) block if last instruction.
1017 ALWAYS_INLINE AssemblerLabel bx(RegisterID rm)
1018 {
1019 m_formatter.oneWordOp8RegReg143(OP_BX, rm, (RegisterID)0);
1020 return m_formatter.label();
1021 }
1022
1023 void bkpt(uint8_t imm = 0)
1024 {
1025 m_formatter.oneWordOp8Imm8(OP_BKPT, imm);
1026 }
1027
1028 ALWAYS_INLINE void clz(RegisterID rd, RegisterID rm)
1029 {
1030 ASSERT(!BadReg(rd));
1031 ASSERT(!BadReg(rm));
1032 m_formatter.twoWordOp12Reg4FourFours(OP_CLZ, rm, FourFours(0xf, rd, 8, rm));
1033 }
1034
1035 ALWAYS_INLINE void cmn(RegisterID rn, ARMThumbImmediate imm)
1036 {
1037 ASSERT(rn != ARMRegisters::pc);
1038 ASSERT(imm.isEncodedImm());
1039
1040 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMN_imm, rn, (RegisterID)0xf, imm);
1041 }
1042
1043 ALWAYS_INLINE void cmp(RegisterID rn, ARMThumbImmediate imm)
1044 {
1045 ASSERT(rn != ARMRegisters::pc);
1046 ASSERT(imm.isEncodedImm());
1047
1048 if (!(rn & 8) && imm.isUInt8())
1049 m_formatter.oneWordOp5Reg3Imm8(OP_CMP_imm_T1, rn, imm.getUInt8());
1050 else
1051 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMP_imm_T2, rn, (RegisterID)0xf, imm);
1052 }
1053
1054 ALWAYS_INLINE void cmp(RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
1055 {
1056 ASSERT(rn != ARMRegisters::pc);
1057 ASSERT(!BadReg(rm));
1058 m_formatter.twoWordOp12Reg4FourFours(OP_CMP_reg_T2, rn, FourFours(shift.hi4(), 0xf, shift.lo4(), rm));
1059 }
1060
1061 ALWAYS_INLINE void cmp(RegisterID rn, RegisterID rm)
1062 {
1063 if ((rn | rm) & 8)
1064 cmp(rn, rm, ShiftTypeAndAmount());
1065 else
1066 m_formatter.oneWordOp10Reg3Reg3(OP_CMP_reg_T1, rm, rn);
1067 }
1068
1069 // xor is not spelled with an 'e'. :-(
1070 ALWAYS_INLINE void eor(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
1071 {
1072 ASSERT(!BadReg(rd));
1073 ASSERT(!BadReg(rn));
1074 ASSERT(imm.isEncodedImm());
1075 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_EOR_imm_T1, rn, rd, imm);
1076 }
1077
1078 // xor is not spelled with an 'e'. :-(
1079 ALWAYS_INLINE void eor(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
1080 {
1081 ASSERT(!BadReg(rd));
1082 ASSERT(!BadReg(rn));
1083 ASSERT(!BadReg(rm));
1084 m_formatter.twoWordOp12Reg4FourFours(OP_EOR_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1085 }
1086
1087 // xor is not spelled with an 'e'. :-(
1088 void eor(RegisterID rd, RegisterID rn, RegisterID rm)
1089 {
1090 if ((rd == rn) && !((rd | rm) & 8))
1091 m_formatter.oneWordOp10Reg3Reg3(OP_EOR_reg_T1, rm, rd);
1092 else if ((rd == rm) && !((rd | rn) & 8))
1093 m_formatter.oneWordOp10Reg3Reg3(OP_EOR_reg_T1, rn, rd);
1094 else
1095 eor(rd, rn, rm, ShiftTypeAndAmount());
1096 }
1097
1098 ALWAYS_INLINE void it(Condition cond)
1099 {
1100 m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond));
1101 }
1102
1103 ALWAYS_INLINE void it(Condition cond, bool inst2if)
1104 {
1105 m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if));
1106 }
1107
1108 ALWAYS_INLINE void it(Condition cond, bool inst2if, bool inst3if)
1109 {
1110 m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if, inst3if));
1111 }
1112
1113 ALWAYS_INLINE void it(Condition cond, bool inst2if, bool inst3if, bool inst4if)
1114 {
1115 m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if, inst3if, inst4if));
1116 }
1117
1118 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1119 ALWAYS_INLINE void ldr(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
1120 {
1121 ASSERT(rn != ARMRegisters::pc); // LDR (literal)
1122 ASSERT(imm.isUInt12());
1123
1124 if (!((rt | rn) & 8) && imm.isUInt7())
1125 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDR_imm_T1, imm.getUInt7() >> 2, rn, rt);
1126 else if ((rn == ARMRegisters::sp) && !(rt & 8) && imm.isUInt10())
1127 m_formatter.oneWordOp5Reg3Imm8(OP_LDR_imm_T2, rt, static_cast<uint8_t>(imm.getUInt10() >> 2));
1128 else
1129 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T3, rn, rt, imm.getUInt12());
1130 }
1131
1132 ALWAYS_INLINE void ldrWide8BitImmediate(RegisterID rt, RegisterID rn, uint8_t immediate)
1133 {
1134 ASSERT(rn != ARMRegisters::pc);
1135 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T3, rn, rt, immediate);
1136 }
1137
1138 ALWAYS_INLINE void ldrCompact(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
1139 {
1140 ASSERT(rn != ARMRegisters::pc); // LDR (literal)
1141 ASSERT(imm.isUInt7());
1142 ASSERT(!((rt | rn) & 8));
1143 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDR_imm_T1, imm.getUInt7() >> 2, rn, rt);
1144 }
1145
1146 // If index is set, this is a regular offset or a pre-indexed load;
1147 // if index is not set then is is a post-index load.
1148 //
1149 // If wback is set rn is updated - this is a pre or post index load,
1150 // if wback is not set this is a regular offset memory access.
1151 //
1152 // (-255 <= offset <= 255)
1153 // _reg = REG[rn]
1154 // _tmp = _reg + offset
1155 // MEM[index ? _tmp : _reg] = REG[rt]
1156 // if (wback) REG[rn] = _tmp
1157 ALWAYS_INLINE void ldr(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
1158 {
1159 ASSERT(rt != ARMRegisters::pc);
1160 ASSERT(rn != ARMRegisters::pc);
1161 ASSERT(index || wback);
1162 ASSERT(!wback | (rt != rn));
1163
1164 bool add = true;
1165 if (offset < 0) {
1166 add = false;
1167 offset = -offset;
1168 }
1169 ASSERT((offset & ~0xff) == 0);
1170
1171 offset |= (wback << 8);
1172 offset |= (add << 9);
1173 offset |= (index << 10);
1174 offset |= (1 << 11);
1175
1176 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T4, rn, rt, offset);
1177 }
1178
1179 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1180 ALWAYS_INLINE void ldr(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0)
1181 {
1182 ASSERT(rn != ARMRegisters::pc); // LDR (literal)
1183 ASSERT(!BadReg(rm));
1184 ASSERT(shift <= 3);
1185
1186 if (!shift && !((rt | rn | rm) & 8))
1187 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDR_reg_T1, rm, rn, rt);
1188 else
1189 m_formatter.twoWordOp12Reg4FourFours(OP_LDR_reg_T2, rn, FourFours(rt, 0, shift, rm));
1190 }
1191
1192 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1193 ALWAYS_INLINE void ldrh(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
1194 {
1195 ASSERT(rn != ARMRegisters::pc); // LDR (literal)
1196 ASSERT(imm.isUInt12());
1197
1198 if (!((rt | rn) & 8) && imm.isUInt6())
1199 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDRH_imm_T1, imm.getUInt6() >> 2, rn, rt);
1200 else
1201 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T2, rn, rt, imm.getUInt12());
1202 }
1203
1204 // If index is set, this is a regular offset or a pre-indexed load;
1205 // if index is not set then is is a post-index load.
1206 //
1207 // If wback is set rn is updated - this is a pre or post index load,
1208 // if wback is not set this is a regular offset memory access.
1209 //
1210 // (-255 <= offset <= 255)
1211 // _reg = REG[rn]
1212 // _tmp = _reg + offset
1213 // MEM[index ? _tmp : _reg] = REG[rt]
1214 // if (wback) REG[rn] = _tmp
1215 ALWAYS_INLINE void ldrh(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
1216 {
1217 ASSERT(rt != ARMRegisters::pc);
1218 ASSERT(rn != ARMRegisters::pc);
1219 ASSERT(index || wback);
1220 ASSERT(!wback | (rt != rn));
1221
1222 bool add = true;
1223 if (offset < 0) {
1224 add = false;
1225 offset = -offset;
1226 }
1227 ASSERT((offset & ~0xff) == 0);
1228
1229 offset |= (wback << 8);
1230 offset |= (add << 9);
1231 offset |= (index << 10);
1232 offset |= (1 << 11);
1233
1234 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T3, rn, rt, offset);
1235 }
1236
1237 ALWAYS_INLINE void ldrh(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0)
1238 {
1239 ASSERT(!BadReg(rt)); // Memory hint
1240 ASSERT(rn != ARMRegisters::pc); // LDRH (literal)
1241 ASSERT(!BadReg(rm));
1242 ASSERT(shift <= 3);
1243
1244 if (!shift && !((rt | rn | rm) & 8))
1245 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDRH_reg_T1, rm, rn, rt);
1246 else
1247 m_formatter.twoWordOp12Reg4FourFours(OP_LDRH_reg_T2, rn, FourFours(rt, 0, shift, rm));
1248 }
1249
1250 void ldrb(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
1251 {
1252 ASSERT(rn != ARMRegisters::pc); // LDR (literal)
1253 ASSERT(imm.isUInt12());
1254
1255 if (!((rt | rn) & 8) && imm.isUInt5())
1256 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDRB_imm_T1, imm.getUInt5(), rn, rt);
1257 else
1258 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRB_imm_T2, rn, rt, imm.getUInt12());
1259 }
1260
1261 void ldrb(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
1262 {
1263 ASSERT(rt != ARMRegisters::pc);
1264 ASSERT(rn != ARMRegisters::pc);
1265 ASSERT(index || wback);
1266 ASSERT(!wback | (rt != rn));
1267
1268 bool add = true;
1269 if (offset < 0) {
1270 add = false;
1271 offset = -offset;
1272 }
1273
1274 ASSERT(!(offset & ~0xff));
1275
1276 offset |= (wback << 8);
1277 offset |= (add << 9);
1278 offset |= (index << 10);
1279 offset |= (1 << 11);
1280
1281 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRB_imm_T3, rn, rt, offset);
1282 }
1283
1284 ALWAYS_INLINE void ldrb(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0)
1285 {
1286 ASSERT(rn != ARMRegisters::pc); // LDR (literal)
1287 ASSERT(!BadReg(rm));
1288 ASSERT(shift <= 3);
1289
1290 if (!shift && !((rt | rn | rm) & 8))
1291 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDRB_reg_T1, rm, rn, rt);
1292 else
1293 m_formatter.twoWordOp12Reg4FourFours(OP_LDRB_reg_T2, rn, FourFours(rt, 0, shift, rm));
1294 }
1295
1296 void ldrsb(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0)
1297 {
1298 ASSERT(rn != ARMRegisters::pc);
1299 ASSERT(!BadReg(rm));
1300 ASSERT(shift <= 3);
1301
1302 if (!shift && !((rt | rn | rm) & 8))
1303 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDRSB_reg_T1, rm, rn, rt);
1304 else
1305 m_formatter.twoWordOp12Reg4FourFours(OP_LDRSB_reg_T2, rn, FourFours(rt, 0, shift, rm));
1306 }
1307
1308 void ldrsh(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0)
1309 {
1310 ASSERT(rn != ARMRegisters::pc);
1311 ASSERT(!BadReg(rm));
1312 ASSERT(shift <= 3);
1313
1314 if (!shift && !((rt | rn | rm) & 8))
1315 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDRSH_reg_T1, rm, rn, rt);
1316 else
1317 m_formatter.twoWordOp12Reg4FourFours(OP_LDRSH_reg_T2, rn, FourFours(rt, 0, shift, rm));
1318 }
1319
1320 void lsl(RegisterID rd, RegisterID rm, int32_t shiftAmount)
1321 {
1322 ASSERT(!BadReg(rd));
1323 ASSERT(!BadReg(rm));
1324 ShiftTypeAndAmount shift(SRType_LSL, shiftAmount);
1325 m_formatter.twoWordOp16FourFours(OP_LSL_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1326 }
1327
1328 ALWAYS_INLINE void lsl(RegisterID rd, RegisterID rn, RegisterID rm)
1329 {
1330 ASSERT(!BadReg(rd));
1331 ASSERT(!BadReg(rn));
1332 ASSERT(!BadReg(rm));
1333 m_formatter.twoWordOp12Reg4FourFours(OP_LSL_reg_T2, rn, FourFours(0xf, rd, 0, rm));
1334 }
1335
1336 ALWAYS_INLINE void lsr(RegisterID rd, RegisterID rm, int32_t shiftAmount)
1337 {
1338 ASSERT(!BadReg(rd));
1339 ASSERT(!BadReg(rm));
1340 ShiftTypeAndAmount shift(SRType_LSR, shiftAmount);
1341 m_formatter.twoWordOp16FourFours(OP_LSR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1342 }
1343
1344 ALWAYS_INLINE void lsr(RegisterID rd, RegisterID rn, RegisterID rm)
1345 {
1346 ASSERT(!BadReg(rd));
1347 ASSERT(!BadReg(rn));
1348 ASSERT(!BadReg(rm));
1349 m_formatter.twoWordOp12Reg4FourFours(OP_LSR_reg_T2, rn, FourFours(0xf, rd, 0, rm));
1350 }
1351
1352 ALWAYS_INLINE void movT3(RegisterID rd, ARMThumbImmediate imm)
1353 {
1354 ASSERT(imm.isValid());
1355 ASSERT(!imm.isEncodedImm());
1356 ASSERT(!BadReg(rd));
1357
1358 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T3, imm.m_value.imm4, rd, imm);
1359 }
1360
1361 #if OS(LINUX)
1362 static void revertJumpTo_movT3movtcmpT2(void* instructionStart, RegisterID left, RegisterID right, uintptr_t imm)
1363 {
1364 uint16_t* address = static_cast<uint16_t*>(instructionStart);
1365 ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(imm));
1366 ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(imm >> 16));
1367 address[0] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16);
1368 address[1] = twoWordOp5i6Imm4Reg4EncodedImmSecond(right, lo16);
1369 address[2] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16);
1370 address[3] = twoWordOp5i6Imm4Reg4EncodedImmSecond(right, hi16);
1371 address[4] = OP_CMP_reg_T2 | left;
1372 cacheFlush(address, sizeof(uint16_t) * 5);
1373 }
1374 #else
1375 static void revertJumpTo_movT3(void* instructionStart, RegisterID rd, ARMThumbImmediate imm)
1376 {
1377 ASSERT(imm.isValid());
1378 ASSERT(!imm.isEncodedImm());
1379 ASSERT(!BadReg(rd));
1380
1381 uint16_t* address = static_cast<uint16_t*>(instructionStart);
1382 address[0] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, imm);
1383 address[1] = twoWordOp5i6Imm4Reg4EncodedImmSecond(rd, imm);
1384 cacheFlush(address, sizeof(uint16_t) * 2);
1385 }
1386 #endif
1387
1388 ALWAYS_INLINE void mov(RegisterID rd, ARMThumbImmediate imm)
1389 {
1390 ASSERT(imm.isValid());
1391 ASSERT(!BadReg(rd));
1392
1393 if ((rd < 8) && imm.isUInt8())
1394 m_formatter.oneWordOp5Reg3Imm8(OP_MOV_imm_T1, rd, imm.getUInt8());
1395 else if (imm.isEncodedImm())
1396 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T2, 0xf, rd, imm);
1397 else
1398 movT3(rd, imm);
1399 }
1400
1401 ALWAYS_INLINE void mov(RegisterID rd, RegisterID rm)
1402 {
1403 m_formatter.oneWordOp8RegReg143(OP_MOV_reg_T1, rm, rd);
1404 }
1405
1406 ALWAYS_INLINE void movt(RegisterID rd, ARMThumbImmediate imm)
1407 {
1408 ASSERT(imm.isUInt16());
1409 ASSERT(!BadReg(rd));
1410 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOVT, imm.m_value.imm4, rd, imm);
1411 }
1412
1413 ALWAYS_INLINE void mvn(RegisterID rd, ARMThumbImmediate imm)
1414 {
1415 ASSERT(imm.isEncodedImm());
1416 ASSERT(!BadReg(rd));
1417
1418 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MVN_imm, 0xf, rd, imm);
1419 }
1420
1421 ALWAYS_INLINE void mvn(RegisterID rd, RegisterID rm, ShiftTypeAndAmount shift)
1422 {
1423 ASSERT(!BadReg(rd));
1424 ASSERT(!BadReg(rm));
1425 m_formatter.twoWordOp16FourFours(OP_MVN_reg_T2, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1426 }
1427
1428 ALWAYS_INLINE void mvn(RegisterID rd, RegisterID rm)
1429 {
1430 if (!((rd | rm) & 8))
1431 m_formatter.oneWordOp10Reg3Reg3(OP_MVN_reg_T1, rm, rd);
1432 else
1433 mvn(rd, rm, ShiftTypeAndAmount());
1434 }
1435
1436 ALWAYS_INLINE void neg(RegisterID rd, RegisterID rm)
1437 {
1438 ARMThumbImmediate zero = ARMThumbImmediate::makeUInt12(0);
1439 sub(rd, zero, rm);
1440 }
1441
1442 ALWAYS_INLINE void orr(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
1443 {
1444 ASSERT(!BadReg(rd));
1445 ASSERT(!BadReg(rn));
1446 ASSERT(imm.isEncodedImm());
1447 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ORR_imm_T1, rn, rd, imm);
1448 }
1449
1450 ALWAYS_INLINE void orr(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
1451 {
1452 ASSERT(!BadReg(rd));
1453 ASSERT(!BadReg(rn));
1454 ASSERT(!BadReg(rm));
1455 m_formatter.twoWordOp12Reg4FourFours(OP_ORR_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1456 }
1457
1458 void orr(RegisterID rd, RegisterID rn, RegisterID rm)
1459 {
1460 if ((rd == rn) && !((rd | rm) & 8))
1461 m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rm, rd);
1462 else if ((rd == rm) && !((rd | rn) & 8))
1463 m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rn, rd);
1464 else
1465 orr(rd, rn, rm, ShiftTypeAndAmount());
1466 }
1467
1468 ALWAYS_INLINE void orr_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
1469 {
1470 ASSERT(!BadReg(rd));
1471 ASSERT(!BadReg(rn));
1472 ASSERT(!BadReg(rm));
1473 m_formatter.twoWordOp12Reg4FourFours(OP_ORR_S_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1474 }
1475
1476 void orr_S(RegisterID rd, RegisterID rn, RegisterID rm)
1477 {
1478 if ((rd == rn) && !((rd | rm) & 8))
1479 m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rm, rd);
1480 else if ((rd == rm) && !((rd | rn) & 8))
1481 m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rn, rd);
1482 else
1483 orr_S(rd, rn, rm, ShiftTypeAndAmount());
1484 }
1485
1486 ALWAYS_INLINE void ror(RegisterID rd, RegisterID rm, int32_t shiftAmount)
1487 {
1488 ASSERT(!BadReg(rd));
1489 ASSERT(!BadReg(rm));
1490 ShiftTypeAndAmount shift(SRType_ROR, shiftAmount);
1491 m_formatter.twoWordOp16FourFours(OP_ROR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1492 }
1493
1494 ALWAYS_INLINE void ror(RegisterID rd, RegisterID rn, RegisterID rm)
1495 {
1496 ASSERT(!BadReg(rd));
1497 ASSERT(!BadReg(rn));
1498 ASSERT(!BadReg(rm));
1499 m_formatter.twoWordOp12Reg4FourFours(OP_ROR_reg_T2, rn, FourFours(0xf, rd, 0, rm));
1500 }
1501
1502 ALWAYS_INLINE void pop(RegisterID dest)
1503 {
1504 if (dest < ARMRegisters::r8)
1505 m_formatter.oneWordOp7Imm9(OP_POP_T1, 1 << dest);
1506 else {
1507 // Load postindexed with writeback.
1508 ldr(dest, ARMRegisters::sp, sizeof(void*), false, true);
1509 }
1510 }
1511
1512 ALWAYS_INLINE void pop(uint32_t registerList)
1513 {
1514 ASSERT(WTF::bitCount(registerList) > 1);
1515 ASSERT(!((1 << ARMRegisters::pc) & registerList) || !((1 << ARMRegisters::lr) & registerList));
1516 ASSERT(!((1 << ARMRegisters::sp) & registerList));
1517 m_formatter.twoWordOp16Imm16(OP_POP_T2, registerList);
1518 }
1519
1520 ALWAYS_INLINE void push(RegisterID src)
1521 {
1522 if (src < ARMRegisters::r8)
1523 m_formatter.oneWordOp7Imm9(OP_PUSH_T1, 1 << src);
1524 else if (src == ARMRegisters::lr)
1525 m_formatter.oneWordOp7Imm9(OP_PUSH_T1, 0x100);
1526 else {
1527 // Store preindexed with writeback.
1528 str(src, ARMRegisters::sp, -sizeof(void*), true, true);
1529 }
1530 }
1531
1532 ALWAYS_INLINE void push(uint32_t registerList)
1533 {
1534 ASSERT(WTF::bitCount(registerList) > 1);
1535 ASSERT(!((1 << ARMRegisters::pc) & registerList));
1536 ASSERT(!((1 << ARMRegisters::sp) & registerList));
1537 m_formatter.twoWordOp16Imm16(OP_PUSH_T2, registerList);
1538 }
1539
1540 #if CPU(APPLE_ARMV7S)
1541 template<int datasize>
1542 ALWAYS_INLINE void sdiv(RegisterID rd, RegisterID rn, RegisterID rm)
1543 {
1544 static_assert(datasize == 32, "sdiv datasize must be 32 for armv7s");
1545 ASSERT(!BadReg(rd));
1546 ASSERT(!BadReg(rn));
1547 ASSERT(!BadReg(rm));
1548 m_formatter.twoWordOp12Reg4FourFours(OP_SDIV_T1, rn, FourFours(0xf, rd, 0xf, rm));
1549 }
1550 #endif
1551
1552 ALWAYS_INLINE void smull(RegisterID rdLo, RegisterID rdHi, RegisterID rn, RegisterID rm)
1553 {
1554 ASSERT(!BadReg(rdLo));
1555 ASSERT(!BadReg(rdHi));
1556 ASSERT(!BadReg(rn));
1557 ASSERT(!BadReg(rm));
1558 ASSERT(rdLo != rdHi);
1559 m_formatter.twoWordOp12Reg4FourFours(OP_SMULL_T1, rn, FourFours(rdLo, rdHi, 0, rm));
1560 }
1561
1562 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1563 ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
1564 {
1565 ASSERT(rt != ARMRegisters::pc);
1566 ASSERT(rn != ARMRegisters::pc);
1567 ASSERT(imm.isUInt12());
1568
1569 if (!((rt | rn) & 8) && imm.isUInt7())
1570 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_STR_imm_T1, imm.getUInt7() >> 2, rn, rt);
1571 else if ((rn == ARMRegisters::sp) && !(rt & 8) && imm.isUInt10())
1572 m_formatter.oneWordOp5Reg3Imm8(OP_STR_imm_T2, rt, static_cast<uint8_t>(imm.getUInt10() >> 2));
1573 else
1574 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T3, rn, rt, imm.getUInt12());
1575 }
1576
1577 // If index is set, this is a regular offset or a pre-indexed store;
1578 // if index is not set then is is a post-index store.
1579 //
1580 // If wback is set rn is updated - this is a pre or post index store,
1581 // if wback is not set this is a regular offset memory access.
1582 //
1583 // (-255 <= offset <= 255)
1584 // _reg = REG[rn]
1585 // _tmp = _reg + offset
1586 // MEM[index ? _tmp : _reg] = REG[rt]
1587 // if (wback) REG[rn] = _tmp
1588 ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
1589 {
1590 ASSERT(rt != ARMRegisters::pc);
1591 ASSERT(rn != ARMRegisters::pc);
1592 ASSERT(index || wback);
1593 ASSERT(!wback | (rt != rn));
1594
1595 bool add = true;
1596 if (offset < 0) {
1597 add = false;
1598 offset = -offset;
1599 }
1600 ASSERT((offset & ~0xff) == 0);
1601
1602 offset |= (wback << 8);
1603 offset |= (add << 9);
1604 offset |= (index << 10);
1605 offset |= (1 << 11);
1606
1607 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T4, rn, rt, offset);
1608 }
1609
1610 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1611 ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0)
1612 {
1613 ASSERT(rn != ARMRegisters::pc);
1614 ASSERT(!BadReg(rm));
1615 ASSERT(shift <= 3);
1616
1617 if (!shift && !((rt | rn | rm) & 8))
1618 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_STR_reg_T1, rm, rn, rt);
1619 else
1620 m_formatter.twoWordOp12Reg4FourFours(OP_STR_reg_T2, rn, FourFours(rt, 0, shift, rm));
1621 }
1622
1623 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1624 ALWAYS_INLINE void strb(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
1625 {
1626 ASSERT(rt != ARMRegisters::pc);
1627 ASSERT(rn != ARMRegisters::pc);
1628 ASSERT(imm.isUInt12());
1629
1630 if (!((rt | rn) & 8) && imm.isUInt7())
1631 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_STRB_imm_T1, imm.getUInt7() >> 2, rn, rt);
1632 else
1633 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STRB_imm_T2, rn, rt, imm.getUInt12());
1634 }
1635
1636 // If index is set, this is a regular offset or a pre-indexed store;
1637 // if index is not set then is is a post-index store.
1638 //
1639 // If wback is set rn is updated - this is a pre or post index store,
1640 // if wback is not set this is a regular offset memory access.
1641 //
1642 // (-255 <= offset <= 255)
1643 // _reg = REG[rn]
1644 // _tmp = _reg + offset
1645 // MEM[index ? _tmp : _reg] = REG[rt]
1646 // if (wback) REG[rn] = _tmp
1647 ALWAYS_INLINE void strb(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
1648 {
1649 ASSERT(rt != ARMRegisters::pc);
1650 ASSERT(rn != ARMRegisters::pc);
1651 ASSERT(index || wback);
1652 ASSERT(!wback | (rt != rn));
1653
1654 bool add = true;
1655 if (offset < 0) {
1656 add = false;
1657 offset = -offset;
1658 }
1659 ASSERT((offset & ~0xff) == 0);
1660
1661 offset |= (wback << 8);
1662 offset |= (add << 9);
1663 offset |= (index << 10);
1664 offset |= (1 << 11);
1665
1666 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STRB_imm_T3, rn, rt, offset);
1667 }
1668
1669 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1670 ALWAYS_INLINE void strb(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0)
1671 {
1672 ASSERT(rn != ARMRegisters::pc);
1673 ASSERT(!BadReg(rm));
1674 ASSERT(shift <= 3);
1675
1676 if (!shift && !((rt | rn | rm) & 8))
1677 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_STRB_reg_T1, rm, rn, rt);
1678 else
1679 m_formatter.twoWordOp12Reg4FourFours(OP_STRB_reg_T2, rn, FourFours(rt, 0, shift, rm));
1680 }
1681
1682 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1683 ALWAYS_INLINE void strh(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
1684 {
1685 ASSERT(rt != ARMRegisters::pc);
1686 ASSERT(rn != ARMRegisters::pc);
1687 ASSERT(imm.isUInt12());
1688
1689 if (!((rt | rn) & 8) && imm.isUInt7())
1690 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_STRH_imm_T1, imm.getUInt7() >> 2, rn, rt);
1691 else
1692 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STRH_imm_T2, rn, rt, imm.getUInt12());
1693 }
1694
1695 // If index is set, this is a regular offset or a pre-indexed store;
1696 // if index is not set then is is a post-index store.
1697 //
1698 // If wback is set rn is updated - this is a pre or post index store,
1699 // if wback is not set this is a regular offset memory access.
1700 //
1701 // (-255 <= offset <= 255)
1702 // _reg = REG[rn]
1703 // _tmp = _reg + offset
1704 // MEM[index ? _tmp : _reg] = REG[rt]
1705 // if (wback) REG[rn] = _tmp
1706 ALWAYS_INLINE void strh(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
1707 {
1708 ASSERT(rt != ARMRegisters::pc);
1709 ASSERT(rn != ARMRegisters::pc);
1710 ASSERT(index || wback);
1711 ASSERT(!wback | (rt != rn));
1712
1713 bool add = true;
1714 if (offset < 0) {
1715 add = false;
1716 offset = -offset;
1717 }
1718 ASSERT(!(offset & ~0xff));
1719
1720 offset |= (wback << 8);
1721 offset |= (add << 9);
1722 offset |= (index << 10);
1723 offset |= (1 << 11);
1724
1725 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STRH_imm_T3, rn, rt, offset);
1726 }
1727
1728 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1729 ALWAYS_INLINE void strh(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0)
1730 {
1731 ASSERT(rn != ARMRegisters::pc);
1732 ASSERT(!BadReg(rm));
1733 ASSERT(shift <= 3);
1734
1735 if (!shift && !((rt | rn | rm) & 8))
1736 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_STRH_reg_T1, rm, rn, rt);
1737 else
1738 m_formatter.twoWordOp12Reg4FourFours(OP_STRH_reg_T2, rn, FourFours(rt, 0, shift, rm));
1739 }
1740
1741 ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
1742 {
1743 // Rd can only be SP if Rn is also SP.
1744 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
1745 ASSERT(rd != ARMRegisters::pc);
1746 ASSERT(rn != ARMRegisters::pc);
1747 ASSERT(imm.isValid());
1748
1749 if ((rn == ARMRegisters::sp) && (rd == ARMRegisters::sp) && imm.isUInt9()) {
1750 ASSERT(!(imm.getUInt16() & 3));
1751 m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, static_cast<uint8_t>(imm.getUInt9() >> 2));
1752 return;
1753 } else if (!((rd | rn) & 8)) {
1754 if (imm.isUInt3()) {
1755 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_imm_T1, (RegisterID)imm.getUInt3(), rn, rd);
1756 return;
1757 } else if ((rd == rn) && imm.isUInt8()) {
1758 m_formatter.oneWordOp5Reg3Imm8(OP_SUB_imm_T2, rd, imm.getUInt8());
1759 return;
1760 }
1761 }
1762
1763 if (imm.isEncodedImm())
1764 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T3, rn, rd, imm);
1765 else {
1766 ASSERT(imm.isUInt12());
1767 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T4, rn, rd, imm);
1768 }
1769 }
1770
1771 ALWAYS_INLINE void sub(RegisterID rd, ARMThumbImmediate imm, RegisterID rn)
1772 {
1773 ASSERT(rd != ARMRegisters::pc);
1774 ASSERT(rn != ARMRegisters::pc);
1775 ASSERT(imm.isValid());
1776 ASSERT(imm.isUInt12());
1777
1778 if (!((rd | rn) & 8) && !imm.getUInt12())
1779 m_formatter.oneWordOp10Reg3Reg3(OP_RSB_imm_T1, rn, rd);
1780 else
1781 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_RSB_imm_T2, rn, rd, imm);
1782 }
1783
1784 ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
1785 {
1786 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
1787 ASSERT(rd != ARMRegisters::pc);
1788 ASSERT(rn != ARMRegisters::pc);
1789 ASSERT(!BadReg(rm));
1790 m_formatter.twoWordOp12Reg4FourFours(OP_SUB_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1791 }
1792
1793 // NOTE: In an IT block, add doesn't modify the flags register.
1794 ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, RegisterID rm)
1795 {
1796 if (!((rd | rn | rm) & 8))
1797 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_reg_T1, rm, rn, rd);
1798 else
1799 sub(rd, rn, rm, ShiftTypeAndAmount());
1800 }
1801
1802 // Not allowed in an IT (if then) block.
1803 void sub_S(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
1804 {
1805 // Rd can only be SP if Rn is also SP.
1806 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
1807 ASSERT(rd != ARMRegisters::pc);
1808 ASSERT(rn != ARMRegisters::pc);
1809 ASSERT(imm.isValid());
1810
1811 if ((rn == ARMRegisters::sp) && (rd == ARMRegisters::sp) && imm.isUInt9()) {
1812 ASSERT(!(imm.getUInt16() & 3));
1813 m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, static_cast<uint8_t>(imm.getUInt9() >> 2));
1814 return;
1815 } else if (!((rd | rn) & 8)) {
1816 if (imm.isUInt3()) {
1817 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_imm_T1, (RegisterID)imm.getUInt3(), rn, rd);
1818 return;
1819 } else if ((rd == rn) && imm.isUInt8()) {
1820 m_formatter.oneWordOp5Reg3Imm8(OP_SUB_imm_T2, rd, imm.getUInt8());
1821 return;
1822 }
1823 }
1824
1825 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_S_imm_T3, rn, rd, imm);
1826 }
1827
1828 ALWAYS_INLINE void sub_S(RegisterID rd, ARMThumbImmediate imm, RegisterID rn)
1829 {
1830 ASSERT(rd != ARMRegisters::pc);
1831 ASSERT(rn != ARMRegisters::pc);
1832 ASSERT(imm.isValid());
1833 ASSERT(imm.isUInt12());
1834
1835 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_RSB_S_imm_T2, rn, rd, imm);
1836 }
1837
1838 // Not allowed in an IT (if then) block?
1839 ALWAYS_INLINE void sub_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
1840 {
1841 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
1842 ASSERT(rd != ARMRegisters::pc);
1843 ASSERT(rn != ARMRegisters::pc);
1844 ASSERT(!BadReg(rm));
1845 m_formatter.twoWordOp12Reg4FourFours(OP_SUB_S_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1846 }
1847
1848 // Not allowed in an IT (if then) block.
1849 ALWAYS_INLINE void sub_S(RegisterID rd, RegisterID rn, RegisterID rm)
1850 {
1851 if (!((rd | rn | rm) & 8))
1852 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_reg_T1, rm, rn, rd);
1853 else
1854 sub_S(rd, rn, rm, ShiftTypeAndAmount());
1855 }
1856
1857 ALWAYS_INLINE void tst(RegisterID rn, ARMThumbImmediate imm)
1858 {
1859 ASSERT(!BadReg(rn));
1860 ASSERT(imm.isEncodedImm());
1861
1862 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_TST_imm, rn, (RegisterID)0xf, imm);
1863 }
1864
1865 ALWAYS_INLINE void tst(RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
1866 {
1867 ASSERT(!BadReg(rn));
1868 ASSERT(!BadReg(rm));
1869 m_formatter.twoWordOp12Reg4FourFours(OP_TST_reg_T2, rn, FourFours(shift.hi4(), 0xf, shift.lo4(), rm));
1870 }
1871
1872 ALWAYS_INLINE void tst(RegisterID rn, RegisterID rm)
1873 {
1874 if ((rn | rm) & 8)
1875 tst(rn, rm, ShiftTypeAndAmount());
1876 else
1877 m_formatter.oneWordOp10Reg3Reg3(OP_TST_reg_T1, rm, rn);
1878 }
1879
1880 ALWAYS_INLINE void ubfx(RegisterID rd, RegisterID rn, unsigned lsb, unsigned width)
1881 {
1882 ASSERT(lsb < 32);
1883 ASSERT((width >= 1) && (width <= 32));
1884 ASSERT((lsb + width) <= 32);
1885 m_formatter.twoWordOp12Reg40Imm3Reg4Imm20Imm5(OP_UBFX_T1, rd, rn, (lsb & 0x1c) << 10, (lsb & 0x3) << 6, (width - 1) & 0x1f);
1886 }
1887
1888 #if CPU(APPLE_ARMV7S)
1889 ALWAYS_INLINE void udiv(RegisterID rd, RegisterID rn, RegisterID rm)
1890 {
1891 ASSERT(!BadReg(rd));
1892 ASSERT(!BadReg(rn));
1893 ASSERT(!BadReg(rm));
1894 m_formatter.twoWordOp12Reg4FourFours(OP_UDIV_T1, rn, FourFours(0xf, rd, 0xf, rm));
1895 }
1896 #endif
1897
1898 void vadd(FPDoubleRegisterID rd, FPDoubleRegisterID rn, FPDoubleRegisterID rm)
1899 {
1900 m_formatter.vfpOp(OP_VADD_T2, OP_VADD_T2b, true, rn, rd, rm);
1901 }
1902
1903 void vcmp(FPDoubleRegisterID rd, FPDoubleRegisterID rm)
1904 {
1905 m_formatter.vfpOp(OP_VCMP, OP_VCMPb, true, VFPOperand(4), rd, rm);
1906 }
1907
1908 void vcmpz(FPDoubleRegisterID rd)
1909 {
1910 m_formatter.vfpOp(OP_VCMP, OP_VCMPb, true, VFPOperand(5), rd, VFPOperand(0));
1911 }
1912
1913 void vcvt_signedToFloatingPoint(FPDoubleRegisterID rd, FPSingleRegisterID rm)
1914 {
1915 // boolean values are 64bit (toInt, unsigned, roundZero)
1916 m_formatter.vfpOp(OP_VCVT_FPIVFP, OP_VCVT_FPIVFPb, true, vcvtOp(false, false, false), rd, rm);
1917 }
1918
1919 void vcvt_floatingPointToSigned(FPSingleRegisterID rd, FPDoubleRegisterID rm)
1920 {
1921 // boolean values are 64bit (toInt, unsigned, roundZero)
1922 m_formatter.vfpOp(OP_VCVT_FPIVFP, OP_VCVT_FPIVFPb, true, vcvtOp(true, false, true), rd, rm);
1923 }
1924
1925 void vcvt_floatingPointToUnsigned(FPSingleRegisterID rd, FPDoubleRegisterID rm)
1926 {
1927 // boolean values are 64bit (toInt, unsigned, roundZero)
1928 m_formatter.vfpOp(OP_VCVT_FPIVFP, OP_VCVT_FPIVFPb, true, vcvtOp(true, true, true), rd, rm);
1929 }
1930
1931 void vdiv(FPDoubleRegisterID rd, FPDoubleRegisterID rn, FPDoubleRegisterID rm)
1932 {
1933 m_formatter.vfpOp(OP_VDIV, OP_VDIVb, true, rn, rd, rm);
1934 }
1935
1936 void vldr(FPDoubleRegisterID rd, RegisterID rn, int32_t imm)
1937 {
1938 m_formatter.vfpMemOp(OP_VLDR, OP_VLDRb, true, rn, rd, imm);
1939 }
1940
1941 void flds(FPSingleRegisterID rd, RegisterID rn, int32_t imm)
1942 {
1943 m_formatter.vfpMemOp(OP_FLDS, OP_FLDSb, false, rn, rd, imm);
1944 }
1945
1946 void vmov(RegisterID rd, FPSingleRegisterID rn)
1947 {
1948 ASSERT(!BadReg(rd));
1949 m_formatter.vfpOp(OP_VMOV_StoC, OP_VMOV_StoCb, false, rn, rd, VFPOperand(0));
1950 }
1951
1952 void vmov(FPSingleRegisterID rd, RegisterID rn)
1953 {
1954 ASSERT(!BadReg(rn));
1955 m_formatter.vfpOp(OP_VMOV_CtoS, OP_VMOV_CtoSb, false, rd, rn, VFPOperand(0));
1956 }
1957
1958 void vmov(RegisterID rd1, RegisterID rd2, FPDoubleRegisterID rn)
1959 {
1960 ASSERT(!BadReg(rd1));
1961 ASSERT(!BadReg(rd2));
1962 m_formatter.vfpOp(OP_VMOV_DtoC, OP_VMOV_DtoCb, true, rd2, VFPOperand(rd1 | 16), rn);
1963 }
1964
1965 void vmov(FPDoubleRegisterID rd, RegisterID rn1, RegisterID rn2)
1966 {
1967 ASSERT(!BadReg(rn1));
1968 ASSERT(!BadReg(rn2));
1969 m_formatter.vfpOp(OP_VMOV_CtoD, OP_VMOV_CtoDb, true, rn2, VFPOperand(rn1 | 16), rd);
1970 }
1971
1972 void vmov(FPDoubleRegisterID rd, FPDoubleRegisterID rn)
1973 {
1974 m_formatter.vfpOp(OP_VMOV_T2, OP_VMOV_T2b, true, VFPOperand(0), rd, rn);
1975 }
1976
1977 void vmrs(RegisterID reg = ARMRegisters::pc)
1978 {
1979 ASSERT(reg != ARMRegisters::sp);
1980 m_formatter.vfpOp(OP_VMRS, OP_VMRSb, false, VFPOperand(1), VFPOperand(0x10 | reg), VFPOperand(0));
1981 }
1982
1983 void vmul(FPDoubleRegisterID rd, FPDoubleRegisterID rn, FPDoubleRegisterID rm)
1984 {
1985 m_formatter.vfpOp(OP_VMUL_T2, OP_VMUL_T2b, true, rn, rd, rm);
1986 }
1987
1988 void vstr(FPDoubleRegisterID rd, RegisterID rn, int32_t imm)
1989 {
1990 m_formatter.vfpMemOp(OP_VSTR, OP_VSTRb, true, rn, rd, imm);
1991 }
1992
1993 void fsts(FPSingleRegisterID rd, RegisterID rn, int32_t imm)
1994 {
1995 m_formatter.vfpMemOp(OP_FSTS, OP_FSTSb, false, rn, rd, imm);
1996 }
1997
1998 void vsub(FPDoubleRegisterID rd, FPDoubleRegisterID rn, FPDoubleRegisterID rm)
1999 {
2000 m_formatter.vfpOp(OP_VSUB_T2, OP_VSUB_T2b, true, rn, rd, rm);
2001 }
2002
2003 void vabs(FPDoubleRegisterID rd, FPDoubleRegisterID rm)
2004 {
2005 m_formatter.vfpOp(OP_VABS_T2, OP_VABS_T2b, true, VFPOperand(16), rd, rm);
2006 }
2007
2008 void vneg(FPDoubleRegisterID rd, FPDoubleRegisterID rm)
2009 {
2010 m_formatter.vfpOp(OP_VNEG_T2, OP_VNEG_T2b, true, VFPOperand(1), rd, rm);
2011 }
2012
2013 void vsqrt(FPDoubleRegisterID rd, FPDoubleRegisterID rm)
2014 {
2015 m_formatter.vfpOp(OP_VSQRT_T1, OP_VSQRT_T1b, true, VFPOperand(17), rd, rm);
2016 }
2017
2018 void vcvtds(FPDoubleRegisterID rd, FPSingleRegisterID rm)
2019 {
2020 m_formatter.vfpOp(OP_VCVTDS_T1, OP_VCVTDS_T1b, false, VFPOperand(23), rd, rm);
2021 }
2022
2023 void vcvtsd(FPSingleRegisterID rd, FPDoubleRegisterID rm)
2024 {
2025 m_formatter.vfpOp(OP_VCVTSD_T1, OP_VCVTSD_T1b, true, VFPOperand(23), rd, rm);
2026 }
2027
2028 void nop()
2029 {
2030 m_formatter.oneWordOp8Imm8(OP_NOP_T1, 0);
2031 }
2032
2033 void nopw()
2034 {
2035 m_formatter.twoWordOp16Op16(OP_NOP_T2a, OP_NOP_T2b);
2036 }
2037
2038 void dmbSY()
2039 {
2040 m_formatter.twoWordOp16Op16(OP_DMB_SY_T2a, OP_DMB_SY_T2b);
2041 }
2042
2043 AssemblerLabel labelIgnoringWatchpoints()
2044 {
2045 return m_formatter.label();
2046 }
2047
2048 AssemblerLabel labelForWatchpoint()
2049 {
2050 AssemblerLabel result = m_formatter.label();
2051 if (static_cast<int>(result.m_offset) != m_indexOfLastWatchpoint)
2052 result = label();
2053 m_indexOfLastWatchpoint = result.m_offset;
2054 m_indexOfTailOfLastWatchpoint = result.m_offset + maxJumpReplacementSize();
2055 return result;
2056 }
2057
2058 AssemblerLabel label()
2059 {
2060 AssemblerLabel result = m_formatter.label();
2061 while (UNLIKELY(static_cast<int>(result.m_offset) < m_indexOfTailOfLastWatchpoint)) {
2062 if (UNLIKELY(static_cast<int>(result.m_offset) + 4 <= m_indexOfTailOfLastWatchpoint))
2063 nopw();
2064 else
2065 nop();
2066 result = m_formatter.label();
2067 }
2068 return result;
2069 }
2070
2071 AssemblerLabel align(int alignment)
2072 {
2073 while (!m_formatter.isAligned(alignment))
2074 bkpt();
2075
2076 return label();
2077 }
2078
2079 static void* getRelocatedAddress(void* code, AssemblerLabel label)
2080 {
2081 ASSERT(label.isSet());
2082 return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + label.m_offset);
2083 }
2084
2085 static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b)
2086 {
2087 return b.m_offset - a.m_offset;
2088 }
2089
2090 static int jumpSizeDelta(JumpType jumpType, JumpLinkType jumpLinkType) { return JUMP_ENUM_SIZE(jumpType) - JUMP_ENUM_SIZE(jumpLinkType); }
2091
2092 // Assembler admin methods:
2093
2094 static ALWAYS_INLINE bool linkRecordSourceComparator(const LinkRecord& a, const LinkRecord& b)
2095 {
2096 return a.from() < b.from();
2097 }
2098
2099 static bool canCompact(JumpType jumpType)
2100 {
2101 // The following cannot be compacted:
2102 // JumpFixed: represents custom jump sequence
2103 // JumpNoConditionFixedSize: represents unconditional jump that must remain a fixed size
2104 // JumpConditionFixedSize: represents conditional jump that must remain a fixed size
2105 return (jumpType == JumpNoCondition) || (jumpType == JumpCondition);
2106 }
2107
2108 static JumpLinkType computeJumpType(JumpType jumpType, const uint8_t* from, const uint8_t* to)
2109 {
2110 if (jumpType == JumpFixed)
2111 return LinkInvalid;
2112
2113 // for patchable jump we must leave space for the longest code sequence
2114 if (jumpType == JumpNoConditionFixedSize)
2115 return LinkBX;
2116 if (jumpType == JumpConditionFixedSize)
2117 return LinkConditionalBX;
2118
2119 const int paddingSize = JUMP_ENUM_SIZE(jumpType);
2120
2121 if (jumpType == JumpCondition) {
2122 // 2-byte conditional T1
2123 const uint16_t* jumpT1Location = reinterpret_cast_ptr<const uint16_t*>(from - (paddingSize - JUMP_ENUM_SIZE(LinkJumpT1)));
2124 if (canBeJumpT1(jumpT1Location, to))
2125 return LinkJumpT1;
2126 // 4-byte conditional T3
2127 const uint16_t* jumpT3Location = reinterpret_cast_ptr<const uint16_t*>(from - (paddingSize - JUMP_ENUM_SIZE(LinkJumpT3)));
2128 if (canBeJumpT3(jumpT3Location, to))
2129 return LinkJumpT3;
2130 // 4-byte conditional T4 with IT
2131 const uint16_t* conditionalJumpT4Location =
2132 reinterpret_cast_ptr<const uint16_t*>(from - (paddingSize - JUMP_ENUM_SIZE(LinkConditionalJumpT4)));
2133 if (canBeJumpT4(conditionalJumpT4Location, to))
2134 return LinkConditionalJumpT4;
2135 } else {
2136 // 2-byte unconditional T2
2137 const uint16_t* jumpT2Location = reinterpret_cast_ptr<const uint16_t*>(from - (paddingSize - JUMP_ENUM_SIZE(LinkJumpT2)));
2138 if (canBeJumpT2(jumpT2Location, to))
2139 return LinkJumpT2;
2140 // 4-byte unconditional T4
2141 const uint16_t* jumpT4Location = reinterpret_cast_ptr<const uint16_t*>(from - (paddingSize - JUMP_ENUM_SIZE(LinkJumpT4)));
2142 if (canBeJumpT4(jumpT4Location, to))
2143 return LinkJumpT4;
2144 // use long jump sequence
2145 return LinkBX;
2146 }
2147
2148 ASSERT(jumpType == JumpCondition);
2149 return LinkConditionalBX;
2150 }
2151
2152 static JumpLinkType computeJumpType(LinkRecord& record, const uint8_t* from, const uint8_t* to)
2153 {
2154 JumpLinkType linkType = computeJumpType(record.type(), from, to);
2155 record.setLinkType(linkType);
2156 return linkType;
2157 }
2158
2159 Vector<LinkRecord, 0, UnsafeVectorOverflow>& jumpsToLink()
2160 {
2161 std::sort(m_jumpsToLink.begin(), m_jumpsToLink.end(), linkRecordSourceComparator);
2162 return m_jumpsToLink;
2163 }
2164
2165 static void ALWAYS_INLINE link(LinkRecord& record, uint8_t* from, uint8_t* to)
2166 {
2167 switch (record.linkType()) {
2168 case LinkJumpT1:
2169 linkJumpT1(record.condition(), reinterpret_cast_ptr<uint16_t*>(from), to);
2170 break;
2171 case LinkJumpT2:
2172 linkJumpT2(reinterpret_cast_ptr<uint16_t*>(from), to);
2173 break;
2174 case LinkJumpT3:
2175 linkJumpT3(record.condition(), reinterpret_cast_ptr<uint16_t*>(from), to);
2176 break;
2177 case LinkJumpT4:
2178 linkJumpT4(reinterpret_cast_ptr<uint16_t*>(from), to);
2179 break;
2180 case LinkConditionalJumpT4:
2181 linkConditionalJumpT4(record.condition(), reinterpret_cast_ptr<uint16_t*>(from), to);
2182 break;
2183 case LinkConditionalBX:
2184 linkConditionalBX(record.condition(), reinterpret_cast_ptr<uint16_t*>(from), to);
2185 break;
2186 case LinkBX:
2187 linkBX(reinterpret_cast_ptr<uint16_t*>(from), to);
2188 break;
2189 default:
2190 RELEASE_ASSERT_NOT_REACHED();
2191 break;
2192 }
2193 }
2194
2195 void* unlinkedCode() { return m_formatter.data(); }
2196 size_t codeSize() const { return m_formatter.codeSize(); }
2197
2198 static unsigned getCallReturnOffset(AssemblerLabel call)
2199 {
2200 ASSERT(call.isSet());
2201 return call.m_offset;
2202 }
2203
2204 // Linking & patching:
2205 //
2206 // 'link' and 'patch' methods are for use on unprotected code - such as the code
2207 // within the AssemblerBuffer, and code being patched by the patch buffer. Once
2208 // code has been finalized it is (platform support permitting) within a non-
2209 // writable region of memory; to modify the code in an execute-only execuable
2210 // pool the 'repatch' and 'relink' methods should be used.
2211
2212 void linkJump(AssemblerLabel from, AssemblerLabel to, JumpType type, Condition condition)
2213 {
2214 ASSERT(to.isSet());
2215 ASSERT(from.isSet());
2216 m_jumpsToLink.append(LinkRecord(from.m_offset, to.m_offset, type, condition));
2217 }
2218
2219 static void linkJump(void* code, AssemblerLabel from, void* to)
2220 {
2221 ASSERT(from.isSet());
2222
2223 uint16_t* location = reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
2224 linkJumpAbsolute(location, to);
2225 }
2226
2227 static void linkCall(void* code, AssemblerLabel from, void* to)
2228 {
2229 ASSERT(!(reinterpret_cast<intptr_t>(code) & 1));
2230 ASSERT(from.isSet());
2231
2232 setPointer(reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code) + from.m_offset) - 1, to, false);
2233 }
2234
2235 static void linkPointer(void* code, AssemblerLabel where, void* value)
2236 {
2237 setPointer(reinterpret_cast<char*>(code) + where.m_offset, value, false);
2238 }
2239
2240 static void relinkJump(void* from, void* to)
2241 {
2242 ASSERT(!(reinterpret_cast<intptr_t>(from) & 1));
2243 ASSERT(!(reinterpret_cast<intptr_t>(to) & 1));
2244
2245 linkJumpAbsolute(reinterpret_cast<uint16_t*>(from), to);
2246
2247 cacheFlush(reinterpret_cast<uint16_t*>(from) - 5, 5 * sizeof(uint16_t));
2248 }
2249
2250 static void relinkCall(void* from, void* to)
2251 {
2252 ASSERT(!(reinterpret_cast<intptr_t>(from) & 1));
2253
2254 setPointer(reinterpret_cast<uint16_t*>(from) - 1, to, true);
2255 }
2256
2257 static void* readCallTarget(void* from)
2258 {
2259 return readPointer(reinterpret_cast<uint16_t*>(from) - 1);
2260 }
2261
2262 static void repatchInt32(void* where, int32_t value)
2263 {
2264 ASSERT(!(reinterpret_cast<intptr_t>(where) & 1));
2265
2266 setInt32(where, value, true);
2267 }
2268
2269 static void repatchCompact(void* where, int32_t offset)
2270 {
2271 ASSERT(offset >= -255 && offset <= 255);
2272
2273 bool add = true;
2274 if (offset < 0) {
2275 add = false;
2276 offset = -offset;
2277 }
2278
2279 offset |= (add << 9);
2280 offset |= (1 << 10);
2281 offset |= (1 << 11);
2282
2283 uint16_t* location = reinterpret_cast<uint16_t*>(where);
2284 location[1] &= ~((1 << 12) - 1);
2285 location[1] |= offset;
2286 cacheFlush(location, sizeof(uint16_t) * 2);
2287 }
2288
2289 static void repatchPointer(void* where, void* value)
2290 {
2291 ASSERT(!(reinterpret_cast<intptr_t>(where) & 1));
2292
2293 setPointer(where, value, true);
2294 }
2295
2296 static void* readPointer(void* where)
2297 {
2298 return reinterpret_cast<void*>(readInt32(where));
2299 }
2300
2301 static void replaceWithJump(void* instructionStart, void* to)
2302 {
2303 ASSERT(!(bitwise_cast<uintptr_t>(instructionStart) & 1));
2304 ASSERT(!(bitwise_cast<uintptr_t>(to) & 1));
2305
2306 #if OS(LINUX)
2307 if (canBeJumpT4(reinterpret_cast<uint16_t*>(instructionStart), to)) {
2308 uint16_t* ptr = reinterpret_cast<uint16_t*>(instructionStart) + 2;
2309 linkJumpT4(ptr, to);
2310 cacheFlush(ptr - 2, sizeof(uint16_t) * 2);
2311 } else {
2312 uint16_t* ptr = reinterpret_cast<uint16_t*>(instructionStart) + 5;
2313 linkBX(ptr, to);
2314 cacheFlush(ptr - 5, sizeof(uint16_t) * 5);
2315 }
2316 #else
2317 uint16_t* ptr = reinterpret_cast<uint16_t*>(instructionStart) + 2;
2318 linkJumpT4(ptr, to);
2319 cacheFlush(ptr - 2, sizeof(uint16_t) * 2);
2320 #endif
2321 }
2322
2323 static ptrdiff_t maxJumpReplacementSize()
2324 {
2325 #if OS(LINUX)
2326 return 10;
2327 #else
2328 return 4;
2329 #endif
2330 }
2331
2332 static void replaceWithLoad(void* instructionStart)
2333 {
2334 ASSERT(!(bitwise_cast<uintptr_t>(instructionStart) & 1));
2335 uint16_t* ptr = reinterpret_cast<uint16_t*>(instructionStart);
2336 switch (ptr[0] & 0xFFF0) {
2337 case OP_LDR_imm_T3:
2338 break;
2339 case OP_ADD_imm_T3:
2340 ASSERT(!(ptr[1] & 0xF000));
2341 ptr[0] &= 0x000F;
2342 ptr[0] |= OP_LDR_imm_T3;
2343 ptr[1] |= (ptr[1] & 0x0F00) << 4;
2344 ptr[1] &= 0xF0FF;
2345 cacheFlush(ptr, sizeof(uint16_t) * 2);
2346 break;
2347 default:
2348 RELEASE_ASSERT_NOT_REACHED();
2349 }
2350 }
2351
2352 static void replaceWithAddressComputation(void* instructionStart)
2353 {
2354 ASSERT(!(bitwise_cast<uintptr_t>(instructionStart) & 1));
2355 uint16_t* ptr = reinterpret_cast<uint16_t*>(instructionStart);
2356 switch (ptr[0] & 0xFFF0) {
2357 case OP_LDR_imm_T3:
2358 ASSERT(!(ptr[1] & 0x0F00));
2359 ptr[0] &= 0x000F;
2360 ptr[0] |= OP_ADD_imm_T3;
2361 ptr[1] |= (ptr[1] & 0xF000) >> 4;
2362 ptr[1] &= 0x0FFF;
2363 cacheFlush(ptr, sizeof(uint16_t) * 2);
2364 break;
2365 case OP_ADD_imm_T3:
2366 break;
2367 default:
2368 RELEASE_ASSERT_NOT_REACHED();
2369 }
2370 }
2371
2372 unsigned debugOffset() { return m_formatter.debugOffset(); }
2373
2374 #if OS(LINUX)
2375 static inline void linuxPageFlush(uintptr_t begin, uintptr_t end)
2376 {
2377 asm volatile(
2378 "push {r7}\n"
2379 "mov r0, %0\n"
2380 "mov r1, %1\n"
2381 "movw r7, #0x2\n"
2382 "movt r7, #0xf\n"
2383 "movs r2, #0x0\n"
2384 "svc 0x0\n"
2385 "pop {r7}\n"
2386 :
2387 : "r" (begin), "r" (end)
2388 : "r0", "r1", "r2");
2389 }
2390 #endif
2391
2392 static void cacheFlush(void* code, size_t size)
2393 {
2394 #if OS(IOS)
2395 sys_cache_control(kCacheFunctionPrepareForExecution, code, size);
2396 #elif OS(LINUX)
2397 size_t page = pageSize();
2398 uintptr_t current = reinterpret_cast<uintptr_t>(code);
2399 uintptr_t end = current + size;
2400 uintptr_t firstPageEnd = (current & ~(page - 1)) + page;
2401
2402 if (end <= firstPageEnd) {
2403 linuxPageFlush(current, end);
2404 return;
2405 }
2406
2407 linuxPageFlush(current, firstPageEnd);
2408
2409 for (current = firstPageEnd; current + page < end; current += page)
2410 linuxPageFlush(current, current + page);
2411
2412 linuxPageFlush(current, end);
2413 #elif OS(WINCE)
2414 CacheRangeFlush(code, size, CACHE_SYNC_ALL);
2415 #else
2416 #error "The cacheFlush support is missing on this platform."
2417 #endif
2418 }
2419
2420 private:
2421 // VFP operations commonly take one or more 5-bit operands, typically representing a
2422 // floating point register number. This will commonly be encoded in the instruction
2423 // in two parts, with one single bit field, and one 4-bit field. In the case of
2424 // double precision operands the high bit of the register number will be encoded
2425 // separately, and for single precision operands the high bit of the register number
2426 // will be encoded individually.
2427 // VFPOperand encapsulates a 5-bit VFP operand, with bits 0..3 containing the 4-bit
2428 // field to be encoded together in the instruction (the low 4-bits of a double
2429 // register number, or the high 4-bits of a single register number), and bit 4
2430 // contains the bit value to be encoded individually.
2431 struct VFPOperand {
2432 explicit VFPOperand(uint32_t value)
2433 : m_value(value)
2434 {
2435 ASSERT(!(m_value & ~0x1f));
2436 }
2437
2438 VFPOperand(FPDoubleRegisterID reg)
2439 : m_value(reg)
2440 {
2441 }
2442
2443 VFPOperand(RegisterID reg)
2444 : m_value(reg)
2445 {
2446 }
2447
2448 VFPOperand(FPSingleRegisterID reg)
2449 : m_value(((reg & 1) << 4) | (reg >> 1)) // rotate the lowest bit of 'reg' to the top.
2450 {
2451 }
2452
2453 uint32_t bits1()
2454 {
2455 return m_value >> 4;
2456 }
2457
2458 uint32_t bits4()
2459 {
2460 return m_value & 0xf;
2461 }
2462
2463 uint32_t m_value;
2464 };
2465
2466 VFPOperand vcvtOp(bool toInteger, bool isUnsigned, bool isRoundZero)
2467 {
2468 // Cannot specify rounding when converting to float.
2469 ASSERT(toInteger || !isRoundZero);
2470
2471 uint32_t op = 0x8;
2472 if (toInteger) {
2473 // opc2 indicates both toInteger & isUnsigned.
2474 op |= isUnsigned ? 0x4 : 0x5;
2475 // 'op' field in instruction is isRoundZero
2476 if (isRoundZero)
2477 op |= 0x10;
2478 } else {
2479 ASSERT(!isRoundZero);
2480 // 'op' field in instruction is isUnsigned
2481 if (!isUnsigned)
2482 op |= 0x10;
2483 }
2484 return VFPOperand(op);
2485 }
2486
2487 static void setInt32(void* code, uint32_t value, bool flush)
2488 {
2489 uint16_t* location = reinterpret_cast<uint16_t*>(code);
2490 ASSERT(isMOV_imm_T3(location - 4) && isMOVT(location - 2));
2491
2492 ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(value));
2493 ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(value >> 16));
2494 location[-4] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16);
2495 location[-3] = twoWordOp5i6Imm4Reg4EncodedImmSecond((location[-3] >> 8) & 0xf, lo16);
2496 location[-2] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16);
2497 location[-1] = twoWordOp5i6Imm4Reg4EncodedImmSecond((location[-1] >> 8) & 0xf, hi16);
2498
2499 if (flush)
2500 cacheFlush(location - 4, 4 * sizeof(uint16_t));
2501 }
2502
2503 static int32_t readInt32(void* code)
2504 {
2505 uint16_t* location = reinterpret_cast<uint16_t*>(code);
2506 ASSERT(isMOV_imm_T3(location - 4) && isMOVT(location - 2));
2507
2508 ARMThumbImmediate lo16;
2509 ARMThumbImmediate hi16;
2510 decodeTwoWordOp5i6Imm4Reg4EncodedImmFirst(lo16, location[-4]);
2511 decodeTwoWordOp5i6Imm4Reg4EncodedImmSecond(lo16, location[-3]);
2512 decodeTwoWordOp5i6Imm4Reg4EncodedImmFirst(hi16, location[-2]);
2513 decodeTwoWordOp5i6Imm4Reg4EncodedImmSecond(hi16, location[-1]);
2514 uint32_t result = hi16.asUInt16();
2515 result <<= 16;
2516 result |= lo16.asUInt16();
2517 return static_cast<int32_t>(result);
2518 }
2519
2520 static void setUInt7ForLoad(void* code, ARMThumbImmediate imm)
2521 {
2522 // Requires us to have planted a LDR_imm_T1
2523 ASSERT(imm.isValid());
2524 ASSERT(imm.isUInt7());
2525 uint16_t* location = reinterpret_cast<uint16_t*>(code);
2526 location[0] &= ~((static_cast<uint16_t>(0x7f) >> 2) << 6);
2527 location[0] |= (imm.getUInt7() >> 2) << 6;
2528 cacheFlush(location, sizeof(uint16_t));
2529 }
2530
2531 static void setPointer(void* code, void* value, bool flush)
2532 {
2533 setInt32(code, reinterpret_cast<uint32_t>(value), flush);
2534 }
2535
2536 static bool isB(void* address)
2537 {
2538 uint16_t* instruction = static_cast<uint16_t*>(address);
2539 return ((instruction[0] & 0xf800) == OP_B_T4a) && ((instruction[1] & 0xd000) == OP_B_T4b);
2540 }
2541
2542 static bool isBX(void* address)
2543 {
2544 uint16_t* instruction = static_cast<uint16_t*>(address);
2545 return (instruction[0] & 0xff87) == OP_BX;
2546 }
2547
2548 static bool isMOV_imm_T3(void* address)
2549 {
2550 uint16_t* instruction = static_cast<uint16_t*>(address);
2551 return ((instruction[0] & 0xFBF0) == OP_MOV_imm_T3) && ((instruction[1] & 0x8000) == 0);
2552 }
2553
2554 static bool isMOVT(void* address)
2555 {
2556 uint16_t* instruction = static_cast<uint16_t*>(address);
2557 return ((instruction[0] & 0xFBF0) == OP_MOVT) && ((instruction[1] & 0x8000) == 0);
2558 }
2559
2560 static bool isNOP_T1(void* address)
2561 {
2562 uint16_t* instruction = static_cast<uint16_t*>(address);
2563 return instruction[0] == OP_NOP_T1;
2564 }
2565
2566 static bool isNOP_T2(void* address)
2567 {
2568 uint16_t* instruction = static_cast<uint16_t*>(address);
2569 return (instruction[0] == OP_NOP_T2a) && (instruction[1] == OP_NOP_T2b);
2570 }
2571
2572 static bool canBeJumpT1(const uint16_t* instruction, const void* target)
2573 {
2574 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
2575 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
2576
2577 intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction));
2578 // It does not appear to be documented in the ARM ARM (big surprise), but
2579 // for OP_B_T1 the branch displacement encoded in the instruction is 2
2580 // less than the actual displacement.
2581 relative -= 2;
2582 return ((relative << 23) >> 23) == relative;
2583 }
2584
2585 static bool canBeJumpT2(const uint16_t* instruction, const void* target)
2586 {
2587 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
2588 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
2589
2590 intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction));
2591 // It does not appear to be documented in the ARM ARM (big surprise), but
2592 // for OP_B_T2 the branch displacement encoded in the instruction is 2
2593 // less than the actual displacement.
2594 relative -= 2;
2595 return ((relative << 20) >> 20) == relative;
2596 }
2597
2598 static bool canBeJumpT3(const uint16_t* instruction, const void* target)
2599 {
2600 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
2601 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
2602
2603 intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction));
2604 return ((relative << 11) >> 11) == relative;
2605 }
2606
2607 static bool canBeJumpT4(const uint16_t* instruction, const void* target)
2608 {
2609 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
2610 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
2611
2612 intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction));
2613 return ((relative << 7) >> 7) == relative;
2614 }
2615
2616 static void linkJumpT1(Condition cond, uint16_t* instruction, void* target)
2617 {
2618 // FIMXE: this should be up in the MacroAssembler layer. :-(
2619 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
2620 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
2621 ASSERT(canBeJumpT1(instruction, target));
2622
2623 intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction));
2624 // It does not appear to be documented in the ARM ARM (big surprise), but
2625 // for OP_B_T1 the branch displacement encoded in the instruction is 2
2626 // less than the actual displacement.
2627 relative -= 2;
2628
2629 // All branch offsets should be an even distance.
2630 ASSERT(!(relative & 1));
2631 instruction[-1] = OP_B_T1 | ((cond & 0xf) << 8) | ((relative & 0x1fe) >> 1);
2632 }
2633
2634 static void linkJumpT2(uint16_t* instruction, void* target)
2635 {
2636 // FIMXE: this should be up in the MacroAssembler layer. :-(
2637 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
2638 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
2639 ASSERT(canBeJumpT2(instruction, target));
2640
2641 intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction));
2642 // It does not appear to be documented in the ARM ARM (big surprise), but
2643 // for OP_B_T2 the branch displacement encoded in the instruction is 2
2644 // less than the actual displacement.
2645 relative -= 2;
2646
2647 // All branch offsets should be an even distance.
2648 ASSERT(!(relative & 1));
2649 instruction[-1] = OP_B_T2 | ((relative & 0xffe) >> 1);
2650 }
2651
2652 static void linkJumpT3(Condition cond, uint16_t* instruction, void* target)
2653 {
2654 // FIMXE: this should be up in the MacroAssembler layer. :-(
2655 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
2656 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
2657 ASSERT(canBeJumpT3(instruction, target));
2658
2659 intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction));
2660
2661 // All branch offsets should be an even distance.
2662 ASSERT(!(relative & 1));
2663 instruction[-2] = OP_B_T3a | ((relative & 0x100000) >> 10) | ((cond & 0xf) << 6) | ((relative & 0x3f000) >> 12);
2664 instruction[-1] = OP_B_T3b | ((relative & 0x80000) >> 8) | ((relative & 0x40000) >> 5) | ((relative & 0xffe) >> 1);
2665 }
2666
2667 static void linkJumpT4(uint16_t* instruction, void* target)
2668 {
2669 // FIMXE: this should be up in the MacroAssembler layer. :-(
2670 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
2671 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
2672 ASSERT(canBeJumpT4(instruction, target));
2673
2674 intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction));
2675 // ARM encoding for the top two bits below the sign bit is 'peculiar'.
2676 if (relative >= 0)
2677 relative ^= 0xC00000;
2678
2679 // All branch offsets should be an even distance.
2680 ASSERT(!(relative & 1));
2681 instruction[-2] = OP_B_T4a | ((relative & 0x1000000) >> 14) | ((relative & 0x3ff000) >> 12);
2682 instruction[-1] = OP_B_T4b | ((relative & 0x800000) >> 10) | ((relative & 0x400000) >> 11) | ((relative & 0xffe) >> 1);
2683 }
2684
2685 static void linkConditionalJumpT4(Condition cond, uint16_t* instruction, void* target)
2686 {
2687 // FIMXE: this should be up in the MacroAssembler layer. :-(
2688 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
2689 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
2690
2691 instruction[-3] = ifThenElse(cond) | OP_IT;
2692 linkJumpT4(instruction, target);
2693 }
2694
2695 static void linkBX(uint16_t* instruction, void* target)
2696 {
2697 // FIMXE: this should be up in the MacroAssembler layer. :-(
2698 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
2699 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
2700
2701 const uint16_t JUMP_TEMPORARY_REGISTER = ARMRegisters::ip;
2702 ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) + 1));
2703 ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) >> 16));
2704 instruction[-5] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16);
2705 instruction[-4] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, lo16);
2706 instruction[-3] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16);
2707 instruction[-2] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, hi16);
2708 instruction[-1] = OP_BX | (JUMP_TEMPORARY_REGISTER << 3);
2709 }
2710
2711 static void linkConditionalBX(Condition cond, uint16_t* instruction, void* target)
2712 {
2713 // FIMXE: this should be up in the MacroAssembler layer. :-(
2714 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
2715 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
2716
2717 linkBX(instruction, target);
2718 instruction[-6] = ifThenElse(cond, true, true) | OP_IT;
2719 }
2720
2721 static void linkJumpAbsolute(uint16_t* instruction, void* target)
2722 {
2723 // FIMXE: this should be up in the MacroAssembler layer. :-(
2724 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
2725 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
2726
2727 ASSERT((isMOV_imm_T3(instruction - 5) && isMOVT(instruction - 3) && isBX(instruction - 1))
2728 || (isNOP_T1(instruction - 5) && isNOP_T2(instruction - 4) && isB(instruction - 2)));
2729
2730 if (canBeJumpT4(instruction, target)) {
2731 // There may be a better way to fix this, but right now put the NOPs first, since in the
2732 // case of an conditional branch this will be coming after an ITTT predicating *three*
2733 // instructions! Looking backwards to modify the ITTT to an IT is not easy, due to
2734 // variable wdith encoding - the previous instruction might *look* like an ITTT but
2735 // actually be the second half of a 2-word op.
2736 instruction[-5] = OP_NOP_T1;
2737 instruction[-4] = OP_NOP_T2a;
2738 instruction[-3] = OP_NOP_T2b;
2739 linkJumpT4(instruction, target);
2740 } else {
2741 const uint16_t JUMP_TEMPORARY_REGISTER = ARMRegisters::ip;
2742 ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) + 1));
2743 ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) >> 16));
2744 instruction[-5] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16);
2745 instruction[-4] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, lo16);
2746 instruction[-3] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16);
2747 instruction[-2] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, hi16);
2748 instruction[-1] = OP_BX | (JUMP_TEMPORARY_REGISTER << 3);
2749 }
2750 }
2751
2752 static uint16_t twoWordOp5i6Imm4Reg4EncodedImmFirst(uint16_t op, ARMThumbImmediate imm)
2753 {
2754 return op | (imm.m_value.i << 10) | imm.m_value.imm4;
2755 }
2756
2757 static void decodeTwoWordOp5i6Imm4Reg4EncodedImmFirst(ARMThumbImmediate& result, uint16_t value)
2758 {
2759 result.m_value.i = (value >> 10) & 1;
2760 result.m_value.imm4 = value & 15;
2761 }
2762
2763 static uint16_t twoWordOp5i6Imm4Reg4EncodedImmSecond(uint16_t rd, ARMThumbImmediate imm)
2764 {
2765 return (imm.m_value.imm3 << 12) | (rd << 8) | imm.m_value.imm8;
2766 }
2767
2768 static void decodeTwoWordOp5i6Imm4Reg4EncodedImmSecond(ARMThumbImmediate& result, uint16_t value)
2769 {
2770 result.m_value.imm3 = (value >> 12) & 7;
2771 result.m_value.imm8 = value & 255;
2772 }
2773
2774 class ARMInstructionFormatter {
2775 public:
2776 ALWAYS_INLINE void oneWordOp5Reg3Imm8(OpcodeID op, RegisterID rd, uint8_t imm)
2777 {
2778 m_buffer.putShort(op | (rd << 8) | imm);
2779 }
2780
2781 ALWAYS_INLINE void oneWordOp5Imm5Reg3Reg3(OpcodeID op, uint8_t imm, RegisterID reg1, RegisterID reg2)
2782 {
2783 m_buffer.putShort(op | (imm << 6) | (reg1 << 3) | reg2);
2784 }
2785
2786 ALWAYS_INLINE void oneWordOp7Reg3Reg3Reg3(OpcodeID op, RegisterID reg1, RegisterID reg2, RegisterID reg3)
2787 {
2788 m_buffer.putShort(op | (reg1 << 6) | (reg2 << 3) | reg3);
2789 }
2790
2791 ALWAYS_INLINE void oneWordOp7Imm9(OpcodeID op, uint16_t imm)
2792 {
2793 m_buffer.putShort(op | imm);
2794 }
2795
2796 ALWAYS_INLINE void oneWordOp8Imm8(OpcodeID op, uint8_t imm)
2797 {
2798 m_buffer.putShort(op | imm);
2799 }
2800
2801 ALWAYS_INLINE void oneWordOp8RegReg143(OpcodeID op, RegisterID reg1, RegisterID reg2)
2802 {
2803 m_buffer.putShort(op | ((reg2 & 8) << 4) | (reg1 << 3) | (reg2 & 7));
2804 }
2805
2806 ALWAYS_INLINE void oneWordOp9Imm7(OpcodeID op, uint8_t imm)
2807 {
2808 m_buffer.putShort(op | imm);
2809 }
2810
2811 ALWAYS_INLINE void oneWordOp10Reg3Reg3(OpcodeID op, RegisterID reg1, RegisterID reg2)
2812 {
2813 m_buffer.putShort(op | (reg1 << 3) | reg2);
2814 }
2815
2816 ALWAYS_INLINE void twoWordOp12Reg4FourFours(OpcodeID1 op, RegisterID reg, FourFours ff)
2817 {
2818 m_buffer.putShort(op | reg);
2819 m_buffer.putShort(ff.m_u.value);
2820 }
2821
2822 ALWAYS_INLINE void twoWordOp16FourFours(OpcodeID1 op, FourFours ff)
2823 {
2824 m_buffer.putShort(op);
2825 m_buffer.putShort(ff.m_u.value);
2826 }
2827
2828 ALWAYS_INLINE void twoWordOp16Op16(OpcodeID1 op1, OpcodeID2 op2)
2829 {
2830 m_buffer.putShort(op1);
2831 m_buffer.putShort(op2);
2832 }
2833
2834 ALWAYS_INLINE void twoWordOp16Imm16(OpcodeID1 op1, uint16_t imm)
2835 {
2836 m_buffer.putShort(op1);
2837 m_buffer.putShort(imm);
2838 }
2839
2840 ALWAYS_INLINE void twoWordOp5i6Imm4Reg4EncodedImm(OpcodeID1 op, int imm4, RegisterID rd, ARMThumbImmediate imm)
2841 {
2842 ARMThumbImmediate newImm = imm;
2843 newImm.m_value.imm4 = imm4;
2844
2845 m_buffer.putShort(ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmFirst(op, newImm));
2846 m_buffer.putShort(ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmSecond(rd, newImm));
2847 }
2848
2849 ALWAYS_INLINE void twoWordOp12Reg4Reg4Imm12(OpcodeID1 op, RegisterID reg1, RegisterID reg2, uint16_t imm)
2850 {
2851 m_buffer.putShort(op | reg1);
2852 m_buffer.putShort((reg2 << 12) | imm);
2853 }
2854
2855 ALWAYS_INLINE void twoWordOp12Reg40Imm3Reg4Imm20Imm5(OpcodeID1 op, RegisterID reg1, RegisterID reg2, uint16_t imm1, uint16_t imm2, uint16_t imm3)
2856 {
2857 m_buffer.putShort(op | reg1);
2858 m_buffer.putShort((imm1 << 12) | (reg2 << 8) | (imm2 << 6) | imm3);
2859 }
2860
2861 // Formats up instructions of the pattern:
2862 // 111111111B11aaaa:bbbb222SA2C2cccc
2863 // Where 1s in the pattern come from op1, 2s in the pattern come from op2, S is the provided size bit.
2864 // Operands provide 5 bit values of the form Aaaaa, Bbbbb, Ccccc.
2865 ALWAYS_INLINE void vfpOp(OpcodeID1 op1, OpcodeID2 op2, bool size, VFPOperand a, VFPOperand b, VFPOperand c)
2866 {
2867 ASSERT(!(op1 & 0x004f));
2868 ASSERT(!(op2 & 0xf1af));
2869 m_buffer.putShort(op1 | b.bits1() << 6 | a.bits4());
2870 m_buffer.putShort(op2 | b.bits4() << 12 | size << 8 | a.bits1() << 7 | c.bits1() << 5 | c.bits4());
2871 }
2872
2873 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
2874 // (i.e. +/-(0..255) 32-bit words)
2875 ALWAYS_INLINE void vfpMemOp(OpcodeID1 op1, OpcodeID2 op2, bool size, RegisterID rn, VFPOperand rd, int32_t imm)
2876 {
2877 bool up = true;
2878 if (imm < 0) {
2879 imm = -imm;
2880 up = false;
2881 }
2882
2883 uint32_t offset = imm;
2884 ASSERT(!(offset & ~0x3fc));
2885 offset >>= 2;
2886
2887 m_buffer.putShort(op1 | (up << 7) | rd.bits1() << 6 | rn);
2888 m_buffer.putShort(op2 | rd.bits4() << 12 | size << 8 | offset);
2889 }
2890
2891 // Administrative methods:
2892
2893 size_t codeSize() const { return m_buffer.codeSize(); }
2894 AssemblerLabel label() const { return m_buffer.label(); }
2895 bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); }
2896 void* data() const { return m_buffer.data(); }
2897
2898 unsigned debugOffset() { return m_buffer.debugOffset(); }
2899
2900 AssemblerBuffer m_buffer;
2901 } m_formatter;
2902
2903 Vector<LinkRecord, 0, UnsafeVectorOverflow> m_jumpsToLink;
2904 int m_indexOfLastWatchpoint;
2905 int m_indexOfTailOfLastWatchpoint;
2906 };
2907
2908 } // namespace JSC
2909
2910 #endif // ENABLE(ASSEMBLER) && CPU(ARM_THUMB2)
2911
2912 #endif // ARMAssembler_h