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