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