]> git.saurik.com Git - apple/javascriptcore.git/blame - assembler/ARMv7Assembler.h
JavaScriptCore-576.tar.gz
[apple/javascriptcore.git] / assembler / ARMv7Assembler.h
CommitLineData
ba379fdc
A
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
f9bf01c6 31#if ENABLE(ASSEMBLER) && CPU(ARM_THUMB2)
ba379fdc
A
32
33#include "AssemblerBuffer.h"
34#include <wtf/Assertions.h>
35#include <wtf/Vector.h>
36#include <stdint.h>
37
38namespace JSC {
39
f9bf01c6 40namespace ARMRegisters {
ba379fdc
A
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
163class ARMv7Assembler;
164class 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
f9bf01c6 202 ALWAYS_INLINE static void countLeadingZerosPartial(uint32_t& value, int32_t& zeros, const int N)
ba379fdc 203 {
f9bf01c6
A
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 */
ba379fdc
A
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 {
f9bf01c6
A
239 // Make sure this constructor is only reached with type TypeUInt16;
240 // this extra parameter makes the code a little clearer by making it
241 // explicit at call sites which type is being constructed
242 ASSERT_UNUSED(type, type == TypeUInt16);
243
ba379fdc
A
244 m_value.asInt = value;
245 }
246
247public:
248 static ARMThumbImmediate makeEncodedImm(uint32_t value)
249 {
250 ThumbImmediateValue encoding;
251 encoding.asInt = 0;
252
253 // okay, these are easy.
254 if (value < 256) {
255 encoding.immediate = value;
256 encoding.pattern = 0;
257 return ARMThumbImmediate(TypeEncoded, encoding);
258 }
259
260 int32_t leadingZeros = countLeadingZeros(value);
261 // if there were 24 or more leading zeros, then we'd have hit the (value < 256) case.
262 ASSERT(leadingZeros < 24);
263
264 // Given a number with bit fields Z:B:C, where count(Z)+count(B)+count(C) == 32,
265 // Z are the bits known zero, B is the 8-bit immediate, C are the bits to check for
266 // zero. count(B) == 8, so the count of bits to be checked is 24 - count(Z).
267 int32_t rightShiftAmount = 24 - leadingZeros;
268 if (value == ((value >> rightShiftAmount) << rightShiftAmount)) {
269 // Shift the value down to the low byte position. The assign to
270 // shiftValue7 drops the implicit top bit.
271 encoding.shiftValue7 = value >> rightShiftAmount;
272 // The endoded shift amount is the magnitude of a right rotate.
273 encoding.shiftAmount = 8 + leadingZeros;
274 return ARMThumbImmediate(TypeEncoded, encoding);
275 }
276
277 PatternBytes bytes;
278 bytes.asInt = value;
279
280 if ((bytes.byte0 == bytes.byte1) && (bytes.byte0 == bytes.byte2) && (bytes.byte0 == bytes.byte3)) {
281 encoding.immediate = bytes.byte0;
282 encoding.pattern = 3;
283 return ARMThumbImmediate(TypeEncoded, encoding);
284 }
285
286 if ((bytes.byte0 == bytes.byte2) && !(bytes.byte1 | bytes.byte3)) {
287 encoding.immediate = bytes.byte0;
288 encoding.pattern = 1;
289 return ARMThumbImmediate(TypeEncoded, encoding);
290 }
291
292 if ((bytes.byte1 == bytes.byte3) && !(bytes.byte0 | bytes.byte2)) {
293 encoding.immediate = bytes.byte0;
294 encoding.pattern = 2;
295 return ARMThumbImmediate(TypeEncoded, encoding);
296 }
297
298 return ARMThumbImmediate();
299 }
300
301 static ARMThumbImmediate makeUInt12(int32_t value)
302 {
303 return (!(value & 0xfffff000))
304 ? ARMThumbImmediate(TypeUInt16, (uint16_t)value)
305 : ARMThumbImmediate();
306 }
307
308 static ARMThumbImmediate makeUInt12OrEncodedImm(int32_t value)
309 {
310 // If this is not a 12-bit unsigned it, try making an encoded immediate.
311 return (!(value & 0xfffff000))
312 ? ARMThumbImmediate(TypeUInt16, (uint16_t)value)
313 : makeEncodedImm(value);
314 }
315
316 // The 'make' methods, above, return a !isValid() value if the argument
317 // cannot be represented as the requested type. This methods is called
318 // 'get' since the argument can always be represented.
319 static ARMThumbImmediate makeUInt16(uint16_t value)
320 {
321 return ARMThumbImmediate(TypeUInt16, value);
322 }
323
324 bool isValid()
325 {
326 return m_type != TypeInvalid;
327 }
328
329 // These methods rely on the format of encoded byte values.
330 bool isUInt3() { return !(m_value.asInt & 0xfff8); }
331 bool isUInt4() { return !(m_value.asInt & 0xfff0); }
332 bool isUInt5() { return !(m_value.asInt & 0xffe0); }
333 bool isUInt6() { return !(m_value.asInt & 0xffc0); }
334 bool isUInt7() { return !(m_value.asInt & 0xff80); }
335 bool isUInt8() { return !(m_value.asInt & 0xff00); }
336 bool isUInt9() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xfe00); }
337 bool isUInt10() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xfc00); }
338 bool isUInt12() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xf000); }
339 bool isUInt16() { return m_type == TypeUInt16; }
340 uint8_t getUInt3() { ASSERT(isUInt3()); return m_value.asInt; }
341 uint8_t getUInt4() { ASSERT(isUInt4()); return m_value.asInt; }
342 uint8_t getUInt5() { ASSERT(isUInt5()); return m_value.asInt; }
343 uint8_t getUInt6() { ASSERT(isUInt6()); return m_value.asInt; }
344 uint8_t getUInt7() { ASSERT(isUInt7()); return m_value.asInt; }
345 uint8_t getUInt8() { ASSERT(isUInt8()); return m_value.asInt; }
346 uint8_t getUInt9() { ASSERT(isUInt9()); return m_value.asInt; }
347 uint8_t getUInt10() { ASSERT(isUInt10()); return m_value.asInt; }
348 uint16_t getUInt12() { ASSERT(isUInt12()); return m_value.asInt; }
349 uint16_t getUInt16() { ASSERT(isUInt16()); return m_value.asInt; }
350
351 bool isEncodedImm() { return m_type == TypeEncoded; }
352
353private:
354 ThumbImmediateType m_type;
355 ThumbImmediateValue m_value;
356};
357
358
359typedef enum {
360 SRType_LSL,
361 SRType_LSR,
362 SRType_ASR,
363 SRType_ROR,
364
365 SRType_RRX = SRType_ROR
366} ARMShiftType;
367
368class ARMv7Assembler;
369class ShiftTypeAndAmount {
370 friend class ARMv7Assembler;
371
372public:
373 ShiftTypeAndAmount()
374 {
375 m_u.type = (ARMShiftType)0;
376 m_u.amount = 0;
377 }
378
379 ShiftTypeAndAmount(ARMShiftType type, unsigned amount)
380 {
381 m_u.type = type;
382 m_u.amount = amount & 31;
383 }
384
385 unsigned lo4() { return m_u.lo4; }
386 unsigned hi4() { return m_u.hi4; }
387
388private:
389 union {
390 struct {
391 unsigned lo4 : 4;
392 unsigned hi4 : 4;
393 };
394 struct {
395 unsigned type : 2;
396 unsigned amount : 5;
397 };
398 } m_u;
399};
400
401
402/*
403Some features of the Thumb instruction set are deprecated in ARMv7. Deprecated features affecting
404instructions supported by ARMv7-M are as follows:
405• use of the PC as <Rd> or <Rm> in a 16-bit ADD (SP plus register) instruction
406• use of the SP as <Rm> in a 16-bit ADD (SP plus register) instruction
407• use of the SP as <Rm> in a 16-bit CMP (register) instruction
408• use of MOV (register) instructions in which <Rd> is the SP or PC and <Rm> is also the SP or PC.
409• use of <Rn> as the lowest-numbered register in the register list of a 16-bit STM instruction with base
410register writeback
411*/
412
413class ARMv7Assembler {
414public:
f9bf01c6
A
415 ~ARMv7Assembler()
416 {
417 ASSERT(m_jumpsToLink.isEmpty());
418 }
419
420 typedef ARMRegisters::RegisterID RegisterID;
421 typedef ARMRegisters::FPRegisterID FPRegisterID;
ba379fdc
A
422
423 // (HS, LO, HI, LS) -> (AE, B, A, BE)
424 // (VS, VC) -> (O, NO)
425 typedef enum {
426 ConditionEQ,
427 ConditionNE,
428 ConditionHS,
429 ConditionLO,
430 ConditionMI,
431 ConditionPL,
432 ConditionVS,
433 ConditionVC,
434 ConditionHI,
435 ConditionLS,
436 ConditionGE,
437 ConditionLT,
438 ConditionGT,
439 ConditionLE,
440 ConditionAL,
441
442 ConditionCS = ConditionHS,
443 ConditionCC = ConditionLO,
444 } Condition;
445
446 class JmpSrc {
447 friend class ARMv7Assembler;
448 friend class ARMInstructionFormatter;
449 public:
450 JmpSrc()
451 : m_offset(-1)
452 {
453 }
454
455 private:
456 JmpSrc(int offset)
457 : m_offset(offset)
458 {
459 }
460
461 int m_offset;
462 };
463
464 class JmpDst {
465 friend class ARMv7Assembler;
466 friend class ARMInstructionFormatter;
467 public:
468 JmpDst()
469 : m_offset(-1)
470 , m_used(false)
471 {
472 }
473
474 bool isUsed() const { return m_used; }
475 void used() { m_used = true; }
476 private:
477 JmpDst(int offset)
478 : m_offset(offset)
479 , m_used(false)
480 {
481 ASSERT(m_offset == offset);
482 }
483
484 int m_offset : 31;
485 int m_used : 1;
486 };
487
488private:
489
f9bf01c6
A
490 struct LinkRecord {
491 LinkRecord(intptr_t from, intptr_t to)
492 : from(from)
493 , to(to)
494 {
495 }
496
497 intptr_t from;
498 intptr_t to;
499 };
500
ba379fdc
A
501 // ARMv7, Appx-A.6.3
502 bool BadReg(RegisterID reg)
503 {
f9bf01c6 504 return (reg == ARMRegisters::sp) || (reg == ARMRegisters::pc);
ba379fdc
A
505 }
506
507 bool isSingleRegister(FPRegisterID reg)
508 {
509 // Check that the high bit isn't set (q16+), and that the low bit isn't (s1, s3, etc).
510 return !(reg & ~31);
511 }
512
513 bool isDoubleRegister(FPRegisterID reg)
514 {
515 // Check that the high bit isn't set (q16+), and that the low bit isn't (s1, s3, etc).
516 return !(reg & ~(31 << 1));
517 }
518
519 bool isQuadRegister(FPRegisterID reg)
520 {
521 return !(reg & ~(31 << 2));
522 }
523
524 uint32_t singleRegisterNum(FPRegisterID reg)
525 {
526 ASSERT(isSingleRegister(reg));
527 return reg;
528 }
529
530 uint32_t doubleRegisterNum(FPRegisterID reg)
531 {
532 ASSERT(isDoubleRegister(reg));
533 return reg >> 1;
534 }
535
536 uint32_t quadRegisterNum(FPRegisterID reg)
537 {
538 ASSERT(isQuadRegister(reg));
539 return reg >> 2;
540 }
541
542 uint32_t singleRegisterMask(FPRegisterID rd, int highBitsShift, int lowBitShift)
543 {
544 uint32_t rdNum = singleRegisterNum(rd);
545 uint32_t rdMask = (rdNum >> 1) << highBitsShift;
546 if (rdNum & 1)
547 rdMask |= 1 << lowBitShift;
548 return rdMask;
549 }
550
551 uint32_t doubleRegisterMask(FPRegisterID rd, int highBitShift, int lowBitsShift)
552 {
553 uint32_t rdNum = doubleRegisterNum(rd);
554 uint32_t rdMask = (rdNum & 0xf) << lowBitsShift;
555 if (rdNum & 16)
556 rdMask |= 1 << highBitShift;
557 return rdMask;
558 }
559
560 typedef enum {
561 OP_ADD_reg_T1 = 0x1800,
562 OP_ADD_S_reg_T1 = 0x1800,
563 OP_SUB_reg_T1 = 0x1A00,
564 OP_SUB_S_reg_T1 = 0x1A00,
565 OP_ADD_imm_T1 = 0x1C00,
566 OP_ADD_S_imm_T1 = 0x1C00,
567 OP_SUB_imm_T1 = 0x1E00,
568 OP_SUB_S_imm_T1 = 0x1E00,
569 OP_MOV_imm_T1 = 0x2000,
570 OP_CMP_imm_T1 = 0x2800,
571 OP_ADD_imm_T2 = 0x3000,
572 OP_ADD_S_imm_T2 = 0x3000,
573 OP_SUB_imm_T2 = 0x3800,
574 OP_SUB_S_imm_T2 = 0x3800,
575 OP_AND_reg_T1 = 0x4000,
576 OP_EOR_reg_T1 = 0x4040,
577 OP_TST_reg_T1 = 0x4200,
578 OP_CMP_reg_T1 = 0x4280,
579 OP_ORR_reg_T1 = 0x4300,
580 OP_MVN_reg_T1 = 0x43C0,
581 OP_ADD_reg_T2 = 0x4400,
582 OP_MOV_reg_T1 = 0x4600,
583 OP_BLX = 0x4700,
584 OP_BX = 0x4700,
585 OP_LDRH_reg_T1 = 0x5A00,
586 OP_STR_reg_T1 = 0x5000,
587 OP_LDR_reg_T1 = 0x5800,
588 OP_STR_imm_T1 = 0x6000,
589 OP_LDR_imm_T1 = 0x6800,
590 OP_LDRH_imm_T1 = 0x8800,
591 OP_STR_imm_T2 = 0x9000,
592 OP_LDR_imm_T2 = 0x9800,
593 OP_ADD_SP_imm_T1 = 0xA800,
594 OP_ADD_SP_imm_T2 = 0xB000,
595 OP_SUB_SP_imm_T1 = 0xB080,
596 OP_BKPT = 0xBE00,
597 OP_IT = 0xBF00,
f9bf01c6 598 OP_NOP_T1 = 0xBF00,
ba379fdc
A
599 } OpcodeID;
600
601 typedef enum {
602 OP_AND_reg_T2 = 0xEA00,
603 OP_TST_reg_T2 = 0xEA10,
604 OP_ORR_reg_T2 = 0xEA40,
605 OP_ASR_imm_T1 = 0xEA4F,
606 OP_LSL_imm_T1 = 0xEA4F,
607 OP_LSR_imm_T1 = 0xEA4F,
608 OP_ROR_imm_T1 = 0xEA4F,
609 OP_MVN_reg_T2 = 0xEA6F,
610 OP_EOR_reg_T2 = 0xEA80,
611 OP_ADD_reg_T3 = 0xEB00,
612 OP_ADD_S_reg_T3 = 0xEB10,
613 OP_SUB_reg_T2 = 0xEBA0,
614 OP_SUB_S_reg_T2 = 0xEBB0,
615 OP_CMP_reg_T2 = 0xEBB0,
616 OP_B_T4a = 0xF000,
617 OP_AND_imm_T1 = 0xF000,
618 OP_TST_imm = 0xF010,
619 OP_ORR_imm_T1 = 0xF040,
620 OP_MOV_imm_T2 = 0xF040,
621 OP_MVN_imm = 0xF060,
622 OP_EOR_imm_T1 = 0xF080,
623 OP_ADD_imm_T3 = 0xF100,
624 OP_ADD_S_imm_T3 = 0xF110,
625 OP_CMN_imm = 0xF110,
626 OP_SUB_imm_T3 = 0xF1A0,
627 OP_SUB_S_imm_T3 = 0xF1B0,
628 OP_CMP_imm_T2 = 0xF1B0,
629 OP_ADD_imm_T4 = 0xF200,
630 OP_MOV_imm_T3 = 0xF240,
631 OP_SUB_imm_T4 = 0xF2A0,
632 OP_MOVT = 0xF2C0,
f9bf01c6 633 OP_NOP_T2a = 0xF3AF,
ba379fdc
A
634 OP_LDRH_reg_T2 = 0xF830,
635 OP_LDRH_imm_T3 = 0xF830,
636 OP_STR_imm_T4 = 0xF840,
637 OP_STR_reg_T2 = 0xF840,
638 OP_LDR_imm_T4 = 0xF850,
639 OP_LDR_reg_T2 = 0xF850,
640 OP_LDRH_imm_T2 = 0xF8B0,
641 OP_STR_imm_T3 = 0xF8C0,
642 OP_LDR_imm_T3 = 0xF8D0,
643 OP_LSL_reg_T2 = 0xFA00,
644 OP_LSR_reg_T2 = 0xFA20,
645 OP_ASR_reg_T2 = 0xFA40,
646 OP_ROR_reg_T2 = 0xFA60,
647 OP_SMULL_T1 = 0xFB80,
648 } OpcodeID1;
649
650 typedef enum {
651 OP_B_T4b = 0x9000,
f9bf01c6 652 OP_NOP_T2b = 0x8000,
ba379fdc
A
653 } OpcodeID2;
654
655 struct FourFours {
656 FourFours(unsigned f3, unsigned f2, unsigned f1, unsigned f0)
657 {
658 m_u.f0 = f0;
659 m_u.f1 = f1;
660 m_u.f2 = f2;
661 m_u.f3 = f3;
662 }
663
664 union {
665 unsigned value;
666 struct {
667 unsigned f0 : 4;
668 unsigned f1 : 4;
669 unsigned f2 : 4;
670 unsigned f3 : 4;
671 };
672 } m_u;
673 };
674
675 class ARMInstructionFormatter;
676
677 // false means else!
678 bool ifThenElseConditionBit(Condition condition, bool isIf)
679 {
680 return isIf ? (condition & 1) : !(condition & 1);
681 }
682 uint8_t ifThenElse(Condition condition, bool inst2if, bool inst3if, bool inst4if)
683 {
684 int mask = (ifThenElseConditionBit(condition, inst2if) << 3)
685 | (ifThenElseConditionBit(condition, inst3if) << 2)
686 | (ifThenElseConditionBit(condition, inst4if) << 1)
687 | 1;
688 ASSERT((condition != ConditionAL) || (mask & (mask - 1)));
689 return (condition << 4) | mask;
690 }
691 uint8_t ifThenElse(Condition condition, bool inst2if, bool inst3if)
692 {
693 int mask = (ifThenElseConditionBit(condition, inst2if) << 3)
694 | (ifThenElseConditionBit(condition, inst3if) << 2)
695 | 2;
696 ASSERT((condition != ConditionAL) || (mask & (mask - 1)));
697 return (condition << 4) | mask;
698 }
699 uint8_t ifThenElse(Condition condition, bool inst2if)
700 {
701 int mask = (ifThenElseConditionBit(condition, inst2if) << 3)
702 | 4;
703 ASSERT((condition != ConditionAL) || (mask & (mask - 1)));
704 return (condition << 4) | mask;
705 }
706
707 uint8_t ifThenElse(Condition condition)
708 {
709 int mask = 8;
710 ASSERT((condition != ConditionAL) || (mask & (mask - 1)));
711 return (condition << 4) | mask;
712 }
713
714public:
715
716 void add(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
717 {
718 // Rd can only be SP if Rn is also SP.
f9bf01c6
A
719 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
720 ASSERT(rd != ARMRegisters::pc);
721 ASSERT(rn != ARMRegisters::pc);
ba379fdc
A
722 ASSERT(imm.isValid());
723
f9bf01c6 724 if (rn == ARMRegisters::sp) {
ba379fdc
A
725 if (!(rd & 8) && imm.isUInt10()) {
726 m_formatter.oneWordOp5Reg3Imm8(OP_ADD_SP_imm_T1, rd, imm.getUInt10() >> 2);
727 return;
f9bf01c6 728 } else if ((rd == ARMRegisters::sp) && imm.isUInt9()) {
ba379fdc
A
729 m_formatter.oneWordOp9Imm7(OP_ADD_SP_imm_T2, imm.getUInt9() >> 2);
730 return;
731 }
732 } else if (!((rd | rn) & 8)) {
733 if (imm.isUInt3()) {
734 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_imm_T1, (RegisterID)imm.getUInt3(), rn, rd);
735 return;
736 } else if ((rd == rn) && imm.isUInt8()) {
737 m_formatter.oneWordOp5Reg3Imm8(OP_ADD_imm_T2, rd, imm.getUInt8());
738 return;
739 }
740 }
741
742 if (imm.isEncodedImm())
743 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T3, rn, rd, imm);
744 else {
745 ASSERT(imm.isUInt12());
746 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T4, rn, rd, imm);
747 }
748 }
749
750 void add(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
751 {
f9bf01c6
A
752 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
753 ASSERT(rd != ARMRegisters::pc);
754 ASSERT(rn != ARMRegisters::pc);
ba379fdc
A
755 ASSERT(!BadReg(rm));
756 m_formatter.twoWordOp12Reg4FourFours(OP_ADD_reg_T3, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
757 }
758
759 // NOTE: In an IT block, add doesn't modify the flags register.
760 void add(RegisterID rd, RegisterID rn, RegisterID rm)
761 {
762 if (rd == rn)
763 m_formatter.oneWordOp8RegReg143(OP_ADD_reg_T2, rm, rd);
764 else if (rd == rm)
765 m_formatter.oneWordOp8RegReg143(OP_ADD_reg_T2, rn, rd);
766 else if (!((rd | rn | rm) & 8))
767 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_reg_T1, rm, rn, rd);
768 else
769 add(rd, rn, rm, ShiftTypeAndAmount());
770 }
771
772 // Not allowed in an IT (if then) block.
773 void add_S(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
774 {
775 // Rd can only be SP if Rn is also SP.
f9bf01c6
A
776 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
777 ASSERT(rd != ARMRegisters::pc);
778 ASSERT(rn != ARMRegisters::pc);
ba379fdc
A
779 ASSERT(imm.isEncodedImm());
780
781 if (!((rd | rn) & 8)) {
782 if (imm.isUInt3()) {
783 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_S_imm_T1, (RegisterID)imm.getUInt3(), rn, rd);
784 return;
785 } else if ((rd == rn) && imm.isUInt8()) {
786 m_formatter.oneWordOp5Reg3Imm8(OP_ADD_S_imm_T2, rd, imm.getUInt8());
787 return;
788 }
789 }
790
791 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_S_imm_T3, rn, rd, imm);
792 }
793
794 // Not allowed in an IT (if then) block?
795 void add_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
796 {
f9bf01c6
A
797 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
798 ASSERT(rd != ARMRegisters::pc);
799 ASSERT(rn != ARMRegisters::pc);
ba379fdc
A
800 ASSERT(!BadReg(rm));
801 m_formatter.twoWordOp12Reg4FourFours(OP_ADD_S_reg_T3, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
802 }
803
804 // Not allowed in an IT (if then) block.
805 void add_S(RegisterID rd, RegisterID rn, RegisterID rm)
806 {
807 if (!((rd | rn | rm) & 8))
808 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_S_reg_T1, rm, rn, rd);
809 else
810 add_S(rd, rn, rm, ShiftTypeAndAmount());
811 }
812
813 void ARM_and(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
814 {
815 ASSERT(!BadReg(rd));
816 ASSERT(!BadReg(rn));
817 ASSERT(imm.isEncodedImm());
818 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_AND_imm_T1, rn, rd, imm);
819 }
820
821 void ARM_and(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
822 {
823 ASSERT(!BadReg(rd));
824 ASSERT(!BadReg(rn));
825 ASSERT(!BadReg(rm));
826 m_formatter.twoWordOp12Reg4FourFours(OP_AND_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
827 }
828
829 void ARM_and(RegisterID rd, RegisterID rn, RegisterID rm)
830 {
831 if ((rd == rn) && !((rd | rm) & 8))
832 m_formatter.oneWordOp10Reg3Reg3(OP_AND_reg_T1, rm, rd);
833 else if ((rd == rm) && !((rd | rn) & 8))
834 m_formatter.oneWordOp10Reg3Reg3(OP_AND_reg_T1, rn, rd);
835 else
836 ARM_and(rd, rn, rm, ShiftTypeAndAmount());
837 }
838
839 void asr(RegisterID rd, RegisterID rm, int32_t shiftAmount)
840 {
841 ASSERT(!BadReg(rd));
842 ASSERT(!BadReg(rm));
843 ShiftTypeAndAmount shift(SRType_ASR, shiftAmount);
844 m_formatter.twoWordOp16FourFours(OP_ASR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
845 }
846
847 void asr(RegisterID rd, RegisterID rn, RegisterID rm)
848 {
849 ASSERT(!BadReg(rd));
850 ASSERT(!BadReg(rn));
851 ASSERT(!BadReg(rm));
852 m_formatter.twoWordOp12Reg4FourFours(OP_ASR_reg_T2, rn, FourFours(0xf, rd, 0, rm));
853 }
854
855 // Only allowed in IT (if then) block if last instruction.
856 JmpSrc b()
857 {
858 m_formatter.twoWordOp16Op16(OP_B_T4a, OP_B_T4b);
859 return JmpSrc(m_formatter.size());
860 }
861
862 // Only allowed in IT (if then) block if last instruction.
863 JmpSrc blx(RegisterID rm)
864 {
f9bf01c6 865 ASSERT(rm != ARMRegisters::pc);
ba379fdc
A
866 m_formatter.oneWordOp8RegReg143(OP_BLX, rm, (RegisterID)8);
867 return JmpSrc(m_formatter.size());
868 }
869
870 // Only allowed in IT (if then) block if last instruction.
871 JmpSrc bx(RegisterID rm)
872 {
873 m_formatter.oneWordOp8RegReg143(OP_BX, rm, (RegisterID)0);
874 return JmpSrc(m_formatter.size());
875 }
876
877 void bkpt(uint8_t imm=0)
878 {
879 m_formatter.oneWordOp8Imm8(OP_BKPT, imm);
880 }
881
882 void cmn(RegisterID rn, ARMThumbImmediate imm)
883 {
f9bf01c6 884 ASSERT(rn != ARMRegisters::pc);
ba379fdc
A
885 ASSERT(imm.isEncodedImm());
886
887 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMN_imm, rn, (RegisterID)0xf, imm);
888 }
889
890 void cmp(RegisterID rn, ARMThumbImmediate imm)
891 {
f9bf01c6 892 ASSERT(rn != ARMRegisters::pc);
ba379fdc
A
893 ASSERT(imm.isEncodedImm());
894
895 if (!(rn & 8) && imm.isUInt8())
896 m_formatter.oneWordOp5Reg3Imm8(OP_CMP_imm_T1, rn, imm.getUInt8());
897 else
898 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMP_imm_T2, rn, (RegisterID)0xf, imm);
899 }
900
901 void cmp(RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
902 {
f9bf01c6 903 ASSERT(rn != ARMRegisters::pc);
ba379fdc
A
904 ASSERT(!BadReg(rm));
905 m_formatter.twoWordOp12Reg4FourFours(OP_CMP_reg_T2, rn, FourFours(shift.hi4(), 0xf, shift.lo4(), rm));
906 }
907
908 void cmp(RegisterID rn, RegisterID rm)
909 {
910 if ((rn | rm) & 8)
911 cmp(rn, rm, ShiftTypeAndAmount());
912 else
913 m_formatter.oneWordOp10Reg3Reg3(OP_CMP_reg_T1, rm, rn);
914 }
915
916 // xor is not spelled with an 'e'. :-(
917 void eor(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
918 {
919 ASSERT(!BadReg(rd));
920 ASSERT(!BadReg(rn));
921 ASSERT(imm.isEncodedImm());
922 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_EOR_imm_T1, rn, rd, imm);
923 }
924
925 // xor is not spelled with an 'e'. :-(
926 void eor(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
927 {
928 ASSERT(!BadReg(rd));
929 ASSERT(!BadReg(rn));
930 ASSERT(!BadReg(rm));
931 m_formatter.twoWordOp12Reg4FourFours(OP_EOR_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
932 }
933
934 // xor is not spelled with an 'e'. :-(
935 void eor(RegisterID rd, RegisterID rn, RegisterID rm)
936 {
937 if ((rd == rn) && !((rd | rm) & 8))
938 m_formatter.oneWordOp10Reg3Reg3(OP_EOR_reg_T1, rm, rd);
939 else if ((rd == rm) && !((rd | rn) & 8))
940 m_formatter.oneWordOp10Reg3Reg3(OP_EOR_reg_T1, rn, rd);
941 else
942 eor(rd, rn, rm, ShiftTypeAndAmount());
943 }
944
945 void it(Condition cond)
946 {
947 m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond));
948 }
949
950 void it(Condition cond, bool inst2if)
951 {
952 m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if));
953 }
954
955 void it(Condition cond, bool inst2if, bool inst3if)
956 {
957 m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if, inst3if));
958 }
959
960 void it(Condition cond, bool inst2if, bool inst3if, bool inst4if)
961 {
962 m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if, inst3if, inst4if));
963 }
964
f9bf01c6 965 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
ba379fdc
A
966 void ldr(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
967 {
f9bf01c6 968 ASSERT(rn != ARMRegisters::pc); // LDR (literal)
ba379fdc
A
969 ASSERT(imm.isUInt12());
970
971 if (!((rt | rn) & 8) && imm.isUInt7())
972 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDR_imm_T1, imm.getUInt7() >> 2, rn, rt);
f9bf01c6 973 else if ((rn == ARMRegisters::sp) && !(rt & 8) && imm.isUInt10())
ba379fdc
A
974 m_formatter.oneWordOp5Reg3Imm8(OP_LDR_imm_T2, rt, imm.getUInt10() >> 2);
975 else
976 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T3, rn, rt, imm.getUInt12());
977 }
978
979 // If index is set, this is a regular offset or a pre-indexed load;
980 // if index is not set then is is a post-index load.
981 //
982 // If wback is set rn is updated - this is a pre or post index load,
983 // if wback is not set this is a regular offset memory access.
984 //
985 // (-255 <= offset <= 255)
986 // _reg = REG[rn]
987 // _tmp = _reg + offset
988 // MEM[index ? _tmp : _reg] = REG[rt]
989 // if (wback) REG[rn] = _tmp
990 void ldr(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
991 {
f9bf01c6
A
992 ASSERT(rt != ARMRegisters::pc);
993 ASSERT(rn != ARMRegisters::pc);
ba379fdc
A
994 ASSERT(index || wback);
995 ASSERT(!wback | (rt != rn));
996
997 bool add = true;
998 if (offset < 0) {
999 add = false;
1000 offset = -offset;
1001 }
1002 ASSERT((offset & ~0xff) == 0);
1003
1004 offset |= (wback << 8);
1005 offset |= (add << 9);
1006 offset |= (index << 10);
1007 offset |= (1 << 11);
1008
1009 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T4, rn, rt, offset);
1010 }
1011
f9bf01c6 1012 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
ba379fdc
A
1013 void ldr(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0)
1014 {
f9bf01c6 1015 ASSERT(rn != ARMRegisters::pc); // LDR (literal)
ba379fdc
A
1016 ASSERT(!BadReg(rm));
1017 ASSERT(shift <= 3);
1018
1019 if (!shift && !((rt | rn | rm) & 8))
1020 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDR_reg_T1, rm, rn, rt);
1021 else
1022 m_formatter.twoWordOp12Reg4FourFours(OP_LDR_reg_T2, rn, FourFours(rt, 0, shift, rm));
1023 }
1024
f9bf01c6 1025 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
ba379fdc
A
1026 void ldrh(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
1027 {
f9bf01c6 1028 ASSERT(rn != ARMRegisters::pc); // LDR (literal)
ba379fdc
A
1029 ASSERT(imm.isUInt12());
1030
1031 if (!((rt | rn) & 8) && imm.isUInt6())
1032 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDRH_imm_T1, imm.getUInt6() >> 2, rn, rt);
1033 else
1034 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T2, rn, rt, imm.getUInt12());
1035 }
1036
1037 // If index is set, this is a regular offset or a pre-indexed load;
1038 // if index is not set then is is a post-index load.
1039 //
1040 // If wback is set rn is updated - this is a pre or post index load,
1041 // if wback is not set this is a regular offset memory access.
1042 //
1043 // (-255 <= offset <= 255)
1044 // _reg = REG[rn]
1045 // _tmp = _reg + offset
1046 // MEM[index ? _tmp : _reg] = REG[rt]
1047 // if (wback) REG[rn] = _tmp
1048 void ldrh(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
1049 {
f9bf01c6
A
1050 ASSERT(rt != ARMRegisters::pc);
1051 ASSERT(rn != ARMRegisters::pc);
ba379fdc
A
1052 ASSERT(index || wback);
1053 ASSERT(!wback | (rt != rn));
1054
1055 bool add = true;
1056 if (offset < 0) {
1057 add = false;
1058 offset = -offset;
1059 }
1060 ASSERT((offset & ~0xff) == 0);
1061
1062 offset |= (wback << 8);
1063 offset |= (add << 9);
1064 offset |= (index << 10);
1065 offset |= (1 << 11);
1066
1067 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T3, rn, rt, offset);
1068 }
1069
1070 void ldrh(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0)
1071 {
1072 ASSERT(!BadReg(rt)); // Memory hint
f9bf01c6 1073 ASSERT(rn != ARMRegisters::pc); // LDRH (literal)
ba379fdc
A
1074 ASSERT(!BadReg(rm));
1075 ASSERT(shift <= 3);
1076
1077 if (!shift && !((rt | rn | rm) & 8))
1078 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDRH_reg_T1, rm, rn, rt);
1079 else
1080 m_formatter.twoWordOp12Reg4FourFours(OP_LDRH_reg_T2, rn, FourFours(rt, 0, shift, rm));
1081 }
1082
1083 void lsl(RegisterID rd, RegisterID rm, int32_t shiftAmount)
1084 {
1085 ASSERT(!BadReg(rd));
1086 ASSERT(!BadReg(rm));
1087 ShiftTypeAndAmount shift(SRType_LSL, shiftAmount);
1088 m_formatter.twoWordOp16FourFours(OP_LSL_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1089 }
1090
1091 void lsl(RegisterID rd, RegisterID rn, RegisterID rm)
1092 {
1093 ASSERT(!BadReg(rd));
1094 ASSERT(!BadReg(rn));
1095 ASSERT(!BadReg(rm));
1096 m_formatter.twoWordOp12Reg4FourFours(OP_LSL_reg_T2, rn, FourFours(0xf, rd, 0, rm));
1097 }
1098
1099 void lsr(RegisterID rd, RegisterID rm, int32_t shiftAmount)
1100 {
1101 ASSERT(!BadReg(rd));
1102 ASSERT(!BadReg(rm));
1103 ShiftTypeAndAmount shift(SRType_LSR, shiftAmount);
1104 m_formatter.twoWordOp16FourFours(OP_LSR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1105 }
1106
1107 void lsr(RegisterID rd, RegisterID rn, RegisterID rm)
1108 {
1109 ASSERT(!BadReg(rd));
1110 ASSERT(!BadReg(rn));
1111 ASSERT(!BadReg(rm));
1112 m_formatter.twoWordOp12Reg4FourFours(OP_LSR_reg_T2, rn, FourFours(0xf, rd, 0, rm));
1113 }
1114
1115 void movT3(RegisterID rd, ARMThumbImmediate imm)
1116 {
1117 ASSERT(imm.isValid());
1118 ASSERT(!imm.isEncodedImm());
1119 ASSERT(!BadReg(rd));
1120
1121 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T3, imm.m_value.imm4, rd, imm);
1122 }
1123
1124 void mov(RegisterID rd, ARMThumbImmediate imm)
1125 {
1126 ASSERT(imm.isValid());
1127 ASSERT(!BadReg(rd));
1128
1129 if ((rd < 8) && imm.isUInt8())
1130 m_formatter.oneWordOp5Reg3Imm8(OP_MOV_imm_T1, rd, imm.getUInt8());
1131 else if (imm.isEncodedImm())
1132 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T2, 0xf, rd, imm);
1133 else
1134 movT3(rd, imm);
1135 }
1136
1137 void mov(RegisterID rd, RegisterID rm)
1138 {
1139 m_formatter.oneWordOp8RegReg143(OP_MOV_reg_T1, rm, rd);
1140 }
1141
1142 void movt(RegisterID rd, ARMThumbImmediate imm)
1143 {
1144 ASSERT(imm.isUInt16());
1145 ASSERT(!BadReg(rd));
1146 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOVT, imm.m_value.imm4, rd, imm);
1147 }
1148
1149 void mvn(RegisterID rd, ARMThumbImmediate imm)
1150 {
1151 ASSERT(imm.isEncodedImm());
1152 ASSERT(!BadReg(rd));
1153
1154 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MVN_imm, 0xf, rd, imm);
1155 }
1156
1157 void mvn(RegisterID rd, RegisterID rm, ShiftTypeAndAmount shift)
1158 {
1159 ASSERT(!BadReg(rd));
1160 ASSERT(!BadReg(rm));
1161 m_formatter.twoWordOp16FourFours(OP_MVN_reg_T2, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1162 }
1163
1164 void mvn(RegisterID rd, RegisterID rm)
1165 {
1166 if (!((rd | rm) & 8))
1167 m_formatter.oneWordOp10Reg3Reg3(OP_MVN_reg_T1, rm, rd);
1168 else
1169 mvn(rd, rm, ShiftTypeAndAmount());
1170 }
1171
1172 void orr(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
1173 {
1174 ASSERT(!BadReg(rd));
1175 ASSERT(!BadReg(rn));
1176 ASSERT(imm.isEncodedImm());
1177 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ORR_imm_T1, rn, rd, imm);
1178 }
1179
1180 void orr(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
1181 {
1182 ASSERT(!BadReg(rd));
1183 ASSERT(!BadReg(rn));
1184 ASSERT(!BadReg(rm));
1185 m_formatter.twoWordOp12Reg4FourFours(OP_ORR_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1186 }
1187
1188 void orr(RegisterID rd, RegisterID rn, RegisterID rm)
1189 {
1190 if ((rd == rn) && !((rd | rm) & 8))
1191 m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rm, rd);
1192 else if ((rd == rm) && !((rd | rn) & 8))
1193 m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rn, rd);
1194 else
1195 orr(rd, rn, rm, ShiftTypeAndAmount());
1196 }
1197
1198 void ror(RegisterID rd, RegisterID rm, int32_t shiftAmount)
1199 {
1200 ASSERT(!BadReg(rd));
1201 ASSERT(!BadReg(rm));
1202 ShiftTypeAndAmount shift(SRType_ROR, shiftAmount);
1203 m_formatter.twoWordOp16FourFours(OP_ROR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1204 }
1205
1206 void ror(RegisterID rd, RegisterID rn, RegisterID rm)
1207 {
1208 ASSERT(!BadReg(rd));
1209 ASSERT(!BadReg(rn));
1210 ASSERT(!BadReg(rm));
1211 m_formatter.twoWordOp12Reg4FourFours(OP_ROR_reg_T2, rn, FourFours(0xf, rd, 0, rm));
1212 }
1213
1214 void smull(RegisterID rdLo, RegisterID rdHi, RegisterID rn, RegisterID rm)
1215 {
1216 ASSERT(!BadReg(rdLo));
1217 ASSERT(!BadReg(rdHi));
1218 ASSERT(!BadReg(rn));
1219 ASSERT(!BadReg(rm));
1220 ASSERT(rdLo != rdHi);
1221 m_formatter.twoWordOp12Reg4FourFours(OP_SMULL_T1, rn, FourFours(rdLo, rdHi, 0, rm));
1222 }
1223
f9bf01c6 1224 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
ba379fdc
A
1225 void str(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
1226 {
f9bf01c6
A
1227 ASSERT(rt != ARMRegisters::pc);
1228 ASSERT(rn != ARMRegisters::pc);
ba379fdc
A
1229 ASSERT(imm.isUInt12());
1230
1231 if (!((rt | rn) & 8) && imm.isUInt7())
1232 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_STR_imm_T1, imm.getUInt7() >> 2, rn, rt);
f9bf01c6 1233 else if ((rn == ARMRegisters::sp) && !(rt & 8) && imm.isUInt10())
ba379fdc
A
1234 m_formatter.oneWordOp5Reg3Imm8(OP_STR_imm_T2, rt, imm.getUInt10() >> 2);
1235 else
1236 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T3, rn, rt, imm.getUInt12());
1237 }
1238
1239 // If index is set, this is a regular offset or a pre-indexed store;
1240 // if index is not set then is is a post-index store.
1241 //
1242 // If wback is set rn is updated - this is a pre or post index store,
1243 // if wback is not set this is a regular offset memory access.
1244 //
1245 // (-255 <= offset <= 255)
1246 // _reg = REG[rn]
1247 // _tmp = _reg + offset
1248 // MEM[index ? _tmp : _reg] = REG[rt]
1249 // if (wback) REG[rn] = _tmp
1250 void str(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
1251 {
f9bf01c6
A
1252 ASSERT(rt != ARMRegisters::pc);
1253 ASSERT(rn != ARMRegisters::pc);
ba379fdc
A
1254 ASSERT(index || wback);
1255 ASSERT(!wback | (rt != rn));
1256
1257 bool add = true;
1258 if (offset < 0) {
1259 add = false;
1260 offset = -offset;
1261 }
1262 ASSERT((offset & ~0xff) == 0);
1263
1264 offset |= (wback << 8);
1265 offset |= (add << 9);
1266 offset |= (index << 10);
1267 offset |= (1 << 11);
1268
1269 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T4, rn, rt, offset);
1270 }
1271
f9bf01c6 1272 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
ba379fdc
A
1273 void str(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0)
1274 {
f9bf01c6 1275 ASSERT(rn != ARMRegisters::pc);
ba379fdc
A
1276 ASSERT(!BadReg(rm));
1277 ASSERT(shift <= 3);
1278
1279 if (!shift && !((rt | rn | rm) & 8))
1280 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_STR_reg_T1, rm, rn, rt);
1281 else
1282 m_formatter.twoWordOp12Reg4FourFours(OP_STR_reg_T2, rn, FourFours(rt, 0, shift, rm));
1283 }
1284
1285 void sub(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
1286 {
1287 // Rd can only be SP if Rn is also SP.
f9bf01c6
A
1288 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
1289 ASSERT(rd != ARMRegisters::pc);
1290 ASSERT(rn != ARMRegisters::pc);
ba379fdc
A
1291 ASSERT(imm.isValid());
1292
f9bf01c6 1293 if ((rn == ARMRegisters::sp) && (rd == ARMRegisters::sp) && imm.isUInt9()) {
ba379fdc
A
1294 m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, imm.getUInt9() >> 2);
1295 return;
1296 } else if (!((rd | rn) & 8)) {
1297 if (imm.isUInt3()) {
1298 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_imm_T1, (RegisterID)imm.getUInt3(), rn, rd);
1299 return;
1300 } else if ((rd == rn) && imm.isUInt8()) {
1301 m_formatter.oneWordOp5Reg3Imm8(OP_SUB_imm_T2, rd, imm.getUInt8());
1302 return;
1303 }
1304 }
1305
1306 if (imm.isEncodedImm())
1307 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T3, rn, rd, imm);
1308 else {
1309 ASSERT(imm.isUInt12());
1310 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T4, rn, rd, imm);
1311 }
1312 }
1313
1314 void sub(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
1315 {
f9bf01c6
A
1316 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
1317 ASSERT(rd != ARMRegisters::pc);
1318 ASSERT(rn != ARMRegisters::pc);
ba379fdc
A
1319 ASSERT(!BadReg(rm));
1320 m_formatter.twoWordOp12Reg4FourFours(OP_SUB_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1321 }
1322
1323 // NOTE: In an IT block, add doesn't modify the flags register.
1324 void sub(RegisterID rd, RegisterID rn, RegisterID rm)
1325 {
1326 if (!((rd | rn | rm) & 8))
1327 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_reg_T1, rm, rn, rd);
1328 else
1329 sub(rd, rn, rm, ShiftTypeAndAmount());
1330 }
1331
1332 // Not allowed in an IT (if then) block.
1333 void sub_S(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
1334 {
1335 // Rd can only be SP if Rn is also SP.
f9bf01c6
A
1336 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
1337 ASSERT(rd != ARMRegisters::pc);
1338 ASSERT(rn != ARMRegisters::pc);
ba379fdc
A
1339 ASSERT(imm.isValid());
1340
f9bf01c6 1341 if ((rn == ARMRegisters::sp) && (rd == ARMRegisters::sp) && imm.isUInt9()) {
ba379fdc
A
1342 m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, imm.getUInt9() >> 2);
1343 return;
1344 } else if (!((rd | rn) & 8)) {
1345 if (imm.isUInt3()) {
1346 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_S_imm_T1, (RegisterID)imm.getUInt3(), rn, rd);
1347 return;
1348 } else if ((rd == rn) && imm.isUInt8()) {
1349 m_formatter.oneWordOp5Reg3Imm8(OP_SUB_S_imm_T2, rd, imm.getUInt8());
1350 return;
1351 }
1352 }
1353
1354 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_S_imm_T3, rn, rd, imm);
1355 }
1356
1357 // Not allowed in an IT (if then) block?
1358 void sub_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
1359 {
f9bf01c6
A
1360 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
1361 ASSERT(rd != ARMRegisters::pc);
1362 ASSERT(rn != ARMRegisters::pc);
ba379fdc
A
1363 ASSERT(!BadReg(rm));
1364 m_formatter.twoWordOp12Reg4FourFours(OP_SUB_S_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1365 }
1366
1367 // Not allowed in an IT (if then) block.
1368 void sub_S(RegisterID rd, RegisterID rn, RegisterID rm)
1369 {
1370 if (!((rd | rn | rm) & 8))
1371 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_S_reg_T1, rm, rn, rd);
1372 else
1373 sub_S(rd, rn, rm, ShiftTypeAndAmount());
1374 }
1375
1376 void tst(RegisterID rn, ARMThumbImmediate imm)
1377 {
1378 ASSERT(!BadReg(rn));
1379 ASSERT(imm.isEncodedImm());
1380
1381 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_TST_imm, rn, (RegisterID)0xf, imm);
1382 }
1383
1384 void tst(RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
1385 {
1386 ASSERT(!BadReg(rn));
1387 ASSERT(!BadReg(rm));
1388 m_formatter.twoWordOp12Reg4FourFours(OP_TST_reg_T2, rn, FourFours(shift.hi4(), 0xf, shift.lo4(), rm));
1389 }
1390
1391 void tst(RegisterID rn, RegisterID rm)
1392 {
1393 if ((rn | rm) & 8)
1394 tst(rn, rm, ShiftTypeAndAmount());
1395 else
1396 m_formatter.oneWordOp10Reg3Reg3(OP_TST_reg_T1, rm, rn);
1397 }
1398
1399 void vadd_F64(FPRegisterID rd, FPRegisterID rn, FPRegisterID rm)
1400 {
1401 m_formatter.vfpOp(0x0b00ee30 | doubleRegisterMask(rd, 6, 28) | doubleRegisterMask(rn, 23, 0) | doubleRegisterMask(rm, 21, 16));
1402 }
1403
1404 void vcmp_F64(FPRegisterID rd, FPRegisterID rm)
1405 {
1406 m_formatter.vfpOp(0x0bc0eeb4 | doubleRegisterMask(rd, 6, 28) | doubleRegisterMask(rm, 21, 16));
1407 }
1408
1409 void vcvt_F64_S32(FPRegisterID fd, FPRegisterID sm)
1410 {
1411 m_formatter.vfpOp(0x0bc0eeb8 | doubleRegisterMask(fd, 6, 28) | singleRegisterMask(sm, 16, 21));
1412 }
1413
1414 void vcvt_S32_F64(FPRegisterID sd, FPRegisterID fm)
1415 {
1416 m_formatter.vfpOp(0x0bc0eebd | singleRegisterMask(sd, 28, 6) | doubleRegisterMask(fm, 21, 16));
1417 }
1418
1419 void vldr(FPRegisterID rd, RegisterID rn, int32_t imm)
1420 {
1421 vmem(rd, rn, imm, true);
1422 }
1423
1424 void vmov(RegisterID rd, FPRegisterID sn)
1425 {
1426 m_formatter.vfpOp(0x0a10ee10 | (rd << 28) | singleRegisterMask(sn, 0, 23));
1427 }
1428
1429 void vmov(FPRegisterID sn, RegisterID rd)
1430 {
1431 m_formatter.vfpOp(0x0a10ee00 | (rd << 28) | singleRegisterMask(sn, 0, 23));
1432 }
1433
1434 // move FPSCR flags to APSR.
1435 void vmrs_APSR_nzcv_FPSCR()
1436 {
1437 m_formatter.vfpOp(0xfa10eef1);
1438 }
1439
1440 void vmul_F64(FPRegisterID rd, FPRegisterID rn, FPRegisterID rm)
1441 {
1442 m_formatter.vfpOp(0x0b00ee20 | doubleRegisterMask(rd, 6, 28) | doubleRegisterMask(rn, 23, 0) | doubleRegisterMask(rm, 21, 16));
1443 }
1444
1445 void vstr(FPRegisterID rd, RegisterID rn, int32_t imm)
1446 {
1447 vmem(rd, rn, imm, false);
1448 }
1449
1450 void vsub_F64(FPRegisterID rd, FPRegisterID rn, FPRegisterID rm)
1451 {
1452 m_formatter.vfpOp(0x0b40ee30 | doubleRegisterMask(rd, 6, 28) | doubleRegisterMask(rn, 23, 0) | doubleRegisterMask(rm, 21, 16));
1453 }
1454
1455
1456 JmpDst label()
1457 {
1458 return JmpDst(m_formatter.size());
1459 }
1460
1461 JmpDst align(int alignment)
1462 {
1463 while (!m_formatter.isAligned(alignment))
1464 bkpt();
1465
1466 return label();
1467 }
1468
1469 static void* getRelocatedAddress(void* code, JmpSrc jump)
1470 {
1471 ASSERT(jump.m_offset != -1);
1472
1473 return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + jump.m_offset);
1474 }
1475
1476 static void* getRelocatedAddress(void* code, JmpDst destination)
1477 {
1478 ASSERT(destination.m_offset != -1);
1479
1480 return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + destination.m_offset);
1481 }
1482
1483 static int getDifferenceBetweenLabels(JmpDst src, JmpDst dst)
1484 {
1485 return dst.m_offset - src.m_offset;
1486 }
1487
1488 static int getDifferenceBetweenLabels(JmpDst src, JmpSrc dst)
1489 {
1490 return dst.m_offset - src.m_offset;
1491 }
1492
1493 static int getDifferenceBetweenLabels(JmpSrc src, JmpDst dst)
1494 {
1495 return dst.m_offset - src.m_offset;
1496 }
1497
1498 // Assembler admin methods:
1499
1500 size_t size() const
1501 {
1502 return m_formatter.size();
1503 }
1504
1505 void* executableCopy(ExecutablePool* allocator)
1506 {
1507 void* copy = m_formatter.executableCopy(allocator);
f9bf01c6
A
1508
1509 unsigned jumpCount = m_jumpsToLink.size();
1510 for (unsigned i = 0; i < jumpCount; ++i) {
1511 uint16_t* location = reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(copy) + m_jumpsToLink[i].from);
1512 uint16_t* target = reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(copy) + m_jumpsToLink[i].to);
1513 linkJumpAbsolute(location, target);
1514 }
1515 m_jumpsToLink.clear();
1516
ba379fdc
A
1517 ASSERT(copy);
1518 return copy;
1519 }
1520
1521 static unsigned getCallReturnOffset(JmpSrc call)
1522 {
1523 ASSERT(call.m_offset >= 0);
1524 return call.m_offset;
1525 }
1526
1527 // Linking & patching:
1528 //
1529 // 'link' and 'patch' methods are for use on unprotected code - such as the code
1530 // within the AssemblerBuffer, and code being patched by the patch buffer. Once
1531 // code has been finalized it is (platform support permitting) within a non-
1532 // writable region of memory; to modify the code in an execute-only execuable
1533 // pool the 'repatch' and 'relink' methods should be used.
1534
1535 void linkJump(JmpSrc from, JmpDst to)
1536 {
1537 ASSERT(to.m_offset != -1);
1538 ASSERT(from.m_offset != -1);
f9bf01c6 1539 m_jumpsToLink.append(LinkRecord(from.m_offset, to.m_offset));
ba379fdc
A
1540 }
1541
1542 static void linkJump(void* code, JmpSrc from, void* to)
1543 {
1544 ASSERT(from.m_offset != -1);
1545
1546 uint16_t* location = reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
f9bf01c6 1547 linkJumpAbsolute(location, to);
ba379fdc
A
1548 }
1549
1550 // bah, this mathod should really be static, since it is used by the LinkBuffer.
1551 // return a bool saying whether the link was successful?
1552 static void linkCall(void* code, JmpSrc from, void* to)
1553 {
1554 ASSERT(!(reinterpret_cast<intptr_t>(code) & 1));
1555 ASSERT(from.m_offset != -1);
1556 ASSERT(reinterpret_cast<intptr_t>(to) & 1);
1557
1558 setPointer(reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code) + from.m_offset) - 1, to);
1559 }
1560
1561 static void linkPointer(void* code, JmpDst where, void* value)
1562 {
1563 setPointer(reinterpret_cast<char*>(code) + where.m_offset, value);
1564 }
1565
1566 static void relinkJump(void* from, void* to)
1567 {
1568 ASSERT(!(reinterpret_cast<intptr_t>(from) & 1));
1569 ASSERT(!(reinterpret_cast<intptr_t>(to) & 1));
1570
f9bf01c6 1571 linkJumpAbsolute(reinterpret_cast<uint16_t*>(from), to);
ba379fdc 1572
f9bf01c6 1573 ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(from) - 5, 5 * sizeof(uint16_t));
ba379fdc
A
1574 }
1575
1576 static void relinkCall(void* from, void* to)
1577 {
1578 ASSERT(!(reinterpret_cast<intptr_t>(from) & 1));
1579 ASSERT(reinterpret_cast<intptr_t>(to) & 1);
1580
1581 setPointer(reinterpret_cast<uint16_t*>(from) - 1, to);
1582
1583 ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(from) - 5, 4 * sizeof(uint16_t));
1584 }
1585
1586 static void repatchInt32(void* where, int32_t value)
1587 {
1588 ASSERT(!(reinterpret_cast<intptr_t>(where) & 1));
1589
1590 setInt32(where, value);
1591
1592 ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(where) - 4, 4 * sizeof(uint16_t));
1593 }
1594
1595 static void repatchPointer(void* where, void* value)
1596 {
1597 ASSERT(!(reinterpret_cast<intptr_t>(where) & 1));
1598
1599 setPointer(where, value);
1600
1601 ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(where) - 4, 4 * sizeof(uint16_t));
1602 }
1603
1604 static void repatchLoadPtrToLEA(void* where)
1605 {
1606 ASSERT(!(reinterpret_cast<intptr_t>(where) & 1));
1607
1608 uint16_t* loadOp = reinterpret_cast<uint16_t*>(where) + 4;
1609 ASSERT((*loadOp & 0xfff0) == OP_LDR_reg_T2);
1610
1611 *loadOp = OP_ADD_reg_T3 | (*loadOp & 0xf);
1612 ExecutableAllocator::cacheFlush(loadOp, sizeof(uint16_t));
1613 }
1614
1615private:
1616
1617 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
1618 // (i.e. +/-(0..255) 32-bit words)
1619 void vmem(FPRegisterID rd, RegisterID rn, int32_t imm, bool isLoad)
1620 {
1621 bool up;
1622 uint32_t offset;
1623 if (imm < 0) {
1624 offset = -imm;
1625 up = false;
1626 } else {
1627 offset = imm;
1628 up = true;
1629 }
1630
1631 // offset is effectively leftshifted by 2 already (the bottom two bits are zero, and not
1632 // reperesented in the instruction. Left shift by 14, to mov it into position 0x00AA0000.
1633 ASSERT((offset & ~(0xff << 2)) == 0);
1634 offset <<= 14;
1635
1636 m_formatter.vfpOp(0x0b00ed00 | offset | (up << 7) | (isLoad << 4) | doubleRegisterMask(rd, 6, 28) | rn);
1637 }
1638
1639 static void setInt32(void* code, uint32_t value)
1640 {
1641 uint16_t* location = reinterpret_cast<uint16_t*>(code);
f9bf01c6 1642 ASSERT(isMOV_imm_T3(location - 4) && isMOVT(location - 2));
ba379fdc 1643
f9bf01c6
A
1644 ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(value));
1645 ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(value >> 16));
1646 location[-4] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16);
1647 location[-3] = twoWordOp5i6Imm4Reg4EncodedImmSecond((location[-3] >> 8) & 0xf, lo16);
1648 location[-2] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16);
1649 location[-1] = twoWordOp5i6Imm4Reg4EncodedImmSecond((location[-1] >> 8) & 0xf, hi16);
ba379fdc
A
1650
1651 ExecutableAllocator::cacheFlush(location - 4, 4 * sizeof(uint16_t));
1652 }
1653
1654 static void setPointer(void* code, void* value)
1655 {
1656 setInt32(code, reinterpret_cast<uint32_t>(value));
1657 }
1658
f9bf01c6
A
1659 static bool isB(void* address)
1660 {
1661 uint16_t* instruction = static_cast<uint16_t*>(address);
1662 return ((instruction[0] & 0xf800) == OP_B_T4a) && ((instruction[1] & 0xd000) == OP_B_T4b);
1663 }
ba379fdc 1664
f9bf01c6
A
1665 static bool isBX(void* address)
1666 {
1667 uint16_t* instruction = static_cast<uint16_t*>(address);
1668 return (instruction[0] & 0xff87) == OP_BX;
1669 }
ba379fdc 1670
f9bf01c6
A
1671 static bool isMOV_imm_T3(void* address)
1672 {
1673 uint16_t* instruction = static_cast<uint16_t*>(address);
1674 return ((instruction[0] & 0xFBF0) == OP_MOV_imm_T3) && ((instruction[1] & 0x8000) == 0);
1675 }
ba379fdc 1676
f9bf01c6
A
1677 static bool isMOVT(void* address)
1678 {
1679 uint16_t* instruction = static_cast<uint16_t*>(address);
1680 return ((instruction[0] & 0xFBF0) == OP_MOVT) && ((instruction[1] & 0x8000) == 0);
ba379fdc
A
1681 }
1682
f9bf01c6 1683 static bool isNOP_T1(void* address)
ba379fdc 1684 {
f9bf01c6
A
1685 uint16_t* instruction = static_cast<uint16_t*>(address);
1686 return instruction[0] == OP_NOP_T1;
ba379fdc 1687 }
f9bf01c6
A
1688
1689 static bool isNOP_T2(void* address)
ba379fdc 1690 {
f9bf01c6
A
1691 uint16_t* instruction = static_cast<uint16_t*>(address);
1692 return (instruction[0] == OP_NOP_T2a) && (instruction[1] == OP_NOP_T2b);
1693 }
1694
1695 static void linkJumpAbsolute(uint16_t* instruction, void* target)
1696 {
1697 // FIMXE: this should be up in the MacroAssembler layer. :-(
1698 const uint16_t JUMP_TEMPORARY_REGISTER = ARMRegisters::ip;
1699
1700 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
1701 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
1702
1703 ASSERT( (isMOV_imm_T3(instruction - 5) && isMOVT(instruction - 3) && isBX(instruction - 1))
1704 || (isNOP_T1(instruction - 5) && isNOP_T2(instruction - 4) && isB(instruction - 2)) );
1705
1706 intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction));
1707 if (((relative << 7) >> 7) == relative) {
1708 // ARM encoding for the top two bits below the sign bit is 'peculiar'.
1709 if (relative >= 0)
1710 relative ^= 0xC00000;
1711
1712 // All branch offsets should be an even distance.
1713 ASSERT(!(relative & 1));
1714 // There may be a better way to fix this, but right now put the NOPs first, since in the
1715 // case of an conditional branch this will be coming after an ITTT predicating *three*
1716 // instructions! Looking backwards to modify the ITTT to an IT is not easy, due to
1717 // variable wdith encoding - the previous instruction might *look* like an ITTT but
1718 // actually be the second half of a 2-word op.
1719 instruction[-5] = OP_NOP_T1;
1720 instruction[-4] = OP_NOP_T2a;
1721 instruction[-3] = OP_NOP_T2b;
1722 instruction[-2] = OP_B_T4a | ((relative & 0x1000000) >> 14) | ((relative & 0x3ff000) >> 12);
1723 instruction[-1] = OP_B_T4b | ((relative & 0x800000) >> 10) | ((relative & 0x400000) >> 11) | ((relative & 0xffe) >> 1);
1724 } else {
1725 ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) + 1));
1726 ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) >> 16));
1727 instruction[-5] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16);
1728 instruction[-4] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, lo16);
1729 instruction[-3] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16);
1730 instruction[-2] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, hi16);
1731 instruction[-1] = OP_BX | (JUMP_TEMPORARY_REGISTER << 3);
1732 }
1733 }
1734
1735 static uint16_t twoWordOp5i6Imm4Reg4EncodedImmFirst(uint16_t op, ARMThumbImmediate imm)
1736 {
1737 return op | (imm.m_value.i << 10) | imm.m_value.imm4;
1738 }
1739 static uint16_t twoWordOp5i6Imm4Reg4EncodedImmSecond(uint16_t rd, ARMThumbImmediate imm)
1740 {
1741 return (imm.m_value.imm3 << 12) | (rd << 8) | imm.m_value.imm8;
ba379fdc
A
1742 }
1743
1744 class ARMInstructionFormatter {
1745 public:
1746 void oneWordOp5Reg3Imm8(OpcodeID op, RegisterID rd, uint8_t imm)
1747 {
1748 m_buffer.putShort(op | (rd << 8) | imm);
1749 }
1750
1751 void oneWordOp5Imm5Reg3Reg3(OpcodeID op, uint8_t imm, RegisterID reg1, RegisterID reg2)
1752 {
1753 m_buffer.putShort(op | (imm << 6) | (reg1 << 3) | reg2);
1754 }
1755
1756 void oneWordOp7Reg3Reg3Reg3(OpcodeID op, RegisterID reg1, RegisterID reg2, RegisterID reg3)
1757 {
1758 m_buffer.putShort(op | (reg1 << 6) | (reg2 << 3) | reg3);
1759 }
1760
1761 void oneWordOp8Imm8(OpcodeID op, uint8_t imm)
1762 {
1763 m_buffer.putShort(op | imm);
1764 }
1765
1766 void oneWordOp8RegReg143(OpcodeID op, RegisterID reg1, RegisterID reg2)
1767 {
1768 m_buffer.putShort(op | ((reg2 & 8) << 4) | (reg1 << 3) | (reg2 & 7));
1769 }
1770 void oneWordOp9Imm7(OpcodeID op, uint8_t imm)
1771 {
1772 m_buffer.putShort(op | imm);
1773 }
1774
1775 void oneWordOp10Reg3Reg3(OpcodeID op, RegisterID reg1, RegisterID reg2)
1776 {
1777 m_buffer.putShort(op | (reg1 << 3) | reg2);
1778 }
1779
1780 void twoWordOp12Reg4FourFours(OpcodeID1 op, RegisterID reg, FourFours ff)
1781 {
1782 m_buffer.putShort(op | reg);
1783 m_buffer.putShort(ff.m_u.value);
1784 }
1785
1786 void twoWordOp16FourFours(OpcodeID1 op, FourFours ff)
1787 {
1788 m_buffer.putShort(op);
1789 m_buffer.putShort(ff.m_u.value);
1790 }
1791
1792 void twoWordOp16Op16(OpcodeID1 op1, OpcodeID2 op2)
1793 {
1794 m_buffer.putShort(op1);
1795 m_buffer.putShort(op2);
1796 }
1797
1798 void twoWordOp5i6Imm4Reg4EncodedImm(OpcodeID1 op, int imm4, RegisterID rd, ARMThumbImmediate imm)
1799 {
f9bf01c6
A
1800 ARMThumbImmediate newImm = imm;
1801 newImm.m_value.imm4 = imm4;
1802
1803 m_buffer.putShort(ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmFirst(op, newImm));
1804 m_buffer.putShort(ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmSecond(rd, newImm));
ba379fdc
A
1805 }
1806
1807 void twoWordOp12Reg4Reg4Imm12(OpcodeID1 op, RegisterID reg1, RegisterID reg2, uint16_t imm)
1808 {
1809 m_buffer.putShort(op | reg1);
1810 m_buffer.putShort((reg2 << 12) | imm);
1811 }
1812
1813 void vfpOp(int32_t op)
1814 {
1815 m_buffer.putInt(op);
1816 }
1817
1818
1819 // Administrative methods:
1820
1821 size_t size() const { return m_buffer.size(); }
1822 bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); }
1823 void* data() const { return m_buffer.data(); }
1824 void* executableCopy(ExecutablePool* allocator) { return m_buffer.executableCopy(allocator); }
1825
1826 private:
1827 AssemblerBuffer m_buffer;
1828 } m_formatter;
f9bf01c6
A
1829
1830 Vector<LinkRecord> m_jumpsToLink;
ba379fdc
A
1831};
1832
1833} // namespace JSC
1834
f9bf01c6 1835#endif // ENABLE(ASSEMBLER) && CPU(ARM_THUMB2)
ba379fdc
A
1836
1837#endif // ARMAssembler_h