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) && CPU(ARM_THUMB2)
33 #include "AssemblerBuffer.h"
34 #include <wtf/Assertions.h>
35 #include <wtf/Vector.h>
40 namespace ARMRegisters
{
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 void 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 // 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
);
244 m_value
.asInt
= value
;
248 static ARMThumbImmediate
makeEncodedImm(uint32_t value
)
250 ThumbImmediateValue encoding
;
253 // okay, these are easy.
255 encoding
.immediate
= value
;
256 encoding
.pattern
= 0;
257 return ARMThumbImmediate(TypeEncoded
, encoding
);
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);
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
);
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
);
286 if ((bytes
.byte0
== bytes
.byte2
) && !(bytes
.byte1
| bytes
.byte3
)) {
287 encoding
.immediate
= bytes
.byte0
;
288 encoding
.pattern
= 1;
289 return ARMThumbImmediate(TypeEncoded
, encoding
);
292 if ((bytes
.byte1
== bytes
.byte3
) && !(bytes
.byte0
| bytes
.byte2
)) {
293 encoding
.immediate
= bytes
.byte0
;
294 encoding
.pattern
= 2;
295 return ARMThumbImmediate(TypeEncoded
, encoding
);
298 return ARMThumbImmediate();
301 static ARMThumbImmediate
makeUInt12(int32_t value
)
303 return (!(value
& 0xfffff000))
304 ? ARMThumbImmediate(TypeUInt16
, (uint16_t)value
)
305 : ARMThumbImmediate();
308 static ARMThumbImmediate
makeUInt12OrEncodedImm(int32_t value
)
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
);
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
)
321 return ARMThumbImmediate(TypeUInt16
, value
);
326 return m_type
!= TypeInvalid
;
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
; }
351 bool isEncodedImm() { return m_type
== TypeEncoded
; }
354 ThumbImmediateType m_type
;
355 ThumbImmediateValue m_value
;
365 SRType_RRX
= SRType_ROR
368 class ARMv7Assembler
;
369 class ShiftTypeAndAmount
{
370 friend class ARMv7Assembler
;
375 m_u
.type
= (ARMShiftType
)0;
379 ShiftTypeAndAmount(ARMShiftType type
, unsigned amount
)
382 m_u
.amount
= amount
& 31;
385 unsigned lo4() { return m_u
.lo4
; }
386 unsigned hi4() { return m_u
.hi4
; }
403 Some features of the Thumb instruction set are deprecated in ARMv7. Deprecated features affecting
404 instructions 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
413 class ARMv7Assembler
{
417 ASSERT(m_jumpsToLink
.isEmpty());
420 typedef ARMRegisters::RegisterID RegisterID
;
421 typedef ARMRegisters::FPRegisterID FPRegisterID
;
423 // (HS, LO, HI, LS) -> (AE, B, A, BE)
424 // (VS, VC) -> (O, NO)
442 ConditionCS
= ConditionHS
,
443 ConditionCC
= ConditionLO
,
447 friend class ARMv7Assembler
;
448 friend class ARMInstructionFormatter
;
465 friend class ARMv7Assembler
;
466 friend class ARMInstructionFormatter
;
474 bool isUsed() const { return m_used
; }
475 void used() { m_used
= true; }
481 ASSERT(m_offset
== offset
);
491 LinkRecord(intptr_t from
, intptr_t to
)
502 bool BadReg(RegisterID reg
)
504 return (reg
== ARMRegisters::sp
) || (reg
== ARMRegisters::pc
);
507 bool isSingleRegister(FPRegisterID reg
)
509 // Check that the high bit isn't set (q16+), and that the low bit isn't (s1, s3, etc).
513 bool isDoubleRegister(FPRegisterID reg
)
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));
519 bool isQuadRegister(FPRegisterID reg
)
521 return !(reg
& ~(31 << 2));
524 uint32_t singleRegisterNum(FPRegisterID reg
)
526 ASSERT(isSingleRegister(reg
));
530 uint32_t doubleRegisterNum(FPRegisterID reg
)
532 ASSERT(isDoubleRegister(reg
));
536 uint32_t quadRegisterNum(FPRegisterID reg
)
538 ASSERT(isQuadRegister(reg
));
542 uint32_t singleRegisterMask(FPRegisterID rd
, int highBitsShift
, int lowBitShift
)
544 uint32_t rdNum
= singleRegisterNum(rd
);
545 uint32_t rdMask
= (rdNum
>> 1) << highBitsShift
;
547 rdMask
|= 1 << lowBitShift
;
551 uint32_t doubleRegisterMask(FPRegisterID rd
, int highBitShift
, int lowBitsShift
)
553 uint32_t rdNum
= doubleRegisterNum(rd
);
554 uint32_t rdMask
= (rdNum
& 0xf) << lowBitsShift
;
556 rdMask
|= 1 << highBitShift
;
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,
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,
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,
617 OP_AND_imm_T1
= 0xF000,
619 OP_ORR_imm_T1
= 0xF040,
620 OP_MOV_imm_T2
= 0xF040,
622 OP_EOR_imm_T1
= 0xF080,
623 OP_ADD_imm_T3
= 0xF100,
624 OP_ADD_S_imm_T3
= 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,
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,
656 FourFours(unsigned f3
, unsigned f2
, unsigned f1
, unsigned f0
)
675 class ARMInstructionFormatter
;
678 bool ifThenElseConditionBit(Condition condition
, bool isIf
)
680 return isIf
? (condition
& 1) : !(condition
& 1);
682 uint8_t ifThenElse(Condition condition
, bool inst2if
, bool inst3if
, bool inst4if
)
684 int mask
= (ifThenElseConditionBit(condition
, inst2if
) << 3)
685 | (ifThenElseConditionBit(condition
, inst3if
) << 2)
686 | (ifThenElseConditionBit(condition
, inst4if
) << 1)
688 ASSERT((condition
!= ConditionAL
) || (mask
& (mask
- 1)));
689 return (condition
<< 4) | mask
;
691 uint8_t ifThenElse(Condition condition
, bool inst2if
, bool inst3if
)
693 int mask
= (ifThenElseConditionBit(condition
, inst2if
) << 3)
694 | (ifThenElseConditionBit(condition
, inst3if
) << 2)
696 ASSERT((condition
!= ConditionAL
) || (mask
& (mask
- 1)));
697 return (condition
<< 4) | mask
;
699 uint8_t ifThenElse(Condition condition
, bool inst2if
)
701 int mask
= (ifThenElseConditionBit(condition
, inst2if
) << 3)
703 ASSERT((condition
!= ConditionAL
) || (mask
& (mask
- 1)));
704 return (condition
<< 4) | mask
;
707 uint8_t ifThenElse(Condition condition
)
710 ASSERT((condition
!= ConditionAL
) || (mask
& (mask
- 1)));
711 return (condition
<< 4) | mask
;
716 void add(RegisterID rd
, RegisterID rn
, ARMThumbImmediate imm
)
718 // Rd can only be SP if Rn is also SP.
719 ASSERT((rd
!= ARMRegisters::sp
) || (rn
== ARMRegisters::sp
));
720 ASSERT(rd
!= ARMRegisters::pc
);
721 ASSERT(rn
!= ARMRegisters::pc
);
722 ASSERT(imm
.isValid());
724 if (rn
== ARMRegisters::sp
) {
725 if (!(rd
& 8) && imm
.isUInt10()) {
726 m_formatter
.oneWordOp5Reg3Imm8(OP_ADD_SP_imm_T1
, rd
, imm
.getUInt10() >> 2);
728 } else if ((rd
== ARMRegisters::sp
) && imm
.isUInt9()) {
729 m_formatter
.oneWordOp9Imm7(OP_ADD_SP_imm_T2
, imm
.getUInt9() >> 2);
732 } else if (!((rd
| rn
) & 8)) {
734 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_ADD_imm_T1
, (RegisterID
)imm
.getUInt3(), rn
, rd
);
736 } else if ((rd
== rn
) && imm
.isUInt8()) {
737 m_formatter
.oneWordOp5Reg3Imm8(OP_ADD_imm_T2
, rd
, imm
.getUInt8());
742 if (imm
.isEncodedImm())
743 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T3
, rn
, rd
, imm
);
745 ASSERT(imm
.isUInt12());
746 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T4
, rn
, rd
, imm
);
750 void add(RegisterID rd
, RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
752 ASSERT((rd
!= ARMRegisters::sp
) || (rn
== ARMRegisters::sp
));
753 ASSERT(rd
!= ARMRegisters::pc
);
754 ASSERT(rn
!= ARMRegisters::pc
);
756 m_formatter
.twoWordOp12Reg4FourFours(OP_ADD_reg_T3
, rn
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
759 // NOTE: In an IT block, add doesn't modify the flags register.
760 void add(RegisterID rd
, RegisterID rn
, RegisterID rm
)
763 m_formatter
.oneWordOp8RegReg143(OP_ADD_reg_T2
, rm
, rd
);
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
);
769 add(rd
, rn
, rm
, ShiftTypeAndAmount());
772 // Not allowed in an IT (if then) block.
773 void add_S(RegisterID rd
, RegisterID rn
, ARMThumbImmediate imm
)
775 // Rd can only be SP if Rn is also SP.
776 ASSERT((rd
!= ARMRegisters::sp
) || (rn
== ARMRegisters::sp
));
777 ASSERT(rd
!= ARMRegisters::pc
);
778 ASSERT(rn
!= ARMRegisters::pc
);
779 ASSERT(imm
.isEncodedImm());
781 if (!((rd
| rn
) & 8)) {
783 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_ADD_S_imm_T1
, (RegisterID
)imm
.getUInt3(), rn
, rd
);
785 } else if ((rd
== rn
) && imm
.isUInt8()) {
786 m_formatter
.oneWordOp5Reg3Imm8(OP_ADD_S_imm_T2
, rd
, imm
.getUInt8());
791 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_S_imm_T3
, rn
, rd
, imm
);
794 // Not allowed in an IT (if then) block?
795 void add_S(RegisterID rd
, RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
797 ASSERT((rd
!= ARMRegisters::sp
) || (rn
== ARMRegisters::sp
));
798 ASSERT(rd
!= ARMRegisters::pc
);
799 ASSERT(rn
!= ARMRegisters::pc
);
801 m_formatter
.twoWordOp12Reg4FourFours(OP_ADD_S_reg_T3
, rn
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
804 // Not allowed in an IT (if then) block.
805 void add_S(RegisterID rd
, RegisterID rn
, RegisterID rm
)
807 if (!((rd
| rn
| rm
) & 8))
808 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_ADD_S_reg_T1
, rm
, rn
, rd
);
810 add_S(rd
, rn
, rm
, ShiftTypeAndAmount());
813 void ARM_and(RegisterID rd
, RegisterID rn
, ARMThumbImmediate imm
)
817 ASSERT(imm
.isEncodedImm());
818 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_AND_imm_T1
, rn
, rd
, imm
);
821 void ARM_and(RegisterID rd
, RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
826 m_formatter
.twoWordOp12Reg4FourFours(OP_AND_reg_T2
, rn
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
829 void ARM_and(RegisterID rd
, RegisterID rn
, RegisterID rm
)
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
);
836 ARM_and(rd
, rn
, rm
, ShiftTypeAndAmount());
839 void asr(RegisterID rd
, RegisterID rm
, int32_t shiftAmount
)
843 ShiftTypeAndAmount
shift(SRType_ASR
, shiftAmount
);
844 m_formatter
.twoWordOp16FourFours(OP_ASR_imm_T1
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
847 void asr(RegisterID rd
, RegisterID rn
, RegisterID rm
)
852 m_formatter
.twoWordOp12Reg4FourFours(OP_ASR_reg_T2
, rn
, FourFours(0xf, rd
, 0, rm
));
855 // Only allowed in IT (if then) block if last instruction.
858 m_formatter
.twoWordOp16Op16(OP_B_T4a
, OP_B_T4b
);
859 return JmpSrc(m_formatter
.size());
862 // Only allowed in IT (if then) block if last instruction.
863 JmpSrc
blx(RegisterID rm
)
865 ASSERT(rm
!= ARMRegisters::pc
);
866 m_formatter
.oneWordOp8RegReg143(OP_BLX
, rm
, (RegisterID
)8);
867 return JmpSrc(m_formatter
.size());
870 // Only allowed in IT (if then) block if last instruction.
871 JmpSrc
bx(RegisterID rm
)
873 m_formatter
.oneWordOp8RegReg143(OP_BX
, rm
, (RegisterID
)0);
874 return JmpSrc(m_formatter
.size());
877 void bkpt(uint8_t imm
=0)
879 m_formatter
.oneWordOp8Imm8(OP_BKPT
, imm
);
882 void cmn(RegisterID rn
, ARMThumbImmediate imm
)
884 ASSERT(rn
!= ARMRegisters::pc
);
885 ASSERT(imm
.isEncodedImm());
887 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMN_imm
, rn
, (RegisterID
)0xf, imm
);
890 void cmp(RegisterID rn
, ARMThumbImmediate imm
)
892 ASSERT(rn
!= ARMRegisters::pc
);
893 ASSERT(imm
.isEncodedImm());
895 if (!(rn
& 8) && imm
.isUInt8())
896 m_formatter
.oneWordOp5Reg3Imm8(OP_CMP_imm_T1
, rn
, imm
.getUInt8());
898 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMP_imm_T2
, rn
, (RegisterID
)0xf, imm
);
901 void cmp(RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
903 ASSERT(rn
!= ARMRegisters::pc
);
905 m_formatter
.twoWordOp12Reg4FourFours(OP_CMP_reg_T2
, rn
, FourFours(shift
.hi4(), 0xf, shift
.lo4(), rm
));
908 void cmp(RegisterID rn
, RegisterID rm
)
911 cmp(rn
, rm
, ShiftTypeAndAmount());
913 m_formatter
.oneWordOp10Reg3Reg3(OP_CMP_reg_T1
, rm
, rn
);
916 // xor is not spelled with an 'e'. :-(
917 void eor(RegisterID rd
, RegisterID rn
, ARMThumbImmediate imm
)
921 ASSERT(imm
.isEncodedImm());
922 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_EOR_imm_T1
, rn
, rd
, imm
);
925 // xor is not spelled with an 'e'. :-(
926 void eor(RegisterID rd
, RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
931 m_formatter
.twoWordOp12Reg4FourFours(OP_EOR_reg_T2
, rn
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
934 // xor is not spelled with an 'e'. :-(
935 void eor(RegisterID rd
, RegisterID rn
, RegisterID rm
)
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
);
942 eor(rd
, rn
, rm
, ShiftTypeAndAmount());
945 void it(Condition cond
)
947 m_formatter
.oneWordOp8Imm8(OP_IT
, ifThenElse(cond
));
950 void it(Condition cond
, bool inst2if
)
952 m_formatter
.oneWordOp8Imm8(OP_IT
, ifThenElse(cond
, inst2if
));
955 void it(Condition cond
, bool inst2if
, bool inst3if
)
957 m_formatter
.oneWordOp8Imm8(OP_IT
, ifThenElse(cond
, inst2if
, inst3if
));
960 void it(Condition cond
, bool inst2if
, bool inst3if
, bool inst4if
)
962 m_formatter
.oneWordOp8Imm8(OP_IT
, ifThenElse(cond
, inst2if
, inst3if
, inst4if
));
965 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
966 void ldr(RegisterID rt
, RegisterID rn
, ARMThumbImmediate imm
)
968 ASSERT(rn
!= ARMRegisters::pc
); // LDR (literal)
969 ASSERT(imm
.isUInt12());
971 if (!((rt
| rn
) & 8) && imm
.isUInt7())
972 m_formatter
.oneWordOp5Imm5Reg3Reg3(OP_LDR_imm_T1
, imm
.getUInt7() >> 2, rn
, rt
);
973 else if ((rn
== ARMRegisters::sp
) && !(rt
& 8) && imm
.isUInt10())
974 m_formatter
.oneWordOp5Reg3Imm8(OP_LDR_imm_T2
, rt
, imm
.getUInt10() >> 2);
976 m_formatter
.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T3
, rn
, rt
, imm
.getUInt12());
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.
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.
985 // (-255 <= offset <= 255)
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
)
992 ASSERT(rt
!= ARMRegisters::pc
);
993 ASSERT(rn
!= ARMRegisters::pc
);
994 ASSERT(index
|| wback
);
995 ASSERT(!wback
| (rt
!= rn
));
1002 ASSERT((offset
& ~0xff) == 0);
1004 offset
|= (wback
<< 8);
1005 offset
|= (add
<< 9);
1006 offset
|= (index
<< 10);
1007 offset
|= (1 << 11);
1009 m_formatter
.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T4
, rn
, rt
, offset
);
1012 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1013 void ldr(RegisterID rt
, RegisterID rn
, RegisterID rm
, unsigned shift
=0)
1015 ASSERT(rn
!= ARMRegisters::pc
); // LDR (literal)
1016 ASSERT(!BadReg(rm
));
1019 if (!shift
&& !((rt
| rn
| rm
) & 8))
1020 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_LDR_reg_T1
, rm
, rn
, rt
);
1022 m_formatter
.twoWordOp12Reg4FourFours(OP_LDR_reg_T2
, rn
, FourFours(rt
, 0, shift
, rm
));
1025 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1026 void ldrh(RegisterID rt
, RegisterID rn
, ARMThumbImmediate imm
)
1028 ASSERT(rn
!= ARMRegisters::pc
); // LDR (literal)
1029 ASSERT(imm
.isUInt12());
1031 if (!((rt
| rn
) & 8) && imm
.isUInt6())
1032 m_formatter
.oneWordOp5Imm5Reg3Reg3(OP_LDRH_imm_T1
, imm
.getUInt6() >> 2, rn
, rt
);
1034 m_formatter
.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T2
, rn
, rt
, imm
.getUInt12());
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.
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.
1043 // (-255 <= offset <= 255)
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
)
1050 ASSERT(rt
!= ARMRegisters::pc
);
1051 ASSERT(rn
!= ARMRegisters::pc
);
1052 ASSERT(index
|| wback
);
1053 ASSERT(!wback
| (rt
!= rn
));
1060 ASSERT((offset
& ~0xff) == 0);
1062 offset
|= (wback
<< 8);
1063 offset
|= (add
<< 9);
1064 offset
|= (index
<< 10);
1065 offset
|= (1 << 11);
1067 m_formatter
.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T3
, rn
, rt
, offset
);
1070 void ldrh(RegisterID rt
, RegisterID rn
, RegisterID rm
, unsigned shift
=0)
1072 ASSERT(!BadReg(rt
)); // Memory hint
1073 ASSERT(rn
!= ARMRegisters::pc
); // LDRH (literal)
1074 ASSERT(!BadReg(rm
));
1077 if (!shift
&& !((rt
| rn
| rm
) & 8))
1078 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_LDRH_reg_T1
, rm
, rn
, rt
);
1080 m_formatter
.twoWordOp12Reg4FourFours(OP_LDRH_reg_T2
, rn
, FourFours(rt
, 0, shift
, rm
));
1083 void lsl(RegisterID rd
, RegisterID rm
, int32_t shiftAmount
)
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
));
1091 void lsl(RegisterID rd
, RegisterID rn
, RegisterID rm
)
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
));
1099 void lsr(RegisterID rd
, RegisterID rm
, int32_t shiftAmount
)
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
));
1107 void lsr(RegisterID rd
, RegisterID rn
, RegisterID rm
)
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
));
1115 void movT3(RegisterID rd
, ARMThumbImmediate imm
)
1117 ASSERT(imm
.isValid());
1118 ASSERT(!imm
.isEncodedImm());
1119 ASSERT(!BadReg(rd
));
1121 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T3
, imm
.m_value
.imm4
, rd
, imm
);
1124 void mov(RegisterID rd
, ARMThumbImmediate imm
)
1126 ASSERT(imm
.isValid());
1127 ASSERT(!BadReg(rd
));
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
);
1137 void mov(RegisterID rd
, RegisterID rm
)
1139 m_formatter
.oneWordOp8RegReg143(OP_MOV_reg_T1
, rm
, rd
);
1142 void movt(RegisterID rd
, ARMThumbImmediate imm
)
1144 ASSERT(imm
.isUInt16());
1145 ASSERT(!BadReg(rd
));
1146 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOVT
, imm
.m_value
.imm4
, rd
, imm
);
1149 void mvn(RegisterID rd
, ARMThumbImmediate imm
)
1151 ASSERT(imm
.isEncodedImm());
1152 ASSERT(!BadReg(rd
));
1154 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_MVN_imm
, 0xf, rd
, imm
);
1157 void mvn(RegisterID rd
, RegisterID rm
, ShiftTypeAndAmount shift
)
1159 ASSERT(!BadReg(rd
));
1160 ASSERT(!BadReg(rm
));
1161 m_formatter
.twoWordOp16FourFours(OP_MVN_reg_T2
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
1164 void mvn(RegisterID rd
, RegisterID rm
)
1166 if (!((rd
| rm
) & 8))
1167 m_formatter
.oneWordOp10Reg3Reg3(OP_MVN_reg_T1
, rm
, rd
);
1169 mvn(rd
, rm
, ShiftTypeAndAmount());
1172 void orr(RegisterID rd
, RegisterID rn
, ARMThumbImmediate imm
)
1174 ASSERT(!BadReg(rd
));
1175 ASSERT(!BadReg(rn
));
1176 ASSERT(imm
.isEncodedImm());
1177 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_ORR_imm_T1
, rn
, rd
, imm
);
1180 void orr(RegisterID rd
, RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
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
));
1188 void orr(RegisterID rd
, RegisterID rn
, RegisterID rm
)
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
);
1195 orr(rd
, rn
, rm
, ShiftTypeAndAmount());
1198 void ror(RegisterID rd
, RegisterID rm
, int32_t shiftAmount
)
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
));
1206 void ror(RegisterID rd
, RegisterID rn
, RegisterID rm
)
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
));
1214 void smull(RegisterID rdLo
, RegisterID rdHi
, RegisterID rn
, RegisterID rm
)
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
));
1224 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1225 void str(RegisterID rt
, RegisterID rn
, ARMThumbImmediate imm
)
1227 ASSERT(rt
!= ARMRegisters::pc
);
1228 ASSERT(rn
!= ARMRegisters::pc
);
1229 ASSERT(imm
.isUInt12());
1231 if (!((rt
| rn
) & 8) && imm
.isUInt7())
1232 m_formatter
.oneWordOp5Imm5Reg3Reg3(OP_STR_imm_T1
, imm
.getUInt7() >> 2, rn
, rt
);
1233 else if ((rn
== ARMRegisters::sp
) && !(rt
& 8) && imm
.isUInt10())
1234 m_formatter
.oneWordOp5Reg3Imm8(OP_STR_imm_T2
, rt
, imm
.getUInt10() >> 2);
1236 m_formatter
.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T3
, rn
, rt
, imm
.getUInt12());
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.
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.
1245 // (-255 <= offset <= 255)
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
)
1252 ASSERT(rt
!= ARMRegisters::pc
);
1253 ASSERT(rn
!= ARMRegisters::pc
);
1254 ASSERT(index
|| wback
);
1255 ASSERT(!wback
| (rt
!= rn
));
1262 ASSERT((offset
& ~0xff) == 0);
1264 offset
|= (wback
<< 8);
1265 offset
|= (add
<< 9);
1266 offset
|= (index
<< 10);
1267 offset
|= (1 << 11);
1269 m_formatter
.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T4
, rn
, rt
, offset
);
1272 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1273 void str(RegisterID rt
, RegisterID rn
, RegisterID rm
, unsigned shift
=0)
1275 ASSERT(rn
!= ARMRegisters::pc
);
1276 ASSERT(!BadReg(rm
));
1279 if (!shift
&& !((rt
| rn
| rm
) & 8))
1280 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_STR_reg_T1
, rm
, rn
, rt
);
1282 m_formatter
.twoWordOp12Reg4FourFours(OP_STR_reg_T2
, rn
, FourFours(rt
, 0, shift
, rm
));
1285 void sub(RegisterID rd
, RegisterID rn
, ARMThumbImmediate imm
)
1287 // Rd can only be SP if Rn is also SP.
1288 ASSERT((rd
!= ARMRegisters::sp
) || (rn
== ARMRegisters::sp
));
1289 ASSERT(rd
!= ARMRegisters::pc
);
1290 ASSERT(rn
!= ARMRegisters::pc
);
1291 ASSERT(imm
.isValid());
1293 if ((rn
== ARMRegisters::sp
) && (rd
== ARMRegisters::sp
) && imm
.isUInt9()) {
1294 m_formatter
.oneWordOp9Imm7(OP_SUB_SP_imm_T1
, imm
.getUInt9() >> 2);
1296 } else if (!((rd
| rn
) & 8)) {
1297 if (imm
.isUInt3()) {
1298 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_SUB_imm_T1
, (RegisterID
)imm
.getUInt3(), rn
, rd
);
1300 } else if ((rd
== rn
) && imm
.isUInt8()) {
1301 m_formatter
.oneWordOp5Reg3Imm8(OP_SUB_imm_T2
, rd
, imm
.getUInt8());
1306 if (imm
.isEncodedImm())
1307 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T3
, rn
, rd
, imm
);
1309 ASSERT(imm
.isUInt12());
1310 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T4
, rn
, rd
, imm
);
1314 void sub(RegisterID rd
, RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
1316 ASSERT((rd
!= ARMRegisters::sp
) || (rn
== ARMRegisters::sp
));
1317 ASSERT(rd
!= ARMRegisters::pc
);
1318 ASSERT(rn
!= ARMRegisters::pc
);
1319 ASSERT(!BadReg(rm
));
1320 m_formatter
.twoWordOp12Reg4FourFours(OP_SUB_reg_T2
, rn
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
1323 // NOTE: In an IT block, add doesn't modify the flags register.
1324 void sub(RegisterID rd
, RegisterID rn
, RegisterID rm
)
1326 if (!((rd
| rn
| rm
) & 8))
1327 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_SUB_reg_T1
, rm
, rn
, rd
);
1329 sub(rd
, rn
, rm
, ShiftTypeAndAmount());
1332 // Not allowed in an IT (if then) block.
1333 void sub_S(RegisterID rd
, RegisterID rn
, ARMThumbImmediate imm
)
1335 // Rd can only be SP if Rn is also SP.
1336 ASSERT((rd
!= ARMRegisters::sp
) || (rn
== ARMRegisters::sp
));
1337 ASSERT(rd
!= ARMRegisters::pc
);
1338 ASSERT(rn
!= ARMRegisters::pc
);
1339 ASSERT(imm
.isValid());
1341 if ((rn
== ARMRegisters::sp
) && (rd
== ARMRegisters::sp
) && imm
.isUInt9()) {
1342 m_formatter
.oneWordOp9Imm7(OP_SUB_SP_imm_T1
, imm
.getUInt9() >> 2);
1344 } else if (!((rd
| rn
) & 8)) {
1345 if (imm
.isUInt3()) {
1346 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_SUB_S_imm_T1
, (RegisterID
)imm
.getUInt3(), rn
, rd
);
1348 } else if ((rd
== rn
) && imm
.isUInt8()) {
1349 m_formatter
.oneWordOp5Reg3Imm8(OP_SUB_S_imm_T2
, rd
, imm
.getUInt8());
1354 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_S_imm_T3
, rn
, rd
, imm
);
1357 // Not allowed in an IT (if then) block?
1358 void sub_S(RegisterID rd
, RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
1360 ASSERT((rd
!= ARMRegisters::sp
) || (rn
== ARMRegisters::sp
));
1361 ASSERT(rd
!= ARMRegisters::pc
);
1362 ASSERT(rn
!= ARMRegisters::pc
);
1363 ASSERT(!BadReg(rm
));
1364 m_formatter
.twoWordOp12Reg4FourFours(OP_SUB_S_reg_T2
, rn
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
1367 // Not allowed in an IT (if then) block.
1368 void sub_S(RegisterID rd
, RegisterID rn
, RegisterID rm
)
1370 if (!((rd
| rn
| rm
) & 8))
1371 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_SUB_S_reg_T1
, rm
, rn
, rd
);
1373 sub_S(rd
, rn
, rm
, ShiftTypeAndAmount());
1376 void tst(RegisterID rn
, ARMThumbImmediate imm
)
1378 ASSERT(!BadReg(rn
));
1379 ASSERT(imm
.isEncodedImm());
1381 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_TST_imm
, rn
, (RegisterID
)0xf, imm
);
1384 void tst(RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
1386 ASSERT(!BadReg(rn
));
1387 ASSERT(!BadReg(rm
));
1388 m_formatter
.twoWordOp12Reg4FourFours(OP_TST_reg_T2
, rn
, FourFours(shift
.hi4(), 0xf, shift
.lo4(), rm
));
1391 void tst(RegisterID rn
, RegisterID rm
)
1394 tst(rn
, rm
, ShiftTypeAndAmount());
1396 m_formatter
.oneWordOp10Reg3Reg3(OP_TST_reg_T1
, rm
, rn
);
1399 void vadd_F64(FPRegisterID rd
, FPRegisterID rn
, FPRegisterID rm
)
1401 m_formatter
.vfpOp(0x0b00ee30 | doubleRegisterMask(rd
, 6, 28) | doubleRegisterMask(rn
, 23, 0) | doubleRegisterMask(rm
, 21, 16));
1404 void vcmp_F64(FPRegisterID rd
, FPRegisterID rm
)
1406 m_formatter
.vfpOp(0x0bc0eeb4 | doubleRegisterMask(rd
, 6, 28) | doubleRegisterMask(rm
, 21, 16));
1409 void vcvt_F64_S32(FPRegisterID fd
, FPRegisterID sm
)
1411 m_formatter
.vfpOp(0x0bc0eeb8 | doubleRegisterMask(fd
, 6, 28) | singleRegisterMask(sm
, 16, 21));
1414 void vcvt_S32_F64(FPRegisterID sd
, FPRegisterID fm
)
1416 m_formatter
.vfpOp(0x0bc0eebd | singleRegisterMask(sd
, 28, 6) | doubleRegisterMask(fm
, 21, 16));
1419 void vldr(FPRegisterID rd
, RegisterID rn
, int32_t imm
)
1421 vmem(rd
, rn
, imm
, true);
1424 void vmov(RegisterID rd
, FPRegisterID sn
)
1426 m_formatter
.vfpOp(0x0a10ee10 | (rd
<< 28) | singleRegisterMask(sn
, 0, 23));
1429 void vmov(FPRegisterID sn
, RegisterID rd
)
1431 m_formatter
.vfpOp(0x0a10ee00 | (rd
<< 28) | singleRegisterMask(sn
, 0, 23));
1434 // move FPSCR flags to APSR.
1435 void vmrs_APSR_nzcv_FPSCR()
1437 m_formatter
.vfpOp(0xfa10eef1);
1440 void vmul_F64(FPRegisterID rd
, FPRegisterID rn
, FPRegisterID rm
)
1442 m_formatter
.vfpOp(0x0b00ee20 | doubleRegisterMask(rd
, 6, 28) | doubleRegisterMask(rn
, 23, 0) | doubleRegisterMask(rm
, 21, 16));
1445 void vstr(FPRegisterID rd
, RegisterID rn
, int32_t imm
)
1447 vmem(rd
, rn
, imm
, false);
1450 void vsub_F64(FPRegisterID rd
, FPRegisterID rn
, FPRegisterID rm
)
1452 m_formatter
.vfpOp(0x0b40ee30 | doubleRegisterMask(rd
, 6, 28) | doubleRegisterMask(rn
, 23, 0) | doubleRegisterMask(rm
, 21, 16));
1458 return JmpDst(m_formatter
.size());
1461 JmpDst
align(int alignment
)
1463 while (!m_formatter
.isAligned(alignment
))
1469 static void* getRelocatedAddress(void* code
, JmpSrc jump
)
1471 ASSERT(jump
.m_offset
!= -1);
1473 return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code
) + jump
.m_offset
);
1476 static void* getRelocatedAddress(void* code
, JmpDst destination
)
1478 ASSERT(destination
.m_offset
!= -1);
1480 return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code
) + destination
.m_offset
);
1483 static int getDifferenceBetweenLabels(JmpDst src
, JmpDst dst
)
1485 return dst
.m_offset
- src
.m_offset
;
1488 static int getDifferenceBetweenLabels(JmpDst src
, JmpSrc dst
)
1490 return dst
.m_offset
- src
.m_offset
;
1493 static int getDifferenceBetweenLabels(JmpSrc src
, JmpDst dst
)
1495 return dst
.m_offset
- src
.m_offset
;
1498 // Assembler admin methods:
1502 return m_formatter
.size();
1505 void* executableCopy(ExecutablePool
* allocator
)
1507 void* copy
= m_formatter
.executableCopy(allocator
);
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
);
1515 m_jumpsToLink
.clear();
1521 static unsigned getCallReturnOffset(JmpSrc call
)
1523 ASSERT(call
.m_offset
>= 0);
1524 return call
.m_offset
;
1527 // Linking & patching:
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.
1535 void linkJump(JmpSrc from
, JmpDst to
)
1537 ASSERT(to
.m_offset
!= -1);
1538 ASSERT(from
.m_offset
!= -1);
1539 m_jumpsToLink
.append(LinkRecord(from
.m_offset
, to
.m_offset
));
1542 static void linkJump(void* code
, JmpSrc from
, void* to
)
1544 ASSERT(from
.m_offset
!= -1);
1546 uint16_t* location
= reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code
) + from
.m_offset
);
1547 linkJumpAbsolute(location
, to
);
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
)
1554 ASSERT(!(reinterpret_cast<intptr_t>(code
) & 1));
1555 ASSERT(from
.m_offset
!= -1);
1556 ASSERT(reinterpret_cast<intptr_t>(to
) & 1);
1558 setPointer(reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code
) + from
.m_offset
) - 1, to
);
1561 static void linkPointer(void* code
, JmpDst where
, void* value
)
1563 setPointer(reinterpret_cast<char*>(code
) + where
.m_offset
, value
);
1566 static void relinkJump(void* from
, void* to
)
1568 ASSERT(!(reinterpret_cast<intptr_t>(from
) & 1));
1569 ASSERT(!(reinterpret_cast<intptr_t>(to
) & 1));
1571 linkJumpAbsolute(reinterpret_cast<uint16_t*>(from
), to
);
1573 ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(from
) - 5, 5 * sizeof(uint16_t));
1576 static void relinkCall(void* from
, void* to
)
1578 ASSERT(!(reinterpret_cast<intptr_t>(from
) & 1));
1579 ASSERT(reinterpret_cast<intptr_t>(to
) & 1);
1581 setPointer(reinterpret_cast<uint16_t*>(from
) - 1, to
);
1583 ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(from
) - 5, 4 * sizeof(uint16_t));
1586 static void repatchInt32(void* where
, int32_t value
)
1588 ASSERT(!(reinterpret_cast<intptr_t>(where
) & 1));
1590 setInt32(where
, value
);
1592 ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(where
) - 4, 4 * sizeof(uint16_t));
1595 static void repatchPointer(void* where
, void* value
)
1597 ASSERT(!(reinterpret_cast<intptr_t>(where
) & 1));
1599 setPointer(where
, value
);
1601 ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(where
) - 4, 4 * sizeof(uint16_t));
1604 static void repatchLoadPtrToLEA(void* where
)
1606 ASSERT(!(reinterpret_cast<intptr_t>(where
) & 1));
1608 uint16_t* loadOp
= reinterpret_cast<uint16_t*>(where
) + 4;
1609 ASSERT((*loadOp
& 0xfff0) == OP_LDR_reg_T2
);
1611 *loadOp
= OP_ADD_reg_T3
| (*loadOp
& 0xf);
1612 ExecutableAllocator::cacheFlush(loadOp
, sizeof(uint16_t));
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
)
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);
1636 m_formatter
.vfpOp(0x0b00ed00 | offset
| (up
<< 7) | (isLoad
<< 4) | doubleRegisterMask(rd
, 6, 28) | rn
);
1639 static void setInt32(void* code
, uint32_t value
)
1641 uint16_t* location
= reinterpret_cast<uint16_t*>(code
);
1642 ASSERT(isMOV_imm_T3(location
- 4) && isMOVT(location
- 2));
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
);
1651 ExecutableAllocator::cacheFlush(location
- 4, 4 * sizeof(uint16_t));
1654 static void setPointer(void* code
, void* value
)
1656 setInt32(code
, reinterpret_cast<uint32_t>(value
));
1659 static bool isB(void* address
)
1661 uint16_t* instruction
= static_cast<uint16_t*>(address
);
1662 return ((instruction
[0] & 0xf800) == OP_B_T4a
) && ((instruction
[1] & 0xd000) == OP_B_T4b
);
1665 static bool isBX(void* address
)
1667 uint16_t* instruction
= static_cast<uint16_t*>(address
);
1668 return (instruction
[0] & 0xff87) == OP_BX
;
1671 static bool isMOV_imm_T3(void* address
)
1673 uint16_t* instruction
= static_cast<uint16_t*>(address
);
1674 return ((instruction
[0] & 0xFBF0) == OP_MOV_imm_T3
) && ((instruction
[1] & 0x8000) == 0);
1677 static bool isMOVT(void* address
)
1679 uint16_t* instruction
= static_cast<uint16_t*>(address
);
1680 return ((instruction
[0] & 0xFBF0) == OP_MOVT
) && ((instruction
[1] & 0x8000) == 0);
1683 static bool isNOP_T1(void* address
)
1685 uint16_t* instruction
= static_cast<uint16_t*>(address
);
1686 return instruction
[0] == OP_NOP_T1
;
1689 static bool isNOP_T2(void* address
)
1691 uint16_t* instruction
= static_cast<uint16_t*>(address
);
1692 return (instruction
[0] == OP_NOP_T2a
) && (instruction
[1] == OP_NOP_T2b
);
1695 static void linkJumpAbsolute(uint16_t* instruction
, void* target
)
1697 // FIMXE: this should be up in the MacroAssembler layer. :-(
1698 const uint16_t JUMP_TEMPORARY_REGISTER
= ARMRegisters::ip
;
1700 ASSERT(!(reinterpret_cast<intptr_t>(instruction
) & 1));
1701 ASSERT(!(reinterpret_cast<intptr_t>(target
) & 1));
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)) );
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'.
1710 relative
^= 0xC00000;
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);
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);
1735 static uint16_t twoWordOp5i6Imm4Reg4EncodedImmFirst(uint16_t op
, ARMThumbImmediate imm
)
1737 return op
| (imm
.m_value
.i
<< 10) | imm
.m_value
.imm4
;
1739 static uint16_t twoWordOp5i6Imm4Reg4EncodedImmSecond(uint16_t rd
, ARMThumbImmediate imm
)
1741 return (imm
.m_value
.imm3
<< 12) | (rd
<< 8) | imm
.m_value
.imm8
;
1744 class ARMInstructionFormatter
{
1746 void oneWordOp5Reg3Imm8(OpcodeID op
, RegisterID rd
, uint8_t imm
)
1748 m_buffer
.putShort(op
| (rd
<< 8) | imm
);
1751 void oneWordOp5Imm5Reg3Reg3(OpcodeID op
, uint8_t imm
, RegisterID reg1
, RegisterID reg2
)
1753 m_buffer
.putShort(op
| (imm
<< 6) | (reg1
<< 3) | reg2
);
1756 void oneWordOp7Reg3Reg3Reg3(OpcodeID op
, RegisterID reg1
, RegisterID reg2
, RegisterID reg3
)
1758 m_buffer
.putShort(op
| (reg1
<< 6) | (reg2
<< 3) | reg3
);
1761 void oneWordOp8Imm8(OpcodeID op
, uint8_t imm
)
1763 m_buffer
.putShort(op
| imm
);
1766 void oneWordOp8RegReg143(OpcodeID op
, RegisterID reg1
, RegisterID reg2
)
1768 m_buffer
.putShort(op
| ((reg2
& 8) << 4) | (reg1
<< 3) | (reg2
& 7));
1770 void oneWordOp9Imm7(OpcodeID op
, uint8_t imm
)
1772 m_buffer
.putShort(op
| imm
);
1775 void oneWordOp10Reg3Reg3(OpcodeID op
, RegisterID reg1
, RegisterID reg2
)
1777 m_buffer
.putShort(op
| (reg1
<< 3) | reg2
);
1780 void twoWordOp12Reg4FourFours(OpcodeID1 op
, RegisterID reg
, FourFours ff
)
1782 m_buffer
.putShort(op
| reg
);
1783 m_buffer
.putShort(ff
.m_u
.value
);
1786 void twoWordOp16FourFours(OpcodeID1 op
, FourFours ff
)
1788 m_buffer
.putShort(op
);
1789 m_buffer
.putShort(ff
.m_u
.value
);
1792 void twoWordOp16Op16(OpcodeID1 op1
, OpcodeID2 op2
)
1794 m_buffer
.putShort(op1
);
1795 m_buffer
.putShort(op2
);
1798 void twoWordOp5i6Imm4Reg4EncodedImm(OpcodeID1 op
, int imm4
, RegisterID rd
, ARMThumbImmediate imm
)
1800 ARMThumbImmediate newImm
= imm
;
1801 newImm
.m_value
.imm4
= imm4
;
1803 m_buffer
.putShort(ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmFirst(op
, newImm
));
1804 m_buffer
.putShort(ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmSecond(rd
, newImm
));
1807 void twoWordOp12Reg4Reg4Imm12(OpcodeID1 op
, RegisterID reg1
, RegisterID reg2
, uint16_t imm
)
1809 m_buffer
.putShort(op
| reg1
);
1810 m_buffer
.putShort((reg2
<< 12) | imm
);
1813 void vfpOp(int32_t op
)
1815 m_buffer
.putInt(op
);
1819 // Administrative methods:
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
); }
1827 AssemblerBuffer m_buffer
;
1830 Vector
<LinkRecord
> m_jumpsToLink
;
1835 #endif // ENABLE(ASSEMBLER) && CPU(ARM_THUMB2)
1837 #endif // ARMAssembler_h