]> git.saurik.com Git - apple/javascriptcore.git/blob - assembler/ARMv7Assembler.h
7cf88736c74923c93ba15a727a5a92a2437a74ec
[apple/javascriptcore.git] / assembler / ARMv7Assembler.h
1 /*
2 * Copyright (C) 2009 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #ifndef ARMAssembler_h
27 #define ARMAssembler_h
28
29 #include <wtf/Platform.h>
30
31 #if ENABLE(ASSEMBLER) && PLATFORM_ARM_ARCH(7)
32
33 #include "AssemblerBuffer.h"
34 #include <wtf/Assertions.h>
35 #include <wtf/Vector.h>
36 #include <stdint.h>
37
38 namespace JSC {
39
40 namespace ARM {
41 typedef enum {
42 r0,
43 r1,
44 r2,
45 r3,
46 r4,
47 r5,
48 r6,
49 r7, wr = r7, // thumb work register
50 r8,
51 r9, sb = r9, // static base
52 r10, sl = r10, // stack limit
53 r11, fp = r11, // frame pointer
54 r12, ip = r12,
55 r13, sp = r13,
56 r14, lr = r14,
57 r15, pc = r15,
58 } RegisterID;
59
60 // s0 == d0 == q0
61 // s4 == d2 == q1
62 // etc
63 typedef enum {
64 s0 = 0,
65 s1 = 1,
66 s2 = 2,
67 s3 = 3,
68 s4 = 4,
69 s5 = 5,
70 s6 = 6,
71 s7 = 7,
72 s8 = 8,
73 s9 = 9,
74 s10 = 10,
75 s11 = 11,
76 s12 = 12,
77 s13 = 13,
78 s14 = 14,
79 s15 = 15,
80 s16 = 16,
81 s17 = 17,
82 s18 = 18,
83 s19 = 19,
84 s20 = 20,
85 s21 = 21,
86 s22 = 22,
87 s23 = 23,
88 s24 = 24,
89 s25 = 25,
90 s26 = 26,
91 s27 = 27,
92 s28 = 28,
93 s29 = 29,
94 s30 = 30,
95 s31 = 31,
96 d0 = 0 << 1,
97 d1 = 1 << 1,
98 d2 = 2 << 1,
99 d3 = 3 << 1,
100 d4 = 4 << 1,
101 d5 = 5 << 1,
102 d6 = 6 << 1,
103 d7 = 7 << 1,
104 d8 = 8 << 1,
105 d9 = 9 << 1,
106 d10 = 10 << 1,
107 d11 = 11 << 1,
108 d12 = 12 << 1,
109 d13 = 13 << 1,
110 d14 = 14 << 1,
111 d15 = 15 << 1,
112 d16 = 16 << 1,
113 d17 = 17 << 1,
114 d18 = 18 << 1,
115 d19 = 19 << 1,
116 d20 = 20 << 1,
117 d21 = 21 << 1,
118 d22 = 22 << 1,
119 d23 = 23 << 1,
120 d24 = 24 << 1,
121 d25 = 25 << 1,
122 d26 = 26 << 1,
123 d27 = 27 << 1,
124 d28 = 28 << 1,
125 d29 = 29 << 1,
126 d30 = 30 << 1,
127 d31 = 31 << 1,
128 q0 = 0 << 2,
129 q1 = 1 << 2,
130 q2 = 2 << 2,
131 q3 = 3 << 2,
132 q4 = 4 << 2,
133 q5 = 5 << 2,
134 q6 = 6 << 2,
135 q7 = 7 << 2,
136 q8 = 8 << 2,
137 q9 = 9 << 2,
138 q10 = 10 << 2,
139 q11 = 11 << 2,
140 q12 = 12 << 2,
141 q13 = 13 << 2,
142 q14 = 14 << 2,
143 q15 = 15 << 2,
144 q16 = 16 << 2,
145 q17 = 17 << 2,
146 q18 = 18 << 2,
147 q19 = 19 << 2,
148 q20 = 20 << 2,
149 q21 = 21 << 2,
150 q22 = 22 << 2,
151 q23 = 23 << 2,
152 q24 = 24 << 2,
153 q25 = 25 << 2,
154 q26 = 26 << 2,
155 q27 = 27 << 2,
156 q28 = 28 << 2,
157 q29 = 29 << 2,
158 q30 = 30 << 2,
159 q31 = 31 << 2,
160 } FPRegisterID;
161 }
162
163 class ARMv7Assembler;
164 class ARMThumbImmediate {
165 friend class ARMv7Assembler;
166
167 typedef uint8_t ThumbImmediateType;
168 static const ThumbImmediateType TypeInvalid = 0;
169 static const ThumbImmediateType TypeEncoded = 1;
170 static const ThumbImmediateType TypeUInt16 = 2;
171
172 typedef union {
173 int16_t asInt;
174 struct {
175 unsigned imm8 : 8;
176 unsigned imm3 : 3;
177 unsigned i : 1;
178 unsigned imm4 : 4;
179 };
180 // If this is an encoded immediate, then it may describe a shift, or a pattern.
181 struct {
182 unsigned shiftValue7 : 7;
183 unsigned shiftAmount : 5;
184 };
185 struct {
186 unsigned immediate : 8;
187 unsigned pattern : 4;
188 };
189 } ThumbImmediateValue;
190
191 // byte0 contains least significant bit; not using an array to make client code endian agnostic.
192 typedef union {
193 int32_t asInt;
194 struct {
195 uint8_t byte0;
196 uint8_t byte1;
197 uint8_t byte2;
198 uint8_t byte3;
199 };
200 } PatternBytes;
201
202 ALWAYS_INLINE static int32_t countLeadingZerosPartial(uint32_t& value, int32_t& zeros, const int N)
203 {
204 if (value & ~((1<<N)-1)) /* check for any of the top N bits (of 2N bits) are set */ \
205 value >>= N; /* if any were set, lose the bottom N */ \
206 else /* if none of the top N bits are set, */ \
207 zeros += N; /* then we have identified N leading zeros */
208 }
209
210 static int32_t countLeadingZeros(uint32_t value)
211 {
212 if (!value)
213 return 32;
214
215 int32_t zeros = 0;
216 countLeadingZerosPartial(value, zeros, 16);
217 countLeadingZerosPartial(value, zeros, 8);
218 countLeadingZerosPartial(value, zeros, 4);
219 countLeadingZerosPartial(value, zeros, 2);
220 countLeadingZerosPartial(value, zeros, 1);
221 return zeros;
222 }
223
224 ARMThumbImmediate()
225 : m_type(TypeInvalid)
226 {
227 m_value.asInt = 0;
228 }
229
230 ARMThumbImmediate(ThumbImmediateType type, ThumbImmediateValue value)
231 : m_type(type)
232 , m_value(value)
233 {
234 }
235
236 ARMThumbImmediate(ThumbImmediateType type, uint16_t value)
237 : m_type(TypeUInt16)
238 {
239 m_value.asInt = value;
240 }
241
242 public:
243 static ARMThumbImmediate makeEncodedImm(uint32_t value)
244 {
245 ThumbImmediateValue encoding;
246 encoding.asInt = 0;
247
248 // okay, these are easy.
249 if (value < 256) {
250 encoding.immediate = value;
251 encoding.pattern = 0;
252 return ARMThumbImmediate(TypeEncoded, encoding);
253 }
254
255 int32_t leadingZeros = countLeadingZeros(value);
256 // if there were 24 or more leading zeros, then we'd have hit the (value < 256) case.
257 ASSERT(leadingZeros < 24);
258
259 // Given a number with bit fields Z:B:C, where count(Z)+count(B)+count(C) == 32,
260 // Z are the bits known zero, B is the 8-bit immediate, C are the bits to check for
261 // zero. count(B) == 8, so the count of bits to be checked is 24 - count(Z).
262 int32_t rightShiftAmount = 24 - leadingZeros;
263 if (value == ((value >> rightShiftAmount) << rightShiftAmount)) {
264 // Shift the value down to the low byte position. The assign to
265 // shiftValue7 drops the implicit top bit.
266 encoding.shiftValue7 = value >> rightShiftAmount;
267 // The endoded shift amount is the magnitude of a right rotate.
268 encoding.shiftAmount = 8 + leadingZeros;
269 return ARMThumbImmediate(TypeEncoded, encoding);
270 }
271
272 PatternBytes bytes;
273 bytes.asInt = value;
274
275 if ((bytes.byte0 == bytes.byte1) && (bytes.byte0 == bytes.byte2) && (bytes.byte0 == bytes.byte3)) {
276 encoding.immediate = bytes.byte0;
277 encoding.pattern = 3;
278 return ARMThumbImmediate(TypeEncoded, encoding);
279 }
280
281 if ((bytes.byte0 == bytes.byte2) && !(bytes.byte1 | bytes.byte3)) {
282 encoding.immediate = bytes.byte0;
283 encoding.pattern = 1;
284 return ARMThumbImmediate(TypeEncoded, encoding);
285 }
286
287 if ((bytes.byte1 == bytes.byte3) && !(bytes.byte0 | bytes.byte2)) {
288 encoding.immediate = bytes.byte0;
289 encoding.pattern = 2;
290 return ARMThumbImmediate(TypeEncoded, encoding);
291 }
292
293 return ARMThumbImmediate();
294 }
295
296 static ARMThumbImmediate makeUInt12(int32_t value)
297 {
298 return (!(value & 0xfffff000))
299 ? ARMThumbImmediate(TypeUInt16, (uint16_t)value)
300 : ARMThumbImmediate();
301 }
302
303 static ARMThumbImmediate makeUInt12OrEncodedImm(int32_t value)
304 {
305 // If this is not a 12-bit unsigned it, try making an encoded immediate.
306 return (!(value & 0xfffff000))
307 ? ARMThumbImmediate(TypeUInt16, (uint16_t)value)
308 : makeEncodedImm(value);
309 }
310
311 // The 'make' methods, above, return a !isValid() value if the argument
312 // cannot be represented as the requested type. This methods is called
313 // 'get' since the argument can always be represented.
314 static ARMThumbImmediate makeUInt16(uint16_t value)
315 {
316 return ARMThumbImmediate(TypeUInt16, value);
317 }
318
319 bool isValid()
320 {
321 return m_type != TypeInvalid;
322 }
323
324 // These methods rely on the format of encoded byte values.
325 bool isUInt3() { return !(m_value.asInt & 0xfff8); }
326 bool isUInt4() { return !(m_value.asInt & 0xfff0); }
327 bool isUInt5() { return !(m_value.asInt & 0xffe0); }
328 bool isUInt6() { return !(m_value.asInt & 0xffc0); }
329 bool isUInt7() { return !(m_value.asInt & 0xff80); }
330 bool isUInt8() { return !(m_value.asInt & 0xff00); }
331 bool isUInt9() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xfe00); }
332 bool isUInt10() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xfc00); }
333 bool isUInt12() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xf000); }
334 bool isUInt16() { return m_type == TypeUInt16; }
335 uint8_t getUInt3() { ASSERT(isUInt3()); return m_value.asInt; }
336 uint8_t getUInt4() { ASSERT(isUInt4()); return m_value.asInt; }
337 uint8_t getUInt5() { ASSERT(isUInt5()); return m_value.asInt; }
338 uint8_t getUInt6() { ASSERT(isUInt6()); return m_value.asInt; }
339 uint8_t getUInt7() { ASSERT(isUInt7()); return m_value.asInt; }
340 uint8_t getUInt8() { ASSERT(isUInt8()); return m_value.asInt; }
341 uint8_t getUInt9() { ASSERT(isUInt9()); return m_value.asInt; }
342 uint8_t getUInt10() { ASSERT(isUInt10()); return m_value.asInt; }
343 uint16_t getUInt12() { ASSERT(isUInt12()); return m_value.asInt; }
344 uint16_t getUInt16() { ASSERT(isUInt16()); return m_value.asInt; }
345
346 bool isEncodedImm() { return m_type == TypeEncoded; }
347
348 private:
349 ThumbImmediateType m_type;
350 ThumbImmediateValue m_value;
351 };
352
353
354 typedef enum {
355 SRType_LSL,
356 SRType_LSR,
357 SRType_ASR,
358 SRType_ROR,
359
360 SRType_RRX = SRType_ROR
361 } ARMShiftType;
362
363 class ARMv7Assembler;
364 class ShiftTypeAndAmount {
365 friend class ARMv7Assembler;
366
367 public:
368 ShiftTypeAndAmount()
369 {
370 m_u.type = (ARMShiftType)0;
371 m_u.amount = 0;
372 }
373
374 ShiftTypeAndAmount(ARMShiftType type, unsigned amount)
375 {
376 m_u.type = type;
377 m_u.amount = amount & 31;
378 }
379
380 unsigned lo4() { return m_u.lo4; }
381 unsigned hi4() { return m_u.hi4; }
382
383 private:
384 union {
385 struct {
386 unsigned lo4 : 4;
387 unsigned hi4 : 4;
388 };
389 struct {
390 unsigned type : 2;
391 unsigned amount : 5;
392 };
393 } m_u;
394 };
395
396
397 /*
398 Some features of the Thumb instruction set are deprecated in ARMv7. Deprecated features affecting
399 instructions supported by ARMv7-M are as follows:
400 • use of the PC as <Rd> or <Rm> in a 16-bit ADD (SP plus register) instruction
401 • use of the SP as <Rm> in a 16-bit ADD (SP plus register) instruction
402 • use of the SP as <Rm> in a 16-bit CMP (register) instruction
403 • use of MOV (register) instructions in which <Rd> is the SP or PC and <Rm> is also the SP or PC.
404 • use of <Rn> as the lowest-numbered register in the register list of a 16-bit STM instruction with base
405 register writeback
406 */
407
408 class ARMv7Assembler {
409 public:
410 typedef ARM::RegisterID RegisterID;
411 typedef ARM::FPRegisterID FPRegisterID;
412
413 // (HS, LO, HI, LS) -> (AE, B, A, BE)
414 // (VS, VC) -> (O, NO)
415 typedef enum {
416 ConditionEQ,
417 ConditionNE,
418 ConditionHS,
419 ConditionLO,
420 ConditionMI,
421 ConditionPL,
422 ConditionVS,
423 ConditionVC,
424 ConditionHI,
425 ConditionLS,
426 ConditionGE,
427 ConditionLT,
428 ConditionGT,
429 ConditionLE,
430 ConditionAL,
431
432 ConditionCS = ConditionHS,
433 ConditionCC = ConditionLO,
434 } Condition;
435
436 class JmpSrc {
437 friend class ARMv7Assembler;
438 friend class ARMInstructionFormatter;
439 public:
440 JmpSrc()
441 : m_offset(-1)
442 {
443 }
444
445 private:
446 JmpSrc(int offset)
447 : m_offset(offset)
448 {
449 }
450
451 int m_offset;
452 };
453
454 class JmpDst {
455 friend class ARMv7Assembler;
456 friend class ARMInstructionFormatter;
457 public:
458 JmpDst()
459 : m_offset(-1)
460 , m_used(false)
461 {
462 }
463
464 bool isUsed() const { return m_used; }
465 void used() { m_used = true; }
466 private:
467 JmpDst(int offset)
468 : m_offset(offset)
469 , m_used(false)
470 {
471 ASSERT(m_offset == offset);
472 }
473
474 int m_offset : 31;
475 int m_used : 1;
476 };
477
478 private:
479
480 // ARMv7, Appx-A.6.3
481 bool BadReg(RegisterID reg)
482 {
483 return (reg == ARM::sp) || (reg == ARM::pc);
484 }
485
486 bool isSingleRegister(FPRegisterID reg)
487 {
488 // Check that the high bit isn't set (q16+), and that the low bit isn't (s1, s3, etc).
489 return !(reg & ~31);
490 }
491
492 bool isDoubleRegister(FPRegisterID reg)
493 {
494 // Check that the high bit isn't set (q16+), and that the low bit isn't (s1, s3, etc).
495 return !(reg & ~(31 << 1));
496 }
497
498 bool isQuadRegister(FPRegisterID reg)
499 {
500 return !(reg & ~(31 << 2));
501 }
502
503 uint32_t singleRegisterNum(FPRegisterID reg)
504 {
505 ASSERT(isSingleRegister(reg));
506 return reg;
507 }
508
509 uint32_t doubleRegisterNum(FPRegisterID reg)
510 {
511 ASSERT(isDoubleRegister(reg));
512 return reg >> 1;
513 }
514
515 uint32_t quadRegisterNum(FPRegisterID reg)
516 {
517 ASSERT(isQuadRegister(reg));
518 return reg >> 2;
519 }
520
521 uint32_t singleRegisterMask(FPRegisterID rd, int highBitsShift, int lowBitShift)
522 {
523 uint32_t rdNum = singleRegisterNum(rd);
524 uint32_t rdMask = (rdNum >> 1) << highBitsShift;
525 if (rdNum & 1)
526 rdMask |= 1 << lowBitShift;
527 return rdMask;
528 }
529
530 uint32_t doubleRegisterMask(FPRegisterID rd, int highBitShift, int lowBitsShift)
531 {
532 uint32_t rdNum = doubleRegisterNum(rd);
533 uint32_t rdMask = (rdNum & 0xf) << lowBitsShift;
534 if (rdNum & 16)
535 rdMask |= 1 << highBitShift;
536 return rdMask;
537 }
538
539 typedef enum {
540 OP_ADD_reg_T1 = 0x1800,
541 OP_ADD_S_reg_T1 = 0x1800,
542 OP_SUB_reg_T1 = 0x1A00,
543 OP_SUB_S_reg_T1 = 0x1A00,
544 OP_ADD_imm_T1 = 0x1C00,
545 OP_ADD_S_imm_T1 = 0x1C00,
546 OP_SUB_imm_T1 = 0x1E00,
547 OP_SUB_S_imm_T1 = 0x1E00,
548 OP_MOV_imm_T1 = 0x2000,
549 OP_CMP_imm_T1 = 0x2800,
550 OP_ADD_imm_T2 = 0x3000,
551 OP_ADD_S_imm_T2 = 0x3000,
552 OP_SUB_imm_T2 = 0x3800,
553 OP_SUB_S_imm_T2 = 0x3800,
554 OP_AND_reg_T1 = 0x4000,
555 OP_EOR_reg_T1 = 0x4040,
556 OP_TST_reg_T1 = 0x4200,
557 OP_CMP_reg_T1 = 0x4280,
558 OP_ORR_reg_T1 = 0x4300,
559 OP_MVN_reg_T1 = 0x43C0,
560 OP_ADD_reg_T2 = 0x4400,
561 OP_MOV_reg_T1 = 0x4600,
562 OP_BLX = 0x4700,
563 OP_BX = 0x4700,
564 OP_LDRH_reg_T1 = 0x5A00,
565 OP_STR_reg_T1 = 0x5000,
566 OP_LDR_reg_T1 = 0x5800,
567 OP_STR_imm_T1 = 0x6000,
568 OP_LDR_imm_T1 = 0x6800,
569 OP_LDRH_imm_T1 = 0x8800,
570 OP_STR_imm_T2 = 0x9000,
571 OP_LDR_imm_T2 = 0x9800,
572 OP_ADD_SP_imm_T1 = 0xA800,
573 OP_ADD_SP_imm_T2 = 0xB000,
574 OP_SUB_SP_imm_T1 = 0xB080,
575 OP_BKPT = 0xBE00,
576 OP_IT = 0xBF00,
577 } OpcodeID;
578
579 typedef enum {
580 OP_AND_reg_T2 = 0xEA00,
581 OP_TST_reg_T2 = 0xEA10,
582 OP_ORR_reg_T2 = 0xEA40,
583 OP_ASR_imm_T1 = 0xEA4F,
584 OP_LSL_imm_T1 = 0xEA4F,
585 OP_LSR_imm_T1 = 0xEA4F,
586 OP_ROR_imm_T1 = 0xEA4F,
587 OP_MVN_reg_T2 = 0xEA6F,
588 OP_EOR_reg_T2 = 0xEA80,
589 OP_ADD_reg_T3 = 0xEB00,
590 OP_ADD_S_reg_T3 = 0xEB10,
591 OP_SUB_reg_T2 = 0xEBA0,
592 OP_SUB_S_reg_T2 = 0xEBB0,
593 OP_CMP_reg_T2 = 0xEBB0,
594 OP_B_T4a = 0xF000,
595 OP_AND_imm_T1 = 0xF000,
596 OP_TST_imm = 0xF010,
597 OP_ORR_imm_T1 = 0xF040,
598 OP_MOV_imm_T2 = 0xF040,
599 OP_MVN_imm = 0xF060,
600 OP_EOR_imm_T1 = 0xF080,
601 OP_ADD_imm_T3 = 0xF100,
602 OP_ADD_S_imm_T3 = 0xF110,
603 OP_CMN_imm = 0xF110,
604 OP_SUB_imm_T3 = 0xF1A0,
605 OP_SUB_S_imm_T3 = 0xF1B0,
606 OP_CMP_imm_T2 = 0xF1B0,
607 OP_ADD_imm_T4 = 0xF200,
608 OP_MOV_imm_T3 = 0xF240,
609 OP_SUB_imm_T4 = 0xF2A0,
610 OP_MOVT = 0xF2C0,
611 OP_LDRH_reg_T2 = 0xF830,
612 OP_LDRH_imm_T3 = 0xF830,
613 OP_STR_imm_T4 = 0xF840,
614 OP_STR_reg_T2 = 0xF840,
615 OP_LDR_imm_T4 = 0xF850,
616 OP_LDR_reg_T2 = 0xF850,
617 OP_LDRH_imm_T2 = 0xF8B0,
618 OP_STR_imm_T3 = 0xF8C0,
619 OP_LDR_imm_T3 = 0xF8D0,
620 OP_LSL_reg_T2 = 0xFA00,
621 OP_LSR_reg_T2 = 0xFA20,
622 OP_ASR_reg_T2 = 0xFA40,
623 OP_ROR_reg_T2 = 0xFA60,
624 OP_SMULL_T1 = 0xFB80,
625 } OpcodeID1;
626
627 typedef enum {
628 OP_B_T4b = 0x9000,
629 } OpcodeID2;
630
631 struct FourFours {
632 FourFours(unsigned f3, unsigned f2, unsigned f1, unsigned f0)
633 {
634 m_u.f0 = f0;
635 m_u.f1 = f1;
636 m_u.f2 = f2;
637 m_u.f3 = f3;
638 }
639
640 union {
641 unsigned value;
642 struct {
643 unsigned f0 : 4;
644 unsigned f1 : 4;
645 unsigned f2 : 4;
646 unsigned f3 : 4;
647 };
648 } m_u;
649 };
650
651 class ARMInstructionFormatter;
652
653 // false means else!
654 bool ifThenElseConditionBit(Condition condition, bool isIf)
655 {
656 return isIf ? (condition & 1) : !(condition & 1);
657 }
658 uint8_t ifThenElse(Condition condition, bool inst2if, bool inst3if, bool inst4if)
659 {
660 int mask = (ifThenElseConditionBit(condition, inst2if) << 3)
661 | (ifThenElseConditionBit(condition, inst3if) << 2)
662 | (ifThenElseConditionBit(condition, inst4if) << 1)
663 | 1;
664 ASSERT((condition != ConditionAL) || (mask & (mask - 1)));
665 return (condition << 4) | mask;
666 }
667 uint8_t ifThenElse(Condition condition, bool inst2if, bool inst3if)
668 {
669 int mask = (ifThenElseConditionBit(condition, inst2if) << 3)
670 | (ifThenElseConditionBit(condition, inst3if) << 2)
671 | 2;
672 ASSERT((condition != ConditionAL) || (mask & (mask - 1)));
673 return (condition << 4) | mask;
674 }
675 uint8_t ifThenElse(Condition condition, bool inst2if)
676 {
677 int mask = (ifThenElseConditionBit(condition, inst2if) << 3)
678 | 4;
679 ASSERT((condition != ConditionAL) || (mask & (mask - 1)));
680 return (condition << 4) | mask;
681 }
682
683 uint8_t ifThenElse(Condition condition)
684 {
685 int mask = 8;
686 ASSERT((condition != ConditionAL) || (mask & (mask - 1)));
687 return (condition << 4) | mask;
688 }
689
690 public:
691
692 void add(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
693 {
694 // Rd can only be SP if Rn is also SP.
695 ASSERT((rd != ARM::sp) || (rn == ARM::sp));
696 ASSERT(rd != ARM::pc);
697 ASSERT(rn != ARM::pc);
698 ASSERT(imm.isValid());
699
700 if (rn == ARM::sp) {
701 if (!(rd & 8) && imm.isUInt10()) {
702 m_formatter.oneWordOp5Reg3Imm8(OP_ADD_SP_imm_T1, rd, imm.getUInt10() >> 2);
703 return;
704 } else if ((rd == ARM::sp) && imm.isUInt9()) {
705 m_formatter.oneWordOp9Imm7(OP_ADD_SP_imm_T2, imm.getUInt9() >> 2);
706 return;
707 }
708 } else if (!((rd | rn) & 8)) {
709 if (imm.isUInt3()) {
710 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_imm_T1, (RegisterID)imm.getUInt3(), rn, rd);
711 return;
712 } else if ((rd == rn) && imm.isUInt8()) {
713 m_formatter.oneWordOp5Reg3Imm8(OP_ADD_imm_T2, rd, imm.getUInt8());
714 return;
715 }
716 }
717
718 if (imm.isEncodedImm())
719 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T3, rn, rd, imm);
720 else {
721 ASSERT(imm.isUInt12());
722 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T4, rn, rd, imm);
723 }
724 }
725
726 void add(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
727 {
728 ASSERT((rd != ARM::sp) || (rn == ARM::sp));
729 ASSERT(rd != ARM::pc);
730 ASSERT(rn != ARM::pc);
731 ASSERT(!BadReg(rm));
732 m_formatter.twoWordOp12Reg4FourFours(OP_ADD_reg_T3, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
733 }
734
735 // NOTE: In an IT block, add doesn't modify the flags register.
736 void add(RegisterID rd, RegisterID rn, RegisterID rm)
737 {
738 if (rd == rn)
739 m_formatter.oneWordOp8RegReg143(OP_ADD_reg_T2, rm, rd);
740 else if (rd == rm)
741 m_formatter.oneWordOp8RegReg143(OP_ADD_reg_T2, rn, rd);
742 else if (!((rd | rn | rm) & 8))
743 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_reg_T1, rm, rn, rd);
744 else
745 add(rd, rn, rm, ShiftTypeAndAmount());
746 }
747
748 // Not allowed in an IT (if then) block.
749 void add_S(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
750 {
751 // Rd can only be SP if Rn is also SP.
752 ASSERT((rd != ARM::sp) || (rn == ARM::sp));
753 ASSERT(rd != ARM::pc);
754 ASSERT(rn != ARM::pc);
755 ASSERT(imm.isEncodedImm());
756
757 if (!((rd | rn) & 8)) {
758 if (imm.isUInt3()) {
759 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_S_imm_T1, (RegisterID)imm.getUInt3(), rn, rd);
760 return;
761 } else if ((rd == rn) && imm.isUInt8()) {
762 m_formatter.oneWordOp5Reg3Imm8(OP_ADD_S_imm_T2, rd, imm.getUInt8());
763 return;
764 }
765 }
766
767 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_S_imm_T3, rn, rd, imm);
768 }
769
770 // Not allowed in an IT (if then) block?
771 void add_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
772 {
773 ASSERT((rd != ARM::sp) || (rn == ARM::sp));
774 ASSERT(rd != ARM::pc);
775 ASSERT(rn != ARM::pc);
776 ASSERT(!BadReg(rm));
777 m_formatter.twoWordOp12Reg4FourFours(OP_ADD_S_reg_T3, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
778 }
779
780 // Not allowed in an IT (if then) block.
781 void add_S(RegisterID rd, RegisterID rn, RegisterID rm)
782 {
783 if (!((rd | rn | rm) & 8))
784 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_S_reg_T1, rm, rn, rd);
785 else
786 add_S(rd, rn, rm, ShiftTypeAndAmount());
787 }
788
789 void ARM_and(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
790 {
791 ASSERT(!BadReg(rd));
792 ASSERT(!BadReg(rn));
793 ASSERT(imm.isEncodedImm());
794 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_AND_imm_T1, rn, rd, imm);
795 }
796
797 void ARM_and(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
798 {
799 ASSERT(!BadReg(rd));
800 ASSERT(!BadReg(rn));
801 ASSERT(!BadReg(rm));
802 m_formatter.twoWordOp12Reg4FourFours(OP_AND_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
803 }
804
805 void ARM_and(RegisterID rd, RegisterID rn, RegisterID rm)
806 {
807 if ((rd == rn) && !((rd | rm) & 8))
808 m_formatter.oneWordOp10Reg3Reg3(OP_AND_reg_T1, rm, rd);
809 else if ((rd == rm) && !((rd | rn) & 8))
810 m_formatter.oneWordOp10Reg3Reg3(OP_AND_reg_T1, rn, rd);
811 else
812 ARM_and(rd, rn, rm, ShiftTypeAndAmount());
813 }
814
815 void asr(RegisterID rd, RegisterID rm, int32_t shiftAmount)
816 {
817 ASSERT(!BadReg(rd));
818 ASSERT(!BadReg(rm));
819 ShiftTypeAndAmount shift(SRType_ASR, shiftAmount);
820 m_formatter.twoWordOp16FourFours(OP_ASR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
821 }
822
823 void asr(RegisterID rd, RegisterID rn, RegisterID rm)
824 {
825 ASSERT(!BadReg(rd));
826 ASSERT(!BadReg(rn));
827 ASSERT(!BadReg(rm));
828 m_formatter.twoWordOp12Reg4FourFours(OP_ASR_reg_T2, rn, FourFours(0xf, rd, 0, rm));
829 }
830
831 // Only allowed in IT (if then) block if last instruction.
832 JmpSrc b()
833 {
834 m_formatter.twoWordOp16Op16(OP_B_T4a, OP_B_T4b);
835 return JmpSrc(m_formatter.size());
836 }
837
838 // Only allowed in IT (if then) block if last instruction.
839 JmpSrc blx(RegisterID rm)
840 {
841 ASSERT(rm != ARM::pc);
842 m_formatter.oneWordOp8RegReg143(OP_BLX, rm, (RegisterID)8);
843 return JmpSrc(m_formatter.size());
844 }
845
846 // Only allowed in IT (if then) block if last instruction.
847 JmpSrc bx(RegisterID rm)
848 {
849 m_formatter.oneWordOp8RegReg143(OP_BX, rm, (RegisterID)0);
850 return JmpSrc(m_formatter.size());
851 }
852
853 void bkpt(uint8_t imm=0)
854 {
855 m_formatter.oneWordOp8Imm8(OP_BKPT, imm);
856 }
857
858 void cmn(RegisterID rn, ARMThumbImmediate imm)
859 {
860 ASSERT(rn != ARM::pc);
861 ASSERT(imm.isEncodedImm());
862
863 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMN_imm, rn, (RegisterID)0xf, imm);
864 }
865
866 void cmp(RegisterID rn, ARMThumbImmediate imm)
867 {
868 ASSERT(rn != ARM::pc);
869 ASSERT(imm.isEncodedImm());
870
871 if (!(rn & 8) && imm.isUInt8())
872 m_formatter.oneWordOp5Reg3Imm8(OP_CMP_imm_T1, rn, imm.getUInt8());
873 else
874 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMP_imm_T2, rn, (RegisterID)0xf, imm);
875 }
876
877 void cmp(RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
878 {
879 ASSERT(rn != ARM::pc);
880 ASSERT(!BadReg(rm));
881 m_formatter.twoWordOp12Reg4FourFours(OP_CMP_reg_T2, rn, FourFours(shift.hi4(), 0xf, shift.lo4(), rm));
882 }
883
884 void cmp(RegisterID rn, RegisterID rm)
885 {
886 if ((rn | rm) & 8)
887 cmp(rn, rm, ShiftTypeAndAmount());
888 else
889 m_formatter.oneWordOp10Reg3Reg3(OP_CMP_reg_T1, rm, rn);
890 }
891
892 // xor is not spelled with an 'e'. :-(
893 void eor(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
894 {
895 ASSERT(!BadReg(rd));
896 ASSERT(!BadReg(rn));
897 ASSERT(imm.isEncodedImm());
898 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_EOR_imm_T1, rn, rd, imm);
899 }
900
901 // xor is not spelled with an 'e'. :-(
902 void eor(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
903 {
904 ASSERT(!BadReg(rd));
905 ASSERT(!BadReg(rn));
906 ASSERT(!BadReg(rm));
907 m_formatter.twoWordOp12Reg4FourFours(OP_EOR_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
908 }
909
910 // xor is not spelled with an 'e'. :-(
911 void eor(RegisterID rd, RegisterID rn, RegisterID rm)
912 {
913 if ((rd == rn) && !((rd | rm) & 8))
914 m_formatter.oneWordOp10Reg3Reg3(OP_EOR_reg_T1, rm, rd);
915 else if ((rd == rm) && !((rd | rn) & 8))
916 m_formatter.oneWordOp10Reg3Reg3(OP_EOR_reg_T1, rn, rd);
917 else
918 eor(rd, rn, rm, ShiftTypeAndAmount());
919 }
920
921 void it(Condition cond)
922 {
923 m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond));
924 }
925
926 void it(Condition cond, bool inst2if)
927 {
928 m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if));
929 }
930
931 void it(Condition cond, bool inst2if, bool inst3if)
932 {
933 m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if, inst3if));
934 }
935
936 void it(Condition cond, bool inst2if, bool inst3if, bool inst4if)
937 {
938 m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if, inst3if, inst4if));
939 }
940
941 // rt == ARM::pc only allowed if last instruction in IT (if then) block.
942 void ldr(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
943 {
944 ASSERT(rn != ARM::pc); // LDR (literal)
945 ASSERT(imm.isUInt12());
946
947 if (!((rt | rn) & 8) && imm.isUInt7())
948 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDR_imm_T1, imm.getUInt7() >> 2, rn, rt);
949 else if ((rn == ARM::sp) && !(rt & 8) && imm.isUInt10())
950 m_formatter.oneWordOp5Reg3Imm8(OP_LDR_imm_T2, rt, imm.getUInt10() >> 2);
951 else
952 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T3, rn, rt, imm.getUInt12());
953 }
954
955 // If index is set, this is a regular offset or a pre-indexed load;
956 // if index is not set then is is a post-index load.
957 //
958 // If wback is set rn is updated - this is a pre or post index load,
959 // if wback is not set this is a regular offset memory access.
960 //
961 // (-255 <= offset <= 255)
962 // _reg = REG[rn]
963 // _tmp = _reg + offset
964 // MEM[index ? _tmp : _reg] = REG[rt]
965 // if (wback) REG[rn] = _tmp
966 void ldr(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
967 {
968 ASSERT(rt != ARM::pc);
969 ASSERT(rn != ARM::pc);
970 ASSERT(index || wback);
971 ASSERT(!wback | (rt != rn));
972
973 bool add = true;
974 if (offset < 0) {
975 add = false;
976 offset = -offset;
977 }
978 ASSERT((offset & ~0xff) == 0);
979
980 offset |= (wback << 8);
981 offset |= (add << 9);
982 offset |= (index << 10);
983 offset |= (1 << 11);
984
985 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T4, rn, rt, offset);
986 }
987
988 // rt == ARM::pc only allowed if last instruction in IT (if then) block.
989 void ldr(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0)
990 {
991 ASSERT(rn != ARM::pc); // LDR (literal)
992 ASSERT(!BadReg(rm));
993 ASSERT(shift <= 3);
994
995 if (!shift && !((rt | rn | rm) & 8))
996 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDR_reg_T1, rm, rn, rt);
997 else
998 m_formatter.twoWordOp12Reg4FourFours(OP_LDR_reg_T2, rn, FourFours(rt, 0, shift, rm));
999 }
1000
1001 // rt == ARM::pc only allowed if last instruction in IT (if then) block.
1002 void ldrh(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
1003 {
1004 ASSERT(rn != ARM::pc); // LDR (literal)
1005 ASSERT(imm.isUInt12());
1006
1007 if (!((rt | rn) & 8) && imm.isUInt6())
1008 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDRH_imm_T1, imm.getUInt6() >> 2, rn, rt);
1009 else
1010 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T2, rn, rt, imm.getUInt12());
1011 }
1012
1013 // If index is set, this is a regular offset or a pre-indexed load;
1014 // if index is not set then is is a post-index load.
1015 //
1016 // If wback is set rn is updated - this is a pre or post index load,
1017 // if wback is not set this is a regular offset memory access.
1018 //
1019 // (-255 <= offset <= 255)
1020 // _reg = REG[rn]
1021 // _tmp = _reg + offset
1022 // MEM[index ? _tmp : _reg] = REG[rt]
1023 // if (wback) REG[rn] = _tmp
1024 void ldrh(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
1025 {
1026 ASSERT(rt != ARM::pc);
1027 ASSERT(rn != ARM::pc);
1028 ASSERT(index || wback);
1029 ASSERT(!wback | (rt != rn));
1030
1031 bool add = true;
1032 if (offset < 0) {
1033 add = false;
1034 offset = -offset;
1035 }
1036 ASSERT((offset & ~0xff) == 0);
1037
1038 offset |= (wback << 8);
1039 offset |= (add << 9);
1040 offset |= (index << 10);
1041 offset |= (1 << 11);
1042
1043 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T3, rn, rt, offset);
1044 }
1045
1046 void ldrh(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0)
1047 {
1048 ASSERT(!BadReg(rt)); // Memory hint
1049 ASSERT(rn != ARM::pc); // LDRH (literal)
1050 ASSERT(!BadReg(rm));
1051 ASSERT(shift <= 3);
1052
1053 if (!shift && !((rt | rn | rm) & 8))
1054 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDRH_reg_T1, rm, rn, rt);
1055 else
1056 m_formatter.twoWordOp12Reg4FourFours(OP_LDRH_reg_T2, rn, FourFours(rt, 0, shift, rm));
1057 }
1058
1059 void lsl(RegisterID rd, RegisterID rm, int32_t shiftAmount)
1060 {
1061 ASSERT(!BadReg(rd));
1062 ASSERT(!BadReg(rm));
1063 ShiftTypeAndAmount shift(SRType_LSL, shiftAmount);
1064 m_formatter.twoWordOp16FourFours(OP_LSL_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1065 }
1066
1067 void lsl(RegisterID rd, RegisterID rn, RegisterID rm)
1068 {
1069 ASSERT(!BadReg(rd));
1070 ASSERT(!BadReg(rn));
1071 ASSERT(!BadReg(rm));
1072 m_formatter.twoWordOp12Reg4FourFours(OP_LSL_reg_T2, rn, FourFours(0xf, rd, 0, rm));
1073 }
1074
1075 void lsr(RegisterID rd, RegisterID rm, int32_t shiftAmount)
1076 {
1077 ASSERT(!BadReg(rd));
1078 ASSERT(!BadReg(rm));
1079 ShiftTypeAndAmount shift(SRType_LSR, shiftAmount);
1080 m_formatter.twoWordOp16FourFours(OP_LSR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1081 }
1082
1083 void lsr(RegisterID rd, RegisterID rn, RegisterID rm)
1084 {
1085 ASSERT(!BadReg(rd));
1086 ASSERT(!BadReg(rn));
1087 ASSERT(!BadReg(rm));
1088 m_formatter.twoWordOp12Reg4FourFours(OP_LSR_reg_T2, rn, FourFours(0xf, rd, 0, rm));
1089 }
1090
1091 void movT3(RegisterID rd, ARMThumbImmediate imm)
1092 {
1093 ASSERT(imm.isValid());
1094 ASSERT(!imm.isEncodedImm());
1095 ASSERT(!BadReg(rd));
1096
1097 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T3, imm.m_value.imm4, rd, imm);
1098 }
1099
1100 void mov(RegisterID rd, ARMThumbImmediate imm)
1101 {
1102 ASSERT(imm.isValid());
1103 ASSERT(!BadReg(rd));
1104
1105 if ((rd < 8) && imm.isUInt8())
1106 m_formatter.oneWordOp5Reg3Imm8(OP_MOV_imm_T1, rd, imm.getUInt8());
1107 else if (imm.isEncodedImm())
1108 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T2, 0xf, rd, imm);
1109 else
1110 movT3(rd, imm);
1111 }
1112
1113 void mov(RegisterID rd, RegisterID rm)
1114 {
1115 m_formatter.oneWordOp8RegReg143(OP_MOV_reg_T1, rm, rd);
1116 }
1117
1118 void movt(RegisterID rd, ARMThumbImmediate imm)
1119 {
1120 ASSERT(imm.isUInt16());
1121 ASSERT(!BadReg(rd));
1122 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOVT, imm.m_value.imm4, rd, imm);
1123 }
1124
1125 void mvn(RegisterID rd, ARMThumbImmediate imm)
1126 {
1127 ASSERT(imm.isEncodedImm());
1128 ASSERT(!BadReg(rd));
1129
1130 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MVN_imm, 0xf, rd, imm);
1131 }
1132
1133 void mvn(RegisterID rd, RegisterID rm, ShiftTypeAndAmount shift)
1134 {
1135 ASSERT(!BadReg(rd));
1136 ASSERT(!BadReg(rm));
1137 m_formatter.twoWordOp16FourFours(OP_MVN_reg_T2, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1138 }
1139
1140 void mvn(RegisterID rd, RegisterID rm)
1141 {
1142 if (!((rd | rm) & 8))
1143 m_formatter.oneWordOp10Reg3Reg3(OP_MVN_reg_T1, rm, rd);
1144 else
1145 mvn(rd, rm, ShiftTypeAndAmount());
1146 }
1147
1148 void orr(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
1149 {
1150 ASSERT(!BadReg(rd));
1151 ASSERT(!BadReg(rn));
1152 ASSERT(imm.isEncodedImm());
1153 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ORR_imm_T1, rn, rd, imm);
1154 }
1155
1156 void orr(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
1157 {
1158 ASSERT(!BadReg(rd));
1159 ASSERT(!BadReg(rn));
1160 ASSERT(!BadReg(rm));
1161 m_formatter.twoWordOp12Reg4FourFours(OP_ORR_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1162 }
1163
1164 void orr(RegisterID rd, RegisterID rn, RegisterID rm)
1165 {
1166 if ((rd == rn) && !((rd | rm) & 8))
1167 m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rm, rd);
1168 else if ((rd == rm) && !((rd | rn) & 8))
1169 m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rn, rd);
1170 else
1171 orr(rd, rn, rm, ShiftTypeAndAmount());
1172 }
1173
1174 void ror(RegisterID rd, RegisterID rm, int32_t shiftAmount)
1175 {
1176 ASSERT(!BadReg(rd));
1177 ASSERT(!BadReg(rm));
1178 ShiftTypeAndAmount shift(SRType_ROR, shiftAmount);
1179 m_formatter.twoWordOp16FourFours(OP_ROR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1180 }
1181
1182 void ror(RegisterID rd, RegisterID rn, RegisterID rm)
1183 {
1184 ASSERT(!BadReg(rd));
1185 ASSERT(!BadReg(rn));
1186 ASSERT(!BadReg(rm));
1187 m_formatter.twoWordOp12Reg4FourFours(OP_ROR_reg_T2, rn, FourFours(0xf, rd, 0, rm));
1188 }
1189
1190 void smull(RegisterID rdLo, RegisterID rdHi, RegisterID rn, RegisterID rm)
1191 {
1192 ASSERT(!BadReg(rdLo));
1193 ASSERT(!BadReg(rdHi));
1194 ASSERT(!BadReg(rn));
1195 ASSERT(!BadReg(rm));
1196 ASSERT(rdLo != rdHi);
1197 m_formatter.twoWordOp12Reg4FourFours(OP_SMULL_T1, rn, FourFours(rdLo, rdHi, 0, rm));
1198 }
1199
1200 // rt == ARM::pc only allowed if last instruction in IT (if then) block.
1201 void str(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
1202 {
1203 ASSERT(rt != ARM::pc);
1204 ASSERT(rn != ARM::pc);
1205 ASSERT(imm.isUInt12());
1206
1207 if (!((rt | rn) & 8) && imm.isUInt7())
1208 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_STR_imm_T1, imm.getUInt7() >> 2, rn, rt);
1209 else if ((rn == ARM::sp) && !(rt & 8) && imm.isUInt10())
1210 m_formatter.oneWordOp5Reg3Imm8(OP_STR_imm_T2, rt, imm.getUInt10() >> 2);
1211 else
1212 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T3, rn, rt, imm.getUInt12());
1213 }
1214
1215 // If index is set, this is a regular offset or a pre-indexed store;
1216 // if index is not set then is is a post-index store.
1217 //
1218 // If wback is set rn is updated - this is a pre or post index store,
1219 // if wback is not set this is a regular offset memory access.
1220 //
1221 // (-255 <= offset <= 255)
1222 // _reg = REG[rn]
1223 // _tmp = _reg + offset
1224 // MEM[index ? _tmp : _reg] = REG[rt]
1225 // if (wback) REG[rn] = _tmp
1226 void str(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
1227 {
1228 ASSERT(rt != ARM::pc);
1229 ASSERT(rn != ARM::pc);
1230 ASSERT(index || wback);
1231 ASSERT(!wback | (rt != rn));
1232
1233 bool add = true;
1234 if (offset < 0) {
1235 add = false;
1236 offset = -offset;
1237 }
1238 ASSERT((offset & ~0xff) == 0);
1239
1240 offset |= (wback << 8);
1241 offset |= (add << 9);
1242 offset |= (index << 10);
1243 offset |= (1 << 11);
1244
1245 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T4, rn, rt, offset);
1246 }
1247
1248 // rt == ARM::pc only allowed if last instruction in IT (if then) block.
1249 void str(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0)
1250 {
1251 ASSERT(rn != ARM::pc);
1252 ASSERT(!BadReg(rm));
1253 ASSERT(shift <= 3);
1254
1255 if (!shift && !((rt | rn | rm) & 8))
1256 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_STR_reg_T1, rm, rn, rt);
1257 else
1258 m_formatter.twoWordOp12Reg4FourFours(OP_STR_reg_T2, rn, FourFours(rt, 0, shift, rm));
1259 }
1260
1261 void sub(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
1262 {
1263 // Rd can only be SP if Rn is also SP.
1264 ASSERT((rd != ARM::sp) || (rn == ARM::sp));
1265 ASSERT(rd != ARM::pc);
1266 ASSERT(rn != ARM::pc);
1267 ASSERT(imm.isValid());
1268
1269 if ((rn == ARM::sp) && (rd == ARM::sp) && imm.isUInt9()) {
1270 m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, imm.getUInt9() >> 2);
1271 return;
1272 } else if (!((rd | rn) & 8)) {
1273 if (imm.isUInt3()) {
1274 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_imm_T1, (RegisterID)imm.getUInt3(), rn, rd);
1275 return;
1276 } else if ((rd == rn) && imm.isUInt8()) {
1277 m_formatter.oneWordOp5Reg3Imm8(OP_SUB_imm_T2, rd, imm.getUInt8());
1278 return;
1279 }
1280 }
1281
1282 if (imm.isEncodedImm())
1283 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T3, rn, rd, imm);
1284 else {
1285 ASSERT(imm.isUInt12());
1286 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T4, rn, rd, imm);
1287 }
1288 }
1289
1290 void sub(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
1291 {
1292 ASSERT((rd != ARM::sp) || (rn == ARM::sp));
1293 ASSERT(rd != ARM::pc);
1294 ASSERT(rn != ARM::pc);
1295 ASSERT(!BadReg(rm));
1296 m_formatter.twoWordOp12Reg4FourFours(OP_SUB_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1297 }
1298
1299 // NOTE: In an IT block, add doesn't modify the flags register.
1300 void sub(RegisterID rd, RegisterID rn, RegisterID rm)
1301 {
1302 if (!((rd | rn | rm) & 8))
1303 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_reg_T1, rm, rn, rd);
1304 else
1305 sub(rd, rn, rm, ShiftTypeAndAmount());
1306 }
1307
1308 // Not allowed in an IT (if then) block.
1309 void sub_S(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
1310 {
1311 // Rd can only be SP if Rn is also SP.
1312 ASSERT((rd != ARM::sp) || (rn == ARM::sp));
1313 ASSERT(rd != ARM::pc);
1314 ASSERT(rn != ARM::pc);
1315 ASSERT(imm.isValid());
1316
1317 if ((rn == ARM::sp) && (rd == ARM::sp) && imm.isUInt9()) {
1318 m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, imm.getUInt9() >> 2);
1319 return;
1320 } else if (!((rd | rn) & 8)) {
1321 if (imm.isUInt3()) {
1322 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_S_imm_T1, (RegisterID)imm.getUInt3(), rn, rd);
1323 return;
1324 } else if ((rd == rn) && imm.isUInt8()) {
1325 m_formatter.oneWordOp5Reg3Imm8(OP_SUB_S_imm_T2, rd, imm.getUInt8());
1326 return;
1327 }
1328 }
1329
1330 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_S_imm_T3, rn, rd, imm);
1331 }
1332
1333 // Not allowed in an IT (if then) block?
1334 void sub_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
1335 {
1336 ASSERT((rd != ARM::sp) || (rn == ARM::sp));
1337 ASSERT(rd != ARM::pc);
1338 ASSERT(rn != ARM::pc);
1339 ASSERT(!BadReg(rm));
1340 m_formatter.twoWordOp12Reg4FourFours(OP_SUB_S_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1341 }
1342
1343 // Not allowed in an IT (if then) block.
1344 void sub_S(RegisterID rd, RegisterID rn, RegisterID rm)
1345 {
1346 if (!((rd | rn | rm) & 8))
1347 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_S_reg_T1, rm, rn, rd);
1348 else
1349 sub_S(rd, rn, rm, ShiftTypeAndAmount());
1350 }
1351
1352 void tst(RegisterID rn, ARMThumbImmediate imm)
1353 {
1354 ASSERT(!BadReg(rn));
1355 ASSERT(imm.isEncodedImm());
1356
1357 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_TST_imm, rn, (RegisterID)0xf, imm);
1358 }
1359
1360 void tst(RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
1361 {
1362 ASSERT(!BadReg(rn));
1363 ASSERT(!BadReg(rm));
1364 m_formatter.twoWordOp12Reg4FourFours(OP_TST_reg_T2, rn, FourFours(shift.hi4(), 0xf, shift.lo4(), rm));
1365 }
1366
1367 void tst(RegisterID rn, RegisterID rm)
1368 {
1369 if ((rn | rm) & 8)
1370 tst(rn, rm, ShiftTypeAndAmount());
1371 else
1372 m_formatter.oneWordOp10Reg3Reg3(OP_TST_reg_T1, rm, rn);
1373 }
1374
1375 void vadd_F64(FPRegisterID rd, FPRegisterID rn, FPRegisterID rm)
1376 {
1377 m_formatter.vfpOp(0x0b00ee30 | doubleRegisterMask(rd, 6, 28) | doubleRegisterMask(rn, 23, 0) | doubleRegisterMask(rm, 21, 16));
1378 }
1379
1380 void vcmp_F64(FPRegisterID rd, FPRegisterID rm)
1381 {
1382 m_formatter.vfpOp(0x0bc0eeb4 | doubleRegisterMask(rd, 6, 28) | doubleRegisterMask(rm, 21, 16));
1383 }
1384
1385 void vcvt_F64_S32(FPRegisterID fd, FPRegisterID sm)
1386 {
1387 m_formatter.vfpOp(0x0bc0eeb8 | doubleRegisterMask(fd, 6, 28) | singleRegisterMask(sm, 16, 21));
1388 }
1389
1390 void vcvt_S32_F64(FPRegisterID sd, FPRegisterID fm)
1391 {
1392 m_formatter.vfpOp(0x0bc0eebd | singleRegisterMask(sd, 28, 6) | doubleRegisterMask(fm, 21, 16));
1393 }
1394
1395 void vldr(FPRegisterID rd, RegisterID rn, int32_t imm)
1396 {
1397 vmem(rd, rn, imm, true);
1398 }
1399
1400 void vmov(RegisterID rd, FPRegisterID sn)
1401 {
1402 m_formatter.vfpOp(0x0a10ee10 | (rd << 28) | singleRegisterMask(sn, 0, 23));
1403 }
1404
1405 void vmov(FPRegisterID sn, RegisterID rd)
1406 {
1407 m_formatter.vfpOp(0x0a10ee00 | (rd << 28) | singleRegisterMask(sn, 0, 23));
1408 }
1409
1410 // move FPSCR flags to APSR.
1411 void vmrs_APSR_nzcv_FPSCR()
1412 {
1413 m_formatter.vfpOp(0xfa10eef1);
1414 }
1415
1416 void vmul_F64(FPRegisterID rd, FPRegisterID rn, FPRegisterID rm)
1417 {
1418 m_formatter.vfpOp(0x0b00ee20 | doubleRegisterMask(rd, 6, 28) | doubleRegisterMask(rn, 23, 0) | doubleRegisterMask(rm, 21, 16));
1419 }
1420
1421 void vstr(FPRegisterID rd, RegisterID rn, int32_t imm)
1422 {
1423 vmem(rd, rn, imm, false);
1424 }
1425
1426 void vsub_F64(FPRegisterID rd, FPRegisterID rn, FPRegisterID rm)
1427 {
1428 m_formatter.vfpOp(0x0b40ee30 | doubleRegisterMask(rd, 6, 28) | doubleRegisterMask(rn, 23, 0) | doubleRegisterMask(rm, 21, 16));
1429 }
1430
1431
1432 JmpDst label()
1433 {
1434 return JmpDst(m_formatter.size());
1435 }
1436
1437 JmpDst align(int alignment)
1438 {
1439 while (!m_formatter.isAligned(alignment))
1440 bkpt();
1441
1442 return label();
1443 }
1444
1445 static void* getRelocatedAddress(void* code, JmpSrc jump)
1446 {
1447 ASSERT(jump.m_offset != -1);
1448
1449 return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + jump.m_offset);
1450 }
1451
1452 static void* getRelocatedAddress(void* code, JmpDst destination)
1453 {
1454 ASSERT(destination.m_offset != -1);
1455
1456 return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + destination.m_offset);
1457 }
1458
1459 static int getDifferenceBetweenLabels(JmpDst src, JmpDst dst)
1460 {
1461 return dst.m_offset - src.m_offset;
1462 }
1463
1464 static int getDifferenceBetweenLabels(JmpDst src, JmpSrc dst)
1465 {
1466 return dst.m_offset - src.m_offset;
1467 }
1468
1469 static int getDifferenceBetweenLabels(JmpSrc src, JmpDst dst)
1470 {
1471 return dst.m_offset - src.m_offset;
1472 }
1473
1474 // Assembler admin methods:
1475
1476 size_t size() const
1477 {
1478 return m_formatter.size();
1479 }
1480
1481 void* executableCopy(ExecutablePool* allocator)
1482 {
1483 void* copy = m_formatter.executableCopy(allocator);
1484 ASSERT(copy);
1485 return copy;
1486 }
1487
1488 static unsigned getCallReturnOffset(JmpSrc call)
1489 {
1490 ASSERT(call.m_offset >= 0);
1491 return call.m_offset;
1492 }
1493
1494 // Linking & patching:
1495 //
1496 // 'link' and 'patch' methods are for use on unprotected code - such as the code
1497 // within the AssemblerBuffer, and code being patched by the patch buffer. Once
1498 // code has been finalized it is (platform support permitting) within a non-
1499 // writable region of memory; to modify the code in an execute-only execuable
1500 // pool the 'repatch' and 'relink' methods should be used.
1501
1502 void linkJump(JmpSrc from, JmpDst to)
1503 {
1504 ASSERT(to.m_offset != -1);
1505 ASSERT(from.m_offset != -1);
1506
1507 uint16_t* location = reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(m_formatter.data()) + from.m_offset);
1508 intptr_t relative = to.m_offset - from.m_offset;
1509
1510 linkWithOffset(location, relative);
1511 }
1512
1513 static void linkJump(void* code, JmpSrc from, void* to)
1514 {
1515 ASSERT(from.m_offset != -1);
1516
1517 uint16_t* location = reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
1518 intptr_t relative = reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(location);
1519
1520 linkWithOffset(location, relative);
1521 }
1522
1523 // bah, this mathod should really be static, since it is used by the LinkBuffer.
1524 // return a bool saying whether the link was successful?
1525 static void linkCall(void* code, JmpSrc from, void* to)
1526 {
1527 ASSERT(!(reinterpret_cast<intptr_t>(code) & 1));
1528 ASSERT(from.m_offset != -1);
1529 ASSERT(reinterpret_cast<intptr_t>(to) & 1);
1530
1531 setPointer(reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code) + from.m_offset) - 1, to);
1532 }
1533
1534 static void linkPointer(void* code, JmpDst where, void* value)
1535 {
1536 setPointer(reinterpret_cast<char*>(code) + where.m_offset, value);
1537 }
1538
1539 static void relinkJump(void* from, void* to)
1540 {
1541 ASSERT(!(reinterpret_cast<intptr_t>(from) & 1));
1542 ASSERT(!(reinterpret_cast<intptr_t>(to) & 1));
1543
1544 intptr_t relative = reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(from);
1545 linkWithOffset(reinterpret_cast<uint16_t*>(from), relative);
1546
1547 ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(from) - 2, 2 * sizeof(uint16_t));
1548 }
1549
1550 static void relinkCall(void* from, void* to)
1551 {
1552 ASSERT(!(reinterpret_cast<intptr_t>(from) & 1));
1553 ASSERT(reinterpret_cast<intptr_t>(to) & 1);
1554
1555 setPointer(reinterpret_cast<uint16_t*>(from) - 1, to);
1556
1557 ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(from) - 5, 4 * sizeof(uint16_t));
1558 }
1559
1560 static void repatchInt32(void* where, int32_t value)
1561 {
1562 ASSERT(!(reinterpret_cast<intptr_t>(where) & 1));
1563
1564 setInt32(where, value);
1565
1566 ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(where) - 4, 4 * sizeof(uint16_t));
1567 }
1568
1569 static void repatchPointer(void* where, void* value)
1570 {
1571 ASSERT(!(reinterpret_cast<intptr_t>(where) & 1));
1572
1573 setPointer(where, value);
1574
1575 ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(where) - 4, 4 * sizeof(uint16_t));
1576 }
1577
1578 static void repatchLoadPtrToLEA(void* where)
1579 {
1580 ASSERT(!(reinterpret_cast<intptr_t>(where) & 1));
1581
1582 uint16_t* loadOp = reinterpret_cast<uint16_t*>(where) + 4;
1583 ASSERT((*loadOp & 0xfff0) == OP_LDR_reg_T2);
1584
1585 *loadOp = OP_ADD_reg_T3 | (*loadOp & 0xf);
1586 ExecutableAllocator::cacheFlush(loadOp, sizeof(uint16_t));
1587 }
1588
1589 private:
1590
1591 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
1592 // (i.e. +/-(0..255) 32-bit words)
1593 void vmem(FPRegisterID rd, RegisterID rn, int32_t imm, bool isLoad)
1594 {
1595 bool up;
1596 uint32_t offset;
1597 if (imm < 0) {
1598 offset = -imm;
1599 up = false;
1600 } else {
1601 offset = imm;
1602 up = true;
1603 }
1604
1605 // offset is effectively leftshifted by 2 already (the bottom two bits are zero, and not
1606 // reperesented in the instruction. Left shift by 14, to mov it into position 0x00AA0000.
1607 ASSERT((offset & ~(0xff << 2)) == 0);
1608 offset <<= 14;
1609
1610 m_formatter.vfpOp(0x0b00ed00 | offset | (up << 7) | (isLoad << 4) | doubleRegisterMask(rd, 6, 28) | rn);
1611 }
1612
1613 static void setInt32(void* code, uint32_t value)
1614 {
1615 uint16_t* location = reinterpret_cast<uint16_t*>(code);
1616
1617 uint16_t lo16 = value;
1618 uint16_t hi16 = value >> 16;
1619
1620 spliceHi5(location - 4, lo16);
1621 spliceLo11(location - 3, lo16);
1622 spliceHi5(location - 2, hi16);
1623 spliceLo11(location - 1, hi16);
1624
1625 ExecutableAllocator::cacheFlush(location - 4, 4 * sizeof(uint16_t));
1626 }
1627
1628 static void setPointer(void* code, void* value)
1629 {
1630 setInt32(code, reinterpret_cast<uint32_t>(value));
1631 }
1632
1633 // Linking & patching:
1634 // This method assumes that the JmpSrc being linked is a T4 b instruction.
1635 static void linkWithOffset(uint16_t* instruction, intptr_t relative)
1636 {
1637 // Currently branches > 16m = mostly deathy.
1638 if (((relative << 7) >> 7) != relative) {
1639 // FIXME: This CRASH means we cannot turn the JIT on by default on arm-v7.
1640 fprintf(stderr, "Error: Cannot link T4b.\n");
1641 CRASH();
1642 }
1643
1644 // ARM encoding for the top two bits below the sign bit is 'peculiar'.
1645 if (relative >= 0)
1646 relative ^= 0xC00000;
1647
1648 // All branch offsets should be an even distance.
1649 ASSERT(!(relative & 1));
1650
1651 int word1 = ((relative & 0x1000000) >> 14) | ((relative & 0x3ff000) >> 12);
1652 int word2 = ((relative & 0x800000) >> 10) | ((relative & 0x400000) >> 11) | ((relative & 0xffe) >> 1);
1653
1654 instruction[-2] = OP_B_T4a | word1;
1655 instruction[-1] = OP_B_T4b | word2;
1656 }
1657
1658 // These functions can be used to splice 16-bit immediates back into previously generated instructions.
1659 static void spliceHi5(uint16_t* where, uint16_t what)
1660 {
1661 uint16_t pattern = (what >> 12) | ((what & 0x0800) >> 1);
1662 *where = (*where & 0xFBF0) | pattern;
1663 }
1664 static void spliceLo11(uint16_t* where, uint16_t what)
1665 {
1666 uint16_t pattern = ((what & 0x0700) << 4) | (what & 0x00FF);
1667 *where = (*where & 0x8F00) | pattern;
1668 }
1669
1670 class ARMInstructionFormatter {
1671 public:
1672 void oneWordOp5Reg3Imm8(OpcodeID op, RegisterID rd, uint8_t imm)
1673 {
1674 m_buffer.putShort(op | (rd << 8) | imm);
1675 }
1676
1677 void oneWordOp5Imm5Reg3Reg3(OpcodeID op, uint8_t imm, RegisterID reg1, RegisterID reg2)
1678 {
1679 m_buffer.putShort(op | (imm << 6) | (reg1 << 3) | reg2);
1680 }
1681
1682 void oneWordOp7Reg3Reg3Reg3(OpcodeID op, RegisterID reg1, RegisterID reg2, RegisterID reg3)
1683 {
1684 m_buffer.putShort(op | (reg1 << 6) | (reg2 << 3) | reg3);
1685 }
1686
1687 void oneWordOp8Imm8(OpcodeID op, uint8_t imm)
1688 {
1689 m_buffer.putShort(op | imm);
1690 }
1691
1692 void oneWordOp8RegReg143(OpcodeID op, RegisterID reg1, RegisterID reg2)
1693 {
1694 m_buffer.putShort(op | ((reg2 & 8) << 4) | (reg1 << 3) | (reg2 & 7));
1695 }
1696 void oneWordOp9Imm7(OpcodeID op, uint8_t imm)
1697 {
1698 m_buffer.putShort(op | imm);
1699 }
1700
1701 void oneWordOp10Reg3Reg3(OpcodeID op, RegisterID reg1, RegisterID reg2)
1702 {
1703 m_buffer.putShort(op | (reg1 << 3) | reg2);
1704 }
1705
1706 void twoWordOp12Reg4FourFours(OpcodeID1 op, RegisterID reg, FourFours ff)
1707 {
1708 m_buffer.putShort(op | reg);
1709 m_buffer.putShort(ff.m_u.value);
1710 }
1711
1712 void twoWordOp16FourFours(OpcodeID1 op, FourFours ff)
1713 {
1714 m_buffer.putShort(op);
1715 m_buffer.putShort(ff.m_u.value);
1716 }
1717
1718 void twoWordOp16Op16(OpcodeID1 op1, OpcodeID2 op2)
1719 {
1720 m_buffer.putShort(op1);
1721 m_buffer.putShort(op2);
1722 }
1723
1724 void twoWordOp5i6Imm4Reg4EncodedImm(OpcodeID1 op, int imm4, RegisterID rd, ARMThumbImmediate imm)
1725 {
1726 m_buffer.putShort(op | (imm.m_value.i << 10) | imm4);
1727 m_buffer.putShort((imm.m_value.imm3 << 12) | (rd << 8) | imm.m_value.imm8);
1728 }
1729
1730 void twoWordOp12Reg4Reg4Imm12(OpcodeID1 op, RegisterID reg1, RegisterID reg2, uint16_t imm)
1731 {
1732 m_buffer.putShort(op | reg1);
1733 m_buffer.putShort((reg2 << 12) | imm);
1734 }
1735
1736 void vfpOp(int32_t op)
1737 {
1738 m_buffer.putInt(op);
1739 }
1740
1741
1742 // Administrative methods:
1743
1744 size_t size() const { return m_buffer.size(); }
1745 bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); }
1746 void* data() const { return m_buffer.data(); }
1747 void* executableCopy(ExecutablePool* allocator) { return m_buffer.executableCopy(allocator); }
1748
1749 private:
1750 AssemblerBuffer m_buffer;
1751 } m_formatter;
1752 };
1753
1754 } // namespace JSC
1755
1756 #endif // ENABLE(ASSEMBLER) && PLATFORM_ARM_ARCH(7)
1757
1758 #endif // ARMAssembler_h