2 * Copyright (C) 2009 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 #ifndef ARMAssembler_h
27 #define ARMAssembler_h
29 #include <wtf/Platform.h>
31 #if ENABLE(ASSEMBLER) && PLATFORM_ARM_ARCH(7)
33 #include "AssemblerBuffer.h"
34 #include <wtf/Assertions.h>
35 #include <wtf/Vector.h>
49 r7
, wr
= r7
, // thumb work register
51 r9
, sb
= r9
, // static base
52 r10
, sl
= r10
, // stack limit
53 r11
, fp
= r11
, // frame pointer
163 class ARMv7Assembler
;
164 class ARMThumbImmediate
{
165 friend class ARMv7Assembler
;
167 typedef uint8_t ThumbImmediateType
;
168 static const ThumbImmediateType TypeInvalid
= 0;
169 static const ThumbImmediateType TypeEncoded
= 1;
170 static const ThumbImmediateType TypeUInt16
= 2;
180 // If this is an encoded immediate, then it may describe a shift, or a pattern.
182 unsigned shiftValue7
: 7;
183 unsigned shiftAmount
: 5;
186 unsigned immediate
: 8;
187 unsigned pattern
: 4;
189 } ThumbImmediateValue
;
191 // byte0 contains least significant bit; not using an array to make client code endian agnostic.
202 ALWAYS_INLINE
static int32_t countLeadingZerosPartial(uint32_t& value
, int32_t& zeros
, const int N
)
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 */
210 static int32_t countLeadingZeros(uint32_t value
)
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);
225 : m_type(TypeInvalid
)
230 ARMThumbImmediate(ThumbImmediateType type
, ThumbImmediateValue value
)
236 ARMThumbImmediate(ThumbImmediateType type
, uint16_t value
)
239 m_value
.asInt
= value
;
243 static ARMThumbImmediate
makeEncodedImm(uint32_t value
)
245 ThumbImmediateValue encoding
;
248 // okay, these are easy.
250 encoding
.immediate
= value
;
251 encoding
.pattern
= 0;
252 return ARMThumbImmediate(TypeEncoded
, encoding
);
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);
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
);
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
);
281 if ((bytes
.byte0
== bytes
.byte2
) && !(bytes
.byte1
| bytes
.byte3
)) {
282 encoding
.immediate
= bytes
.byte0
;
283 encoding
.pattern
= 1;
284 return ARMThumbImmediate(TypeEncoded
, encoding
);
287 if ((bytes
.byte1
== bytes
.byte3
) && !(bytes
.byte0
| bytes
.byte2
)) {
288 encoding
.immediate
= bytes
.byte0
;
289 encoding
.pattern
= 2;
290 return ARMThumbImmediate(TypeEncoded
, encoding
);
293 return ARMThumbImmediate();
296 static ARMThumbImmediate
makeUInt12(int32_t value
)
298 return (!(value
& 0xfffff000))
299 ? ARMThumbImmediate(TypeUInt16
, (uint16_t)value
)
300 : ARMThumbImmediate();
303 static ARMThumbImmediate
makeUInt12OrEncodedImm(int32_t value
)
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
);
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
)
316 return ARMThumbImmediate(TypeUInt16
, value
);
321 return m_type
!= TypeInvalid
;
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
; }
346 bool isEncodedImm() { return m_type
== TypeEncoded
; }
349 ThumbImmediateType m_type
;
350 ThumbImmediateValue m_value
;
360 SRType_RRX
= SRType_ROR
363 class ARMv7Assembler
;
364 class ShiftTypeAndAmount
{
365 friend class ARMv7Assembler
;
370 m_u
.type
= (ARMShiftType
)0;
374 ShiftTypeAndAmount(ARMShiftType type
, unsigned amount
)
377 m_u
.amount
= amount
& 31;
380 unsigned lo4() { return m_u
.lo4
; }
381 unsigned hi4() { return m_u
.hi4
; }
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
408 class ARMv7Assembler
{
410 typedef ARM::RegisterID RegisterID
;
411 typedef ARM::FPRegisterID FPRegisterID
;
413 // (HS, LO, HI, LS) -> (AE, B, A, BE)
414 // (VS, VC) -> (O, NO)
432 ConditionCS
= ConditionHS
,
433 ConditionCC
= ConditionLO
,
437 friend class ARMv7Assembler
;
438 friend class ARMInstructionFormatter
;
455 friend class ARMv7Assembler
;
456 friend class ARMInstructionFormatter
;
464 bool isUsed() const { return m_used
; }
465 void used() { m_used
= true; }
471 ASSERT(m_offset
== offset
);
481 bool BadReg(RegisterID reg
)
483 return (reg
== ARM::sp
) || (reg
== ARM::pc
);
486 bool isSingleRegister(FPRegisterID reg
)
488 // Check that the high bit isn't set (q16+), and that the low bit isn't (s1, s3, etc).
492 bool isDoubleRegister(FPRegisterID reg
)
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));
498 bool isQuadRegister(FPRegisterID reg
)
500 return !(reg
& ~(31 << 2));
503 uint32_t singleRegisterNum(FPRegisterID reg
)
505 ASSERT(isSingleRegister(reg
));
509 uint32_t doubleRegisterNum(FPRegisterID reg
)
511 ASSERT(isDoubleRegister(reg
));
515 uint32_t quadRegisterNum(FPRegisterID reg
)
517 ASSERT(isQuadRegister(reg
));
521 uint32_t singleRegisterMask(FPRegisterID rd
, int highBitsShift
, int lowBitShift
)
523 uint32_t rdNum
= singleRegisterNum(rd
);
524 uint32_t rdMask
= (rdNum
>> 1) << highBitsShift
;
526 rdMask
|= 1 << lowBitShift
;
530 uint32_t doubleRegisterMask(FPRegisterID rd
, int highBitShift
, int lowBitsShift
)
532 uint32_t rdNum
= doubleRegisterNum(rd
);
533 uint32_t rdMask
= (rdNum
& 0xf) << lowBitsShift
;
535 rdMask
|= 1 << highBitShift
;
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,
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,
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,
595 OP_AND_imm_T1
= 0xF000,
597 OP_ORR_imm_T1
= 0xF040,
598 OP_MOV_imm_T2
= 0xF040,
600 OP_EOR_imm_T1
= 0xF080,
601 OP_ADD_imm_T3
= 0xF100,
602 OP_ADD_S_imm_T3
= 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,
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,
632 FourFours(unsigned f3
, unsigned f2
, unsigned f1
, unsigned f0
)
651 class ARMInstructionFormatter
;
654 bool ifThenElseConditionBit(Condition condition
, bool isIf
)
656 return isIf
? (condition
& 1) : !(condition
& 1);
658 uint8_t ifThenElse(Condition condition
, bool inst2if
, bool inst3if
, bool inst4if
)
660 int mask
= (ifThenElseConditionBit(condition
, inst2if
) << 3)
661 | (ifThenElseConditionBit(condition
, inst3if
) << 2)
662 | (ifThenElseConditionBit(condition
, inst4if
) << 1)
664 ASSERT((condition
!= ConditionAL
) || (mask
& (mask
- 1)));
665 return (condition
<< 4) | mask
;
667 uint8_t ifThenElse(Condition condition
, bool inst2if
, bool inst3if
)
669 int mask
= (ifThenElseConditionBit(condition
, inst2if
) << 3)
670 | (ifThenElseConditionBit(condition
, inst3if
) << 2)
672 ASSERT((condition
!= ConditionAL
) || (mask
& (mask
- 1)));
673 return (condition
<< 4) | mask
;
675 uint8_t ifThenElse(Condition condition
, bool inst2if
)
677 int mask
= (ifThenElseConditionBit(condition
, inst2if
) << 3)
679 ASSERT((condition
!= ConditionAL
) || (mask
& (mask
- 1)));
680 return (condition
<< 4) | mask
;
683 uint8_t ifThenElse(Condition condition
)
686 ASSERT((condition
!= ConditionAL
) || (mask
& (mask
- 1)));
687 return (condition
<< 4) | mask
;
692 void add(RegisterID rd
, RegisterID rn
, ARMThumbImmediate imm
)
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());
701 if (!(rd
& 8) && imm
.isUInt10()) {
702 m_formatter
.oneWordOp5Reg3Imm8(OP_ADD_SP_imm_T1
, rd
, imm
.getUInt10() >> 2);
704 } else if ((rd
== ARM::sp
) && imm
.isUInt9()) {
705 m_formatter
.oneWordOp9Imm7(OP_ADD_SP_imm_T2
, imm
.getUInt9() >> 2);
708 } else if (!((rd
| rn
) & 8)) {
710 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_ADD_imm_T1
, (RegisterID
)imm
.getUInt3(), rn
, rd
);
712 } else if ((rd
== rn
) && imm
.isUInt8()) {
713 m_formatter
.oneWordOp5Reg3Imm8(OP_ADD_imm_T2
, rd
, imm
.getUInt8());
718 if (imm
.isEncodedImm())
719 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T3
, rn
, rd
, imm
);
721 ASSERT(imm
.isUInt12());
722 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T4
, rn
, rd
, imm
);
726 void add(RegisterID rd
, RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
728 ASSERT((rd
!= ARM::sp
) || (rn
== ARM::sp
));
729 ASSERT(rd
!= ARM::pc
);
730 ASSERT(rn
!= ARM::pc
);
732 m_formatter
.twoWordOp12Reg4FourFours(OP_ADD_reg_T3
, rn
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
735 // NOTE: In an IT block, add doesn't modify the flags register.
736 void add(RegisterID rd
, RegisterID rn
, RegisterID rm
)
739 m_formatter
.oneWordOp8RegReg143(OP_ADD_reg_T2
, rm
, rd
);
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
);
745 add(rd
, rn
, rm
, ShiftTypeAndAmount());
748 // Not allowed in an IT (if then) block.
749 void add_S(RegisterID rd
, RegisterID rn
, ARMThumbImmediate imm
)
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());
757 if (!((rd
| rn
) & 8)) {
759 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_ADD_S_imm_T1
, (RegisterID
)imm
.getUInt3(), rn
, rd
);
761 } else if ((rd
== rn
) && imm
.isUInt8()) {
762 m_formatter
.oneWordOp5Reg3Imm8(OP_ADD_S_imm_T2
, rd
, imm
.getUInt8());
767 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_S_imm_T3
, rn
, rd
, imm
);
770 // Not allowed in an IT (if then) block?
771 void add_S(RegisterID rd
, RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
773 ASSERT((rd
!= ARM::sp
) || (rn
== ARM::sp
));
774 ASSERT(rd
!= ARM::pc
);
775 ASSERT(rn
!= ARM::pc
);
777 m_formatter
.twoWordOp12Reg4FourFours(OP_ADD_S_reg_T3
, rn
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
780 // Not allowed in an IT (if then) block.
781 void add_S(RegisterID rd
, RegisterID rn
, RegisterID rm
)
783 if (!((rd
| rn
| rm
) & 8))
784 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_ADD_S_reg_T1
, rm
, rn
, rd
);
786 add_S(rd
, rn
, rm
, ShiftTypeAndAmount());
789 void ARM_and(RegisterID rd
, RegisterID rn
, ARMThumbImmediate imm
)
793 ASSERT(imm
.isEncodedImm());
794 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_AND_imm_T1
, rn
, rd
, imm
);
797 void ARM_and(RegisterID rd
, RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
802 m_formatter
.twoWordOp12Reg4FourFours(OP_AND_reg_T2
, rn
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
805 void ARM_and(RegisterID rd
, RegisterID rn
, RegisterID rm
)
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
);
812 ARM_and(rd
, rn
, rm
, ShiftTypeAndAmount());
815 void asr(RegisterID rd
, RegisterID rm
, int32_t shiftAmount
)
819 ShiftTypeAndAmount
shift(SRType_ASR
, shiftAmount
);
820 m_formatter
.twoWordOp16FourFours(OP_ASR_imm_T1
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
823 void asr(RegisterID rd
, RegisterID rn
, RegisterID rm
)
828 m_formatter
.twoWordOp12Reg4FourFours(OP_ASR_reg_T2
, rn
, FourFours(0xf, rd
, 0, rm
));
831 // Only allowed in IT (if then) block if last instruction.
834 m_formatter
.twoWordOp16Op16(OP_B_T4a
, OP_B_T4b
);
835 return JmpSrc(m_formatter
.size());
838 // Only allowed in IT (if then) block if last instruction.
839 JmpSrc
blx(RegisterID rm
)
841 ASSERT(rm
!= ARM::pc
);
842 m_formatter
.oneWordOp8RegReg143(OP_BLX
, rm
, (RegisterID
)8);
843 return JmpSrc(m_formatter
.size());
846 // Only allowed in IT (if then) block if last instruction.
847 JmpSrc
bx(RegisterID rm
)
849 m_formatter
.oneWordOp8RegReg143(OP_BX
, rm
, (RegisterID
)0);
850 return JmpSrc(m_formatter
.size());
853 void bkpt(uint8_t imm
=0)
855 m_formatter
.oneWordOp8Imm8(OP_BKPT
, imm
);
858 void cmn(RegisterID rn
, ARMThumbImmediate imm
)
860 ASSERT(rn
!= ARM::pc
);
861 ASSERT(imm
.isEncodedImm());
863 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMN_imm
, rn
, (RegisterID
)0xf, imm
);
866 void cmp(RegisterID rn
, ARMThumbImmediate imm
)
868 ASSERT(rn
!= ARM::pc
);
869 ASSERT(imm
.isEncodedImm());
871 if (!(rn
& 8) && imm
.isUInt8())
872 m_formatter
.oneWordOp5Reg3Imm8(OP_CMP_imm_T1
, rn
, imm
.getUInt8());
874 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMP_imm_T2
, rn
, (RegisterID
)0xf, imm
);
877 void cmp(RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
879 ASSERT(rn
!= ARM::pc
);
881 m_formatter
.twoWordOp12Reg4FourFours(OP_CMP_reg_T2
, rn
, FourFours(shift
.hi4(), 0xf, shift
.lo4(), rm
));
884 void cmp(RegisterID rn
, RegisterID rm
)
887 cmp(rn
, rm
, ShiftTypeAndAmount());
889 m_formatter
.oneWordOp10Reg3Reg3(OP_CMP_reg_T1
, rm
, rn
);
892 // xor is not spelled with an 'e'. :-(
893 void eor(RegisterID rd
, RegisterID rn
, ARMThumbImmediate imm
)
897 ASSERT(imm
.isEncodedImm());
898 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_EOR_imm_T1
, rn
, rd
, imm
);
901 // xor is not spelled with an 'e'. :-(
902 void eor(RegisterID rd
, RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
907 m_formatter
.twoWordOp12Reg4FourFours(OP_EOR_reg_T2
, rn
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
910 // xor is not spelled with an 'e'. :-(
911 void eor(RegisterID rd
, RegisterID rn
, RegisterID rm
)
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
);
918 eor(rd
, rn
, rm
, ShiftTypeAndAmount());
921 void it(Condition cond
)
923 m_formatter
.oneWordOp8Imm8(OP_IT
, ifThenElse(cond
));
926 void it(Condition cond
, bool inst2if
)
928 m_formatter
.oneWordOp8Imm8(OP_IT
, ifThenElse(cond
, inst2if
));
931 void it(Condition cond
, bool inst2if
, bool inst3if
)
933 m_formatter
.oneWordOp8Imm8(OP_IT
, ifThenElse(cond
, inst2if
, inst3if
));
936 void it(Condition cond
, bool inst2if
, bool inst3if
, bool inst4if
)
938 m_formatter
.oneWordOp8Imm8(OP_IT
, ifThenElse(cond
, inst2if
, inst3if
, inst4if
));
941 // rt == ARM::pc only allowed if last instruction in IT (if then) block.
942 void ldr(RegisterID rt
, RegisterID rn
, ARMThumbImmediate imm
)
944 ASSERT(rn
!= ARM::pc
); // LDR (literal)
945 ASSERT(imm
.isUInt12());
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);
952 m_formatter
.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T3
, rn
, rt
, imm
.getUInt12());
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.
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.
961 // (-255 <= offset <= 255)
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
)
968 ASSERT(rt
!= ARM::pc
);
969 ASSERT(rn
!= ARM::pc
);
970 ASSERT(index
|| wback
);
971 ASSERT(!wback
| (rt
!= rn
));
978 ASSERT((offset
& ~0xff) == 0);
980 offset
|= (wback
<< 8);
981 offset
|= (add
<< 9);
982 offset
|= (index
<< 10);
985 m_formatter
.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T4
, rn
, rt
, offset
);
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)
991 ASSERT(rn
!= ARM::pc
); // LDR (literal)
995 if (!shift
&& !((rt
| rn
| rm
) & 8))
996 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_LDR_reg_T1
, rm
, rn
, rt
);
998 m_formatter
.twoWordOp12Reg4FourFours(OP_LDR_reg_T2
, rn
, FourFours(rt
, 0, shift
, rm
));
1001 // rt == ARM::pc only allowed if last instruction in IT (if then) block.
1002 void ldrh(RegisterID rt
, RegisterID rn
, ARMThumbImmediate imm
)
1004 ASSERT(rn
!= ARM::pc
); // LDR (literal)
1005 ASSERT(imm
.isUInt12());
1007 if (!((rt
| rn
) & 8) && imm
.isUInt6())
1008 m_formatter
.oneWordOp5Imm5Reg3Reg3(OP_LDRH_imm_T1
, imm
.getUInt6() >> 2, rn
, rt
);
1010 m_formatter
.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T2
, rn
, rt
, imm
.getUInt12());
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.
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.
1019 // (-255 <= offset <= 255)
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
)
1026 ASSERT(rt
!= ARM::pc
);
1027 ASSERT(rn
!= ARM::pc
);
1028 ASSERT(index
|| wback
);
1029 ASSERT(!wback
| (rt
!= rn
));
1036 ASSERT((offset
& ~0xff) == 0);
1038 offset
|= (wback
<< 8);
1039 offset
|= (add
<< 9);
1040 offset
|= (index
<< 10);
1041 offset
|= (1 << 11);
1043 m_formatter
.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T3
, rn
, rt
, offset
);
1046 void ldrh(RegisterID rt
, RegisterID rn
, RegisterID rm
, unsigned shift
=0)
1048 ASSERT(!BadReg(rt
)); // Memory hint
1049 ASSERT(rn
!= ARM::pc
); // LDRH (literal)
1050 ASSERT(!BadReg(rm
));
1053 if (!shift
&& !((rt
| rn
| rm
) & 8))
1054 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_LDRH_reg_T1
, rm
, rn
, rt
);
1056 m_formatter
.twoWordOp12Reg4FourFours(OP_LDRH_reg_T2
, rn
, FourFours(rt
, 0, shift
, rm
));
1059 void lsl(RegisterID rd
, RegisterID rm
, int32_t shiftAmount
)
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
));
1067 void lsl(RegisterID rd
, RegisterID rn
, RegisterID rm
)
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
));
1075 void lsr(RegisterID rd
, RegisterID rm
, int32_t shiftAmount
)
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
));
1083 void lsr(RegisterID rd
, RegisterID rn
, RegisterID rm
)
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
));
1091 void movT3(RegisterID rd
, ARMThumbImmediate imm
)
1093 ASSERT(imm
.isValid());
1094 ASSERT(!imm
.isEncodedImm());
1095 ASSERT(!BadReg(rd
));
1097 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T3
, imm
.m_value
.imm4
, rd
, imm
);
1100 void mov(RegisterID rd
, ARMThumbImmediate imm
)
1102 ASSERT(imm
.isValid());
1103 ASSERT(!BadReg(rd
));
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
);
1113 void mov(RegisterID rd
, RegisterID rm
)
1115 m_formatter
.oneWordOp8RegReg143(OP_MOV_reg_T1
, rm
, rd
);
1118 void movt(RegisterID rd
, ARMThumbImmediate imm
)
1120 ASSERT(imm
.isUInt16());
1121 ASSERT(!BadReg(rd
));
1122 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOVT
, imm
.m_value
.imm4
, rd
, imm
);
1125 void mvn(RegisterID rd
, ARMThumbImmediate imm
)
1127 ASSERT(imm
.isEncodedImm());
1128 ASSERT(!BadReg(rd
));
1130 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_MVN_imm
, 0xf, rd
, imm
);
1133 void mvn(RegisterID rd
, RegisterID rm
, ShiftTypeAndAmount shift
)
1135 ASSERT(!BadReg(rd
));
1136 ASSERT(!BadReg(rm
));
1137 m_formatter
.twoWordOp16FourFours(OP_MVN_reg_T2
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
1140 void mvn(RegisterID rd
, RegisterID rm
)
1142 if (!((rd
| rm
) & 8))
1143 m_formatter
.oneWordOp10Reg3Reg3(OP_MVN_reg_T1
, rm
, rd
);
1145 mvn(rd
, rm
, ShiftTypeAndAmount());
1148 void orr(RegisterID rd
, RegisterID rn
, ARMThumbImmediate imm
)
1150 ASSERT(!BadReg(rd
));
1151 ASSERT(!BadReg(rn
));
1152 ASSERT(imm
.isEncodedImm());
1153 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_ORR_imm_T1
, rn
, rd
, imm
);
1156 void orr(RegisterID rd
, RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
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
));
1164 void orr(RegisterID rd
, RegisterID rn
, RegisterID rm
)
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
);
1171 orr(rd
, rn
, rm
, ShiftTypeAndAmount());
1174 void ror(RegisterID rd
, RegisterID rm
, int32_t shiftAmount
)
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
));
1182 void ror(RegisterID rd
, RegisterID rn
, RegisterID rm
)
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
));
1190 void smull(RegisterID rdLo
, RegisterID rdHi
, RegisterID rn
, RegisterID rm
)
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
));
1200 // rt == ARM::pc only allowed if last instruction in IT (if then) block.
1201 void str(RegisterID rt
, RegisterID rn
, ARMThumbImmediate imm
)
1203 ASSERT(rt
!= ARM::pc
);
1204 ASSERT(rn
!= ARM::pc
);
1205 ASSERT(imm
.isUInt12());
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);
1212 m_formatter
.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T3
, rn
, rt
, imm
.getUInt12());
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.
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.
1221 // (-255 <= offset <= 255)
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
)
1228 ASSERT(rt
!= ARM::pc
);
1229 ASSERT(rn
!= ARM::pc
);
1230 ASSERT(index
|| wback
);
1231 ASSERT(!wback
| (rt
!= rn
));
1238 ASSERT((offset
& ~0xff) == 0);
1240 offset
|= (wback
<< 8);
1241 offset
|= (add
<< 9);
1242 offset
|= (index
<< 10);
1243 offset
|= (1 << 11);
1245 m_formatter
.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T4
, rn
, rt
, offset
);
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)
1251 ASSERT(rn
!= ARM::pc
);
1252 ASSERT(!BadReg(rm
));
1255 if (!shift
&& !((rt
| rn
| rm
) & 8))
1256 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_STR_reg_T1
, rm
, rn
, rt
);
1258 m_formatter
.twoWordOp12Reg4FourFours(OP_STR_reg_T2
, rn
, FourFours(rt
, 0, shift
, rm
));
1261 void sub(RegisterID rd
, RegisterID rn
, ARMThumbImmediate imm
)
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());
1269 if ((rn
== ARM::sp
) && (rd
== ARM::sp
) && imm
.isUInt9()) {
1270 m_formatter
.oneWordOp9Imm7(OP_SUB_SP_imm_T1
, imm
.getUInt9() >> 2);
1272 } else if (!((rd
| rn
) & 8)) {
1273 if (imm
.isUInt3()) {
1274 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_SUB_imm_T1
, (RegisterID
)imm
.getUInt3(), rn
, rd
);
1276 } else if ((rd
== rn
) && imm
.isUInt8()) {
1277 m_formatter
.oneWordOp5Reg3Imm8(OP_SUB_imm_T2
, rd
, imm
.getUInt8());
1282 if (imm
.isEncodedImm())
1283 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T3
, rn
, rd
, imm
);
1285 ASSERT(imm
.isUInt12());
1286 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T4
, rn
, rd
, imm
);
1290 void sub(RegisterID rd
, RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
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
));
1299 // NOTE: In an IT block, add doesn't modify the flags register.
1300 void sub(RegisterID rd
, RegisterID rn
, RegisterID rm
)
1302 if (!((rd
| rn
| rm
) & 8))
1303 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_SUB_reg_T1
, rm
, rn
, rd
);
1305 sub(rd
, rn
, rm
, ShiftTypeAndAmount());
1308 // Not allowed in an IT (if then) block.
1309 void sub_S(RegisterID rd
, RegisterID rn
, ARMThumbImmediate imm
)
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());
1317 if ((rn
== ARM::sp
) && (rd
== ARM::sp
) && imm
.isUInt9()) {
1318 m_formatter
.oneWordOp9Imm7(OP_SUB_SP_imm_T1
, imm
.getUInt9() >> 2);
1320 } else if (!((rd
| rn
) & 8)) {
1321 if (imm
.isUInt3()) {
1322 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_SUB_S_imm_T1
, (RegisterID
)imm
.getUInt3(), rn
, rd
);
1324 } else if ((rd
== rn
) && imm
.isUInt8()) {
1325 m_formatter
.oneWordOp5Reg3Imm8(OP_SUB_S_imm_T2
, rd
, imm
.getUInt8());
1330 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_S_imm_T3
, rn
, rd
, imm
);
1333 // Not allowed in an IT (if then) block?
1334 void sub_S(RegisterID rd
, RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
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
));
1343 // Not allowed in an IT (if then) block.
1344 void sub_S(RegisterID rd
, RegisterID rn
, RegisterID rm
)
1346 if (!((rd
| rn
| rm
) & 8))
1347 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_SUB_S_reg_T1
, rm
, rn
, rd
);
1349 sub_S(rd
, rn
, rm
, ShiftTypeAndAmount());
1352 void tst(RegisterID rn
, ARMThumbImmediate imm
)
1354 ASSERT(!BadReg(rn
));
1355 ASSERT(imm
.isEncodedImm());
1357 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_TST_imm
, rn
, (RegisterID
)0xf, imm
);
1360 void tst(RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
1362 ASSERT(!BadReg(rn
));
1363 ASSERT(!BadReg(rm
));
1364 m_formatter
.twoWordOp12Reg4FourFours(OP_TST_reg_T2
, rn
, FourFours(shift
.hi4(), 0xf, shift
.lo4(), rm
));
1367 void tst(RegisterID rn
, RegisterID rm
)
1370 tst(rn
, rm
, ShiftTypeAndAmount());
1372 m_formatter
.oneWordOp10Reg3Reg3(OP_TST_reg_T1
, rm
, rn
);
1375 void vadd_F64(FPRegisterID rd
, FPRegisterID rn
, FPRegisterID rm
)
1377 m_formatter
.vfpOp(0x0b00ee30 | doubleRegisterMask(rd
, 6, 28) | doubleRegisterMask(rn
, 23, 0) | doubleRegisterMask(rm
, 21, 16));
1380 void vcmp_F64(FPRegisterID rd
, FPRegisterID rm
)
1382 m_formatter
.vfpOp(0x0bc0eeb4 | doubleRegisterMask(rd
, 6, 28) | doubleRegisterMask(rm
, 21, 16));
1385 void vcvt_F64_S32(FPRegisterID fd
, FPRegisterID sm
)
1387 m_formatter
.vfpOp(0x0bc0eeb8 | doubleRegisterMask(fd
, 6, 28) | singleRegisterMask(sm
, 16, 21));
1390 void vcvt_S32_F64(FPRegisterID sd
, FPRegisterID fm
)
1392 m_formatter
.vfpOp(0x0bc0eebd | singleRegisterMask(sd
, 28, 6) | doubleRegisterMask(fm
, 21, 16));
1395 void vldr(FPRegisterID rd
, RegisterID rn
, int32_t imm
)
1397 vmem(rd
, rn
, imm
, true);
1400 void vmov(RegisterID rd
, FPRegisterID sn
)
1402 m_formatter
.vfpOp(0x0a10ee10 | (rd
<< 28) | singleRegisterMask(sn
, 0, 23));
1405 void vmov(FPRegisterID sn
, RegisterID rd
)
1407 m_formatter
.vfpOp(0x0a10ee00 | (rd
<< 28) | singleRegisterMask(sn
, 0, 23));
1410 // move FPSCR flags to APSR.
1411 void vmrs_APSR_nzcv_FPSCR()
1413 m_formatter
.vfpOp(0xfa10eef1);
1416 void vmul_F64(FPRegisterID rd
, FPRegisterID rn
, FPRegisterID rm
)
1418 m_formatter
.vfpOp(0x0b00ee20 | doubleRegisterMask(rd
, 6, 28) | doubleRegisterMask(rn
, 23, 0) | doubleRegisterMask(rm
, 21, 16));
1421 void vstr(FPRegisterID rd
, RegisterID rn
, int32_t imm
)
1423 vmem(rd
, rn
, imm
, false);
1426 void vsub_F64(FPRegisterID rd
, FPRegisterID rn
, FPRegisterID rm
)
1428 m_formatter
.vfpOp(0x0b40ee30 | doubleRegisterMask(rd
, 6, 28) | doubleRegisterMask(rn
, 23, 0) | doubleRegisterMask(rm
, 21, 16));
1434 return JmpDst(m_formatter
.size());
1437 JmpDst
align(int alignment
)
1439 while (!m_formatter
.isAligned(alignment
))
1445 static void* getRelocatedAddress(void* code
, JmpSrc jump
)
1447 ASSERT(jump
.m_offset
!= -1);
1449 return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code
) + jump
.m_offset
);
1452 static void* getRelocatedAddress(void* code
, JmpDst destination
)
1454 ASSERT(destination
.m_offset
!= -1);
1456 return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code
) + destination
.m_offset
);
1459 static int getDifferenceBetweenLabels(JmpDst src
, JmpDst dst
)
1461 return dst
.m_offset
- src
.m_offset
;
1464 static int getDifferenceBetweenLabels(JmpDst src
, JmpSrc dst
)
1466 return dst
.m_offset
- src
.m_offset
;
1469 static int getDifferenceBetweenLabels(JmpSrc src
, JmpDst dst
)
1471 return dst
.m_offset
- src
.m_offset
;
1474 // Assembler admin methods:
1478 return m_formatter
.size();
1481 void* executableCopy(ExecutablePool
* allocator
)
1483 void* copy
= m_formatter
.executableCopy(allocator
);
1488 static unsigned getCallReturnOffset(JmpSrc call
)
1490 ASSERT(call
.m_offset
>= 0);
1491 return call
.m_offset
;
1494 // Linking & patching:
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.
1502 void linkJump(JmpSrc from
, JmpDst to
)
1504 ASSERT(to
.m_offset
!= -1);
1505 ASSERT(from
.m_offset
!= -1);
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
;
1510 linkWithOffset(location
, relative
);
1513 static void linkJump(void* code
, JmpSrc from
, void* to
)
1515 ASSERT(from
.m_offset
!= -1);
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
);
1520 linkWithOffset(location
, relative
);
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
)
1527 ASSERT(!(reinterpret_cast<intptr_t>(code
) & 1));
1528 ASSERT(from
.m_offset
!= -1);
1529 ASSERT(reinterpret_cast<intptr_t>(to
) & 1);
1531 setPointer(reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code
) + from
.m_offset
) - 1, to
);
1534 static void linkPointer(void* code
, JmpDst where
, void* value
)
1536 setPointer(reinterpret_cast<char*>(code
) + where
.m_offset
, value
);
1539 static void relinkJump(void* from
, void* to
)
1541 ASSERT(!(reinterpret_cast<intptr_t>(from
) & 1));
1542 ASSERT(!(reinterpret_cast<intptr_t>(to
) & 1));
1544 intptr_t relative
= reinterpret_cast<intptr_t>(to
) - reinterpret_cast<intptr_t>(from
);
1545 linkWithOffset(reinterpret_cast<uint16_t*>(from
), relative
);
1547 ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(from
) - 2, 2 * sizeof(uint16_t));
1550 static void relinkCall(void* from
, void* to
)
1552 ASSERT(!(reinterpret_cast<intptr_t>(from
) & 1));
1553 ASSERT(reinterpret_cast<intptr_t>(to
) & 1);
1555 setPointer(reinterpret_cast<uint16_t*>(from
) - 1, to
);
1557 ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(from
) - 5, 4 * sizeof(uint16_t));
1560 static void repatchInt32(void* where
, int32_t value
)
1562 ASSERT(!(reinterpret_cast<intptr_t>(where
) & 1));
1564 setInt32(where
, value
);
1566 ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(where
) - 4, 4 * sizeof(uint16_t));
1569 static void repatchPointer(void* where
, void* value
)
1571 ASSERT(!(reinterpret_cast<intptr_t>(where
) & 1));
1573 setPointer(where
, value
);
1575 ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(where
) - 4, 4 * sizeof(uint16_t));
1578 static void repatchLoadPtrToLEA(void* where
)
1580 ASSERT(!(reinterpret_cast<intptr_t>(where
) & 1));
1582 uint16_t* loadOp
= reinterpret_cast<uint16_t*>(where
) + 4;
1583 ASSERT((*loadOp
& 0xfff0) == OP_LDR_reg_T2
);
1585 *loadOp
= OP_ADD_reg_T3
| (*loadOp
& 0xf);
1586 ExecutableAllocator::cacheFlush(loadOp
, sizeof(uint16_t));
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
)
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);
1610 m_formatter
.vfpOp(0x0b00ed00 | offset
| (up
<< 7) | (isLoad
<< 4) | doubleRegisterMask(rd
, 6, 28) | rn
);
1613 static void setInt32(void* code
, uint32_t value
)
1615 uint16_t* location
= reinterpret_cast<uint16_t*>(code
);
1617 uint16_t lo16
= value
;
1618 uint16_t hi16
= value
>> 16;
1620 spliceHi5(location
- 4, lo16
);
1621 spliceLo11(location
- 3, lo16
);
1622 spliceHi5(location
- 2, hi16
);
1623 spliceLo11(location
- 1, hi16
);
1625 ExecutableAllocator::cacheFlush(location
- 4, 4 * sizeof(uint16_t));
1628 static void setPointer(void* code
, void* value
)
1630 setInt32(code
, reinterpret_cast<uint32_t>(value
));
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
)
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");
1644 // ARM encoding for the top two bits below the sign bit is 'peculiar'.
1646 relative
^= 0xC00000;
1648 // All branch offsets should be an even distance.
1649 ASSERT(!(relative
& 1));
1651 int word1
= ((relative
& 0x1000000) >> 14) | ((relative
& 0x3ff000) >> 12);
1652 int word2
= ((relative
& 0x800000) >> 10) | ((relative
& 0x400000) >> 11) | ((relative
& 0xffe) >> 1);
1654 instruction
[-2] = OP_B_T4a
| word1
;
1655 instruction
[-1] = OP_B_T4b
| word2
;
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
)
1661 uint16_t pattern
= (what
>> 12) | ((what
& 0x0800) >> 1);
1662 *where
= (*where
& 0xFBF0) | pattern
;
1664 static void spliceLo11(uint16_t* where
, uint16_t what
)
1666 uint16_t pattern
= ((what
& 0x0700) << 4) | (what
& 0x00FF);
1667 *where
= (*where
& 0x8F00) | pattern
;
1670 class ARMInstructionFormatter
{
1672 void oneWordOp5Reg3Imm8(OpcodeID op
, RegisterID rd
, uint8_t imm
)
1674 m_buffer
.putShort(op
| (rd
<< 8) | imm
);
1677 void oneWordOp5Imm5Reg3Reg3(OpcodeID op
, uint8_t imm
, RegisterID reg1
, RegisterID reg2
)
1679 m_buffer
.putShort(op
| (imm
<< 6) | (reg1
<< 3) | reg2
);
1682 void oneWordOp7Reg3Reg3Reg3(OpcodeID op
, RegisterID reg1
, RegisterID reg2
, RegisterID reg3
)
1684 m_buffer
.putShort(op
| (reg1
<< 6) | (reg2
<< 3) | reg3
);
1687 void oneWordOp8Imm8(OpcodeID op
, uint8_t imm
)
1689 m_buffer
.putShort(op
| imm
);
1692 void oneWordOp8RegReg143(OpcodeID op
, RegisterID reg1
, RegisterID reg2
)
1694 m_buffer
.putShort(op
| ((reg2
& 8) << 4) | (reg1
<< 3) | (reg2
& 7));
1696 void oneWordOp9Imm7(OpcodeID op
, uint8_t imm
)
1698 m_buffer
.putShort(op
| imm
);
1701 void oneWordOp10Reg3Reg3(OpcodeID op
, RegisterID reg1
, RegisterID reg2
)
1703 m_buffer
.putShort(op
| (reg1
<< 3) | reg2
);
1706 void twoWordOp12Reg4FourFours(OpcodeID1 op
, RegisterID reg
, FourFours ff
)
1708 m_buffer
.putShort(op
| reg
);
1709 m_buffer
.putShort(ff
.m_u
.value
);
1712 void twoWordOp16FourFours(OpcodeID1 op
, FourFours ff
)
1714 m_buffer
.putShort(op
);
1715 m_buffer
.putShort(ff
.m_u
.value
);
1718 void twoWordOp16Op16(OpcodeID1 op1
, OpcodeID2 op2
)
1720 m_buffer
.putShort(op1
);
1721 m_buffer
.putShort(op2
);
1724 void twoWordOp5i6Imm4Reg4EncodedImm(OpcodeID1 op
, int imm4
, RegisterID rd
, ARMThumbImmediate imm
)
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
);
1730 void twoWordOp12Reg4Reg4Imm12(OpcodeID1 op
, RegisterID reg1
, RegisterID reg2
, uint16_t imm
)
1732 m_buffer
.putShort(op
| reg1
);
1733 m_buffer
.putShort((reg2
<< 12) | imm
);
1736 void vfpOp(int32_t op
)
1738 m_buffer
.putInt(op
);
1742 // Administrative methods:
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
); }
1750 AssemblerBuffer m_buffer
;
1756 #endif // ENABLE(ASSEMBLER) && PLATFORM_ARM_ARCH(7)
1758 #endif // ARMAssembler_h