1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=79:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Copyright (C) 2009 Apple Inc. All rights reserved.
6 * Copyright (C) 2010 University of Szeged
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * ***** END LICENSE BLOCK ***** */
31 #ifndef ARMAssembler_h
32 #define ARMAssembler_h
34 #include "assembler/wtf/Platform.h"
36 #if ENABLE(ASSEMBLER) && CPU(ARM_THUMB2)
38 #include "AssemblerBuffer.h"
39 #include "assembler/wtf/Assertions.h"
40 #include "assembler/wtf/Vector.h"
45 namespace ARMRegisters {
54 r7, wr = r7, // thumb work register
56 r9, sb = r9, // static base
57 r10, sl = r10, // stack limit
58 r11, fp = r11, // frame pointer
168 class ARMv7Assembler;
169 class ARMThumbImmediate {
170 friend class ARMv7Assembler;
172 typedef uint8_t ThumbImmediateType;
173 static const ThumbImmediateType TypeInvalid = 0;
174 static const ThumbImmediateType TypeEncoded = 1;
175 static const ThumbImmediateType TypeUInt16 = 2;
185 // If this is an encoded immediate, then it may describe a shift, or a pattern.
187 unsigned shiftValue7 : 7;
188 unsigned shiftAmount : 5;
191 unsigned immediate : 8;
192 unsigned pattern : 4;
194 } ThumbImmediateValue;
196 // byte0 contains least significant bit; not using an array to make client code endian agnostic.
207 ALWAYS_INLINE static void countLeadingZerosPartial(uint32_t& value, int32_t& zeros, const int N)
209 if (value & ~((1 << N) - 1)) /* check for any of the top N bits (of 2N bits) are set */
210 value >>= N; /* if any were set, lose the bottom N */
211 else /* if none of the top N bits are set, */
212 zeros += N; /* then we have identified N leading zeros */
215 static int32_t countLeadingZeros(uint32_t value)
221 countLeadingZerosPartial(value, zeros, 16);
222 countLeadingZerosPartial(value, zeros, 8);
223 countLeadingZerosPartial(value, zeros, 4);
224 countLeadingZerosPartial(value, zeros, 2);
225 countLeadingZerosPartial(value, zeros, 1);
230 : m_type(TypeInvalid)
235 ARMThumbImmediate(ThumbImmediateType type, ThumbImmediateValue value)
241 ARMThumbImmediate(ThumbImmediateType type, uint16_t value)
244 // Make sure this constructor is only reached with type TypeUInt16;
245 // this extra parameter makes the code a little clearer by making it
246 // explicit at call sites which type is being constructed
247 ASSERT_UNUSED(type, type == TypeUInt16);
249 m_value.asInt = value;
253 static ARMThumbImmediate makeEncodedImm(uint32_t value)
255 ThumbImmediateValue encoding;
258 // okay, these are easy.
260 encoding.immediate = value;
261 encoding.pattern = 0;
262 return ARMThumbImmediate(TypeEncoded, encoding);
265 int32_t leadingZeros = countLeadingZeros(value);
266 // if there were 24 or more leading zeros, then we'd have hit the (value < 256) case.
267 ASSERT(leadingZeros < 24);
269 // Given a number with bit fields Z:B:C, where count(Z)+count(B)+count(C) == 32,
270 // Z are the bits known zero, B is the 8-bit immediate, C are the bits to check for
271 // zero. count(B) == 8, so the count of bits to be checked is 24 - count(Z).
272 int32_t rightShiftAmount = 24 - leadingZeros;
273 if (value == ((value >> rightShiftAmount) << rightShiftAmount)) {
274 // Shift the value down to the low byte position. The assign to
275 // shiftValue7 drops the implicit top bit.
276 encoding.shiftValue7 = value >> rightShiftAmount;
277 // The endoded shift amount is the magnitude of a right rotate.
278 encoding.shiftAmount = 8 + leadingZeros;
279 return ARMThumbImmediate(TypeEncoded, encoding);
285 if ((bytes.byte0 == bytes.byte1) && (bytes.byte0 == bytes.byte2) && (bytes.byte0 == bytes.byte3)) {
286 encoding.immediate = bytes.byte0;
287 encoding.pattern = 3;
288 return ARMThumbImmediate(TypeEncoded, encoding);
291 if ((bytes.byte0 == bytes.byte2) && !(bytes.byte1 | bytes.byte3)) {
292 encoding.immediate = bytes.byte0;
293 encoding.pattern = 1;
294 return ARMThumbImmediate(TypeEncoded, encoding);
297 if ((bytes.byte1 == bytes.byte3) && !(bytes.byte0 | bytes.byte2)) {
298 encoding.immediate = bytes.byte0;
299 encoding.pattern = 2;
300 return ARMThumbImmediate(TypeEncoded, encoding);
303 return ARMThumbImmediate();
306 static ARMThumbImmediate makeUInt12(int32_t value)
308 return (!(value & 0xfffff000))
309 ? ARMThumbImmediate(TypeUInt16, (uint16_t)value)
310 : ARMThumbImmediate();
313 static ARMThumbImmediate makeUInt12OrEncodedImm(int32_t value)
315 // If this is not a 12-bit unsigned it, try making an encoded immediate.
316 return (!(value & 0xfffff000))
317 ? ARMThumbImmediate(TypeUInt16, (uint16_t)value)
318 : makeEncodedImm(value);
321 // The 'make' methods, above, return a !isValid() value if the argument
322 // cannot be represented as the requested type. This methods is called
323 // 'get' since the argument can always be represented.
324 static ARMThumbImmediate makeUInt16(uint16_t value)
326 return ARMThumbImmediate(TypeUInt16, value);
331 return m_type != TypeInvalid;
334 // These methods rely on the format of encoded byte values.
335 bool isUInt3() { return !(m_value.asInt & 0xfff8); }
336 bool isUInt4() { return !(m_value.asInt & 0xfff0); }
337 bool isUInt5() { return !(m_value.asInt & 0xffe0); }
338 bool isUInt6() { return !(m_value.asInt & 0xffc0); }
339 bool isUInt7() { return !(m_value.asInt & 0xff80); }
340 bool isUInt8() { return !(m_value.asInt & 0xff00); }
341 bool isUInt9() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xfe00); }
342 bool isUInt10() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xfc00); }
343 bool isUInt12() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xf000); }
344 bool isUInt16() { return m_type == TypeUInt16; }
345 uint8_t getUInt3() { ASSERT(isUInt3()); return m_value.asInt; }
346 uint8_t getUInt4() { ASSERT(isUInt4()); return m_value.asInt; }
347 uint8_t getUInt5() { ASSERT(isUInt5()); return m_value.asInt; }
348 uint8_t getUInt6() { ASSERT(isUInt6()); return m_value.asInt; }
349 uint8_t getUInt7() { ASSERT(isUInt7()); return m_value.asInt; }
350 uint8_t getUInt8() { ASSERT(isUInt8()); return m_value.asInt; }
351 uint8_t getUInt9() { ASSERT(isUInt9()); return m_value.asInt; }
352 uint8_t getUInt10() { ASSERT(isUInt10()); return m_value.asInt; }
353 uint16_t getUInt12() { ASSERT(isUInt12()); return m_value.asInt; }
354 uint16_t getUInt16() { ASSERT(isUInt16()); return m_value.asInt; }
356 bool isEncodedImm() { return m_type == TypeEncoded; }
359 ThumbImmediateType m_type;
360 ThumbImmediateValue m_value;
370 SRType_RRX = SRType_ROR
373 class ARMv7Assembler;
374 class ShiftTypeAndAmount {
375 friend class ARMv7Assembler;
380 m_u.type = (ARMShiftType)0;
384 ShiftTypeAndAmount(ARMShiftType type, unsigned amount)
387 m_u.amount = amount & 31;
390 unsigned lo4() { return m_u.lo4; }
391 unsigned hi4() { return m_u.hi4; }
408 Some features of the Thumb instruction set are deprecated in ARMv7. Deprecated features affecting
409 instructions supported by ARMv7-M are as follows:
410 • use of the PC as <Rd> or <Rm> in a 16-bit ADD (SP plus register) instruction
411 • use of the SP as <Rm> in a 16-bit ADD (SP plus register) instruction
412 • use of the SP as <Rm> in a 16-bit CMP (register) instruction
413 • use of MOV (register) instructions in which <Rd> is the SP or PC and <Rm> is also the SP or PC.
414 • use of <Rn> as the lowest-numbered register in the register list of a 16-bit STM instruction with base
418 class ARMv7Assembler {
422 ASSERT(m_jumpsToLink.isEmpty());
425 typedef ARMRegisters::RegisterID RegisterID;
426 typedef ARMRegisters::FPRegisterID FPRegisterID;
428 // (HS, LO, HI, LS) -> (AE, B, A, BE)
429 // (VS, VC) -> (O, NO)
447 ConditionCS = ConditionHS,
448 ConditionCC = ConditionLO,
452 friend class ARMv7Assembler;
453 friend class ARMInstructionFormatter;
470 friend class ARMv7Assembler;
471 friend class ARMInstructionFormatter;
479 bool isUsed() const { return m_used; }
480 void used() { m_used = true; }
486 ASSERT(m_offset == offset);
496 LinkRecord(intptr_t from, intptr_t to)
507 bool BadReg(RegisterID reg)
509 return (reg == ARMRegisters::sp) || (reg == ARMRegisters::pc);
512 bool isSingleRegister(FPRegisterID reg)
514 // Check that the high bit isn't set (q16+), and that the low bit isn't (s1, s3, etc).
518 bool isDoubleRegister(FPRegisterID reg)
520 // Check that the high bit isn't set (q16+), and that the low bit isn't (s1, s3, etc).
521 return !(reg & ~(31 << 1));
524 bool isQuadRegister(FPRegisterID reg)
526 return !(reg & ~(31 << 2));
529 uint32_t singleRegisterNum(FPRegisterID reg)
531 ASSERT(isSingleRegister(reg));
535 uint32_t doubleRegisterNum(FPRegisterID reg)
537 ASSERT(isDoubleRegister(reg));
541 uint32_t quadRegisterNum(FPRegisterID reg)
543 ASSERT(isQuadRegister(reg));
547 uint32_t singleRegisterMask(FPRegisterID rd, int highBitsShift, int lowBitShift)
549 uint32_t rdNum = singleRegisterNum(rd);
550 uint32_t rdMask = (rdNum >> 1) << highBitsShift;
552 rdMask |= 1 << lowBitShift;
556 uint32_t doubleRegisterMask(FPRegisterID rd, int highBitShift, int lowBitsShift)
558 uint32_t rdNum = doubleRegisterNum(rd);
559 uint32_t rdMask = (rdNum & 0xf) << lowBitsShift;
561 rdMask |= 1 << highBitShift;
566 OP_ADD_reg_T1 = 0x1800,
567 OP_ADD_S_reg_T1 = 0x1800,
568 OP_SUB_reg_T1 = 0x1A00,
569 OP_SUB_S_reg_T1 = 0x1A00,
570 OP_ADD_imm_T1 = 0x1C00,
571 OP_ADD_S_imm_T1 = 0x1C00,
572 OP_SUB_imm_T1 = 0x1E00,
573 OP_SUB_S_imm_T1 = 0x1E00,
574 OP_MOV_imm_T1 = 0x2000,
575 OP_CMP_imm_T1 = 0x2800,
576 OP_ADD_imm_T2 = 0x3000,
577 OP_ADD_S_imm_T2 = 0x3000,
578 OP_SUB_imm_T2 = 0x3800,
579 OP_SUB_S_imm_T2 = 0x3800,
580 OP_AND_reg_T1 = 0x4000,
581 OP_EOR_reg_T1 = 0x4040,
582 OP_TST_reg_T1 = 0x4200,
583 OP_CMP_reg_T1 = 0x4280,
584 OP_ORR_reg_T1 = 0x4300,
585 OP_MVN_reg_T1 = 0x43C0,
586 OP_ADD_reg_T2 = 0x4400,
587 OP_MOV_reg_T1 = 0x4600,
590 OP_STR_reg_T1 = 0x5000,
591 OP_LDR_reg_T1 = 0x5800,
592 OP_LDRH_reg_T1 = 0x5A00,
593 OP_LDRB_reg_T1 = 0x5C00,
594 OP_STR_imm_T1 = 0x6000,
595 OP_LDR_imm_T1 = 0x6800,
596 OP_LDRB_imm_T1 = 0x7800,
597 OP_LDRH_imm_T1 = 0x8800,
598 OP_STR_imm_T2 = 0x9000,
599 OP_LDR_imm_T2 = 0x9800,
600 OP_ADD_SP_imm_T1 = 0xA800,
601 OP_ADD_SP_imm_T2 = 0xB000,
602 OP_SUB_SP_imm_T1 = 0xB080,
609 OP_AND_reg_T2 = 0xEA00,
610 OP_TST_reg_T2 = 0xEA10,
611 OP_ORR_reg_T2 = 0xEA40,
612 OP_ASR_imm_T1 = 0xEA4F,
613 OP_LSL_imm_T1 = 0xEA4F,
614 OP_LSR_imm_T1 = 0xEA4F,
615 OP_ROR_imm_T1 = 0xEA4F,
616 OP_MVN_reg_T2 = 0xEA6F,
617 OP_EOR_reg_T2 = 0xEA80,
618 OP_ADD_reg_T3 = 0xEB00,
619 OP_ADD_S_reg_T3 = 0xEB10,
620 OP_SUB_reg_T2 = 0xEBA0,
621 OP_SUB_S_reg_T2 = 0xEBB0,
622 OP_CMP_reg_T2 = 0xEBB0,
624 OP_AND_imm_T1 = 0xF000,
626 OP_ORR_imm_T1 = 0xF040,
627 OP_MOV_imm_T2 = 0xF040,
629 OP_EOR_imm_T1 = 0xF080,
630 OP_ADD_imm_T3 = 0xF100,
631 OP_ADD_S_imm_T3 = 0xF110,
633 OP_SUB_imm_T3 = 0xF1A0,
634 OP_SUB_S_imm_T3 = 0xF1B0,
635 OP_CMP_imm_T2 = 0xF1B0,
636 OP_ADD_imm_T4 = 0xF200,
637 OP_MOV_imm_T3 = 0xF240,
638 OP_SUB_imm_T4 = 0xF2A0,
641 OP_LDRB_imm_T3 = 0xF810,
642 OP_LDRB_reg_T2 = 0xF810,
643 OP_LDRH_reg_T2 = 0xF830,
644 OP_LDRH_imm_T3 = 0xF830,
645 OP_STR_imm_T4 = 0xF840,
646 OP_STR_reg_T2 = 0xF840,
647 OP_LDR_imm_T4 = 0xF850,
648 OP_LDR_reg_T2 = 0xF850,
649 OP_LDRB_imm_T2 = 0xF890,
650 OP_LDRH_imm_T2 = 0xF8B0,
651 OP_STR_imm_T3 = 0xF8C0,
652 OP_LDR_imm_T3 = 0xF8D0,
653 OP_LSL_reg_T2 = 0xFA00,
654 OP_LSR_reg_T2 = 0xFA20,
655 OP_ASR_reg_T2 = 0xFA40,
656 OP_ROR_reg_T2 = 0xFA60,
657 OP_SMULL_T1 = 0xFB80,
666 FourFours(unsigned f3, unsigned f2, unsigned f1, unsigned f0)
685 class ARMInstructionFormatter;
688 bool ifThenElseConditionBit(Condition condition, bool isIf)
690 return isIf ? (condition & 1) : !(condition & 1);
692 uint8_t ifThenElse(Condition condition, bool inst2if, bool inst3if, bool inst4if)
694 int mask = (ifThenElseConditionBit(condition, inst2if) << 3)
695 | (ifThenElseConditionBit(condition, inst3if) << 2)
696 | (ifThenElseConditionBit(condition, inst4if) << 1)
698 ASSERT((condition != ConditionAL) || (mask & (mask - 1)));
699 return (condition << 4) | mask;
701 uint8_t ifThenElse(Condition condition, bool inst2if, bool inst3if)
703 int mask = (ifThenElseConditionBit(condition, inst2if) << 3)
704 | (ifThenElseConditionBit(condition, inst3if) << 2)
706 ASSERT((condition != ConditionAL) || (mask & (mask - 1)));
707 return (condition << 4) | mask;
709 uint8_t ifThenElse(Condition condition, bool inst2if)
711 int mask = (ifThenElseConditionBit(condition, inst2if) << 3)
713 ASSERT((condition != ConditionAL) || (mask & (mask - 1)));
714 return (condition << 4) | mask;
717 uint8_t ifThenElse(Condition condition)
720 ASSERT((condition != ConditionAL) || (mask & (mask - 1)));
721 return (condition << 4) | mask;
726 void add(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
728 // Rd can only be SP if Rn is also SP.
729 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
730 ASSERT(rd != ARMRegisters::pc);
731 ASSERT(rn != ARMRegisters::pc);
732 ASSERT(imm.isValid());
734 if (rn == ARMRegisters::sp) {
735 if (!(rd & 8) && imm.isUInt10()) {
736 m_formatter.oneWordOp5Reg3Imm8(OP_ADD_SP_imm_T1, rd, imm.getUInt10() >> 2);
738 } else if ((rd == ARMRegisters::sp) && imm.isUInt9()) {
739 m_formatter.oneWordOp9Imm7(OP_ADD_SP_imm_T2, imm.getUInt9() >> 2);
742 } else if (!((rd | rn) & 8)) {
744 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_imm_T1, (RegisterID)imm.getUInt3(), rn, rd);
746 } else if ((rd == rn) && imm.isUInt8()) {
747 m_formatter.oneWordOp5Reg3Imm8(OP_ADD_imm_T2, rd, imm.getUInt8());
752 if (imm.isEncodedImm())
753 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T3, rn, rd, imm);
755 ASSERT(imm.isUInt12());
756 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T4, rn, rd, imm);
760 void add(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
762 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
763 ASSERT(rd != ARMRegisters::pc);
764 ASSERT(rn != ARMRegisters::pc);
766 m_formatter.twoWordOp12Reg4FourFours(OP_ADD_reg_T3, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
769 // NOTE: In an IT block, add doesn't modify the flags register.
770 void add(RegisterID rd, RegisterID rn, RegisterID rm)
773 m_formatter.oneWordOp8RegReg143(OP_ADD_reg_T2, rm, rd);
775 m_formatter.oneWordOp8RegReg143(OP_ADD_reg_T2, rn, rd);
776 else if (!((rd | rn | rm) & 8))
777 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_reg_T1, rm, rn, rd);
779 add(rd, rn, rm, ShiftTypeAndAmount());
782 // Not allowed in an IT (if then) block.
783 void add_S(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
785 // Rd can only be SP if Rn is also SP.
786 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
787 ASSERT(rd != ARMRegisters::pc);
788 ASSERT(rn != ARMRegisters::pc);
789 ASSERT(imm.isEncodedImm());
791 if (!((rd | rn) & 8)) {
793 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_S_imm_T1, (RegisterID)imm.getUInt3(), rn, rd);
795 } else if ((rd == rn) && imm.isUInt8()) {
796 m_formatter.oneWordOp5Reg3Imm8(OP_ADD_S_imm_T2, rd, imm.getUInt8());
801 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_S_imm_T3, rn, rd, imm);
804 // Not allowed in an IT (if then) block?
805 void add_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
807 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
808 ASSERT(rd != ARMRegisters::pc);
809 ASSERT(rn != ARMRegisters::pc);
811 m_formatter.twoWordOp12Reg4FourFours(OP_ADD_S_reg_T3, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
814 // Not allowed in an IT (if then) block.
815 void add_S(RegisterID rd, RegisterID rn, RegisterID rm)
817 if (!((rd | rn | rm) & 8))
818 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_S_reg_T1, rm, rn, rd);
820 add_S(rd, rn, rm, ShiftTypeAndAmount());
823 void ARM_and(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
827 ASSERT(imm.isEncodedImm());
828 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_AND_imm_T1, rn, rd, imm);
831 void ARM_and(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
836 m_formatter.twoWordOp12Reg4FourFours(OP_AND_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
839 void ARM_and(RegisterID rd, RegisterID rn, RegisterID rm)
841 if ((rd == rn) && !((rd | rm) & 8))
842 m_formatter.oneWordOp10Reg3Reg3(OP_AND_reg_T1, rm, rd);
843 else if ((rd == rm) && !((rd | rn) & 8))
844 m_formatter.oneWordOp10Reg3Reg3(OP_AND_reg_T1, rn, rd);
846 ARM_and(rd, rn, rm, ShiftTypeAndAmount());
849 void asr(RegisterID rd, RegisterID rm, int32_t shiftAmount)
853 ShiftTypeAndAmount shift(SRType_ASR, shiftAmount);
854 m_formatter.twoWordOp16FourFours(OP_ASR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
857 void asr(RegisterID rd, RegisterID rn, RegisterID rm)
862 m_formatter.twoWordOp12Reg4FourFours(OP_ASR_reg_T2, rn, FourFours(0xf, rd, 0, rm));
865 // Only allowed in IT (if then) block if last instruction.
868 m_formatter.twoWordOp16Op16(OP_B_T4a, OP_B_T4b);
869 return JmpSrc(m_formatter.size());
872 // Only allowed in IT (if then) block if last instruction.
873 JmpSrc blx(RegisterID rm)
875 ASSERT(rm != ARMRegisters::pc);
876 m_formatter.oneWordOp8RegReg143(OP_BLX, rm, (RegisterID)8);
877 return JmpSrc(m_formatter.size());
880 // Only allowed in IT (if then) block if last instruction.
881 JmpSrc bx(RegisterID rm)
883 m_formatter.oneWordOp8RegReg143(OP_BX, rm, (RegisterID)0);
884 return JmpSrc(m_formatter.size());
887 void bkpt(uint8_t imm=0)
889 m_formatter.oneWordOp8Imm8(OP_BKPT, imm);
892 void cmn(RegisterID rn, ARMThumbImmediate imm)
894 ASSERT(rn != ARMRegisters::pc);
895 ASSERT(imm.isEncodedImm());
897 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMN_imm, rn, (RegisterID)0xf, imm);
900 void cmp(RegisterID rn, ARMThumbImmediate imm)
902 ASSERT(rn != ARMRegisters::pc);
903 ASSERT(imm.isEncodedImm());
905 if (!(rn & 8) && imm.isUInt8())
906 m_formatter.oneWordOp5Reg3Imm8(OP_CMP_imm_T1, rn, imm.getUInt8());
908 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMP_imm_T2, rn, (RegisterID)0xf, imm);
911 void cmp(RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
913 ASSERT(rn != ARMRegisters::pc);
915 m_formatter.twoWordOp12Reg4FourFours(OP_CMP_reg_T2, rn, FourFours(shift.hi4(), 0xf, shift.lo4(), rm));
918 void cmp(RegisterID rn, RegisterID rm)
921 cmp(rn, rm, ShiftTypeAndAmount());
923 m_formatter.oneWordOp10Reg3Reg3(OP_CMP_reg_T1, rm, rn);
926 // xor is not spelled with an 'e'. :-(
927 void eor(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
931 ASSERT(imm.isEncodedImm());
932 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_EOR_imm_T1, rn, rd, imm);
935 // xor is not spelled with an 'e'. :-(
936 void eor(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
941 m_formatter.twoWordOp12Reg4FourFours(OP_EOR_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
944 // xor is not spelled with an 'e'. :-(
945 void eor(RegisterID rd, RegisterID rn, RegisterID rm)
947 if ((rd == rn) && !((rd | rm) & 8))
948 m_formatter.oneWordOp10Reg3Reg3(OP_EOR_reg_T1, rm, rd);
949 else if ((rd == rm) && !((rd | rn) & 8))
950 m_formatter.oneWordOp10Reg3Reg3(OP_EOR_reg_T1, rn, rd);
952 eor(rd, rn, rm, ShiftTypeAndAmount());
955 void it(Condition cond)
957 m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond));
960 void it(Condition cond, bool inst2if)
962 m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if));
965 void it(Condition cond, bool inst2if, bool inst3if)
967 m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if, inst3if));
970 void it(Condition cond, bool inst2if, bool inst3if, bool inst4if)
972 m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if, inst3if, inst4if));
975 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
976 void ldr(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
978 ASSERT(rn != ARMRegisters::pc); // LDR (literal)
979 ASSERT(imm.isUInt12());
981 if (!((rt | rn) & 8) && imm.isUInt7())
982 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDR_imm_T1, imm.getUInt7() >> 2, rn, rt);
983 else if ((rn == ARMRegisters::sp) && !(rt & 8) && imm.isUInt10())
984 m_formatter.oneWordOp5Reg3Imm8(OP_LDR_imm_T2, rt, imm.getUInt10() >> 2);
986 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T3, rn, rt, imm.getUInt12());
989 // If index is set, this is a regular offset or a pre-indexed load;
990 // if index is not set then is is a post-index load.
992 // If wback is set rn is updated - this is a pre or post index load,
993 // if wback is not set this is a regular offset memory access.
995 // (-255 <= offset <= 255)
997 // _tmp = _reg + offset
998 // MEM[index ? _tmp : _reg] = REG[rt]
999 // if (wback) REG[rn] = _tmp
1000 void ldr(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
1002 ASSERT(rt != ARMRegisters::pc);
1003 ASSERT(rn != ARMRegisters::pc);
1004 ASSERT(index || wback);
1005 ASSERT(!wback | (rt != rn));
1012 ASSERT((offset & ~0xff) == 0);
1014 offset |= (wback << 8);
1015 offset |= (add << 9);
1016 offset |= (index << 10);
1017 offset |= (1 << 11);
1019 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T4, rn, rt, offset);
1022 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1023 void ldr(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0)
1025 ASSERT(rn != ARMRegisters::pc); // LDR (literal)
1026 ASSERT(!BadReg(rm));
1029 if (!shift && !((rt | rn | rm) & 8))
1030 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDR_reg_T1, rm, rn, rt);
1032 m_formatter.twoWordOp12Reg4FourFours(OP_LDR_reg_T2, rn, FourFours(rt, 0, shift, rm));
1035 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1036 void ldrh(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
1038 ASSERT(rn != ARMRegisters::pc); // LDR (literal)
1039 ASSERT(imm.isUInt12());
1041 if (!((rt | rn) & 8) && imm.isUInt6())
1042 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDRH_imm_T1, imm.getUInt6() >> 2, rn, rt);
1044 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T2, rn, rt, imm.getUInt12());
1047 // If index is set, this is a regular offset or a pre-indexed load;
1048 // if index is not set then is is a post-index load.
1050 // If wback is set rn is updated - this is a pre or post index load,
1051 // if wback is not set this is a regular offset memory access.
1053 // (-255 <= offset <= 255)
1055 // _tmp = _reg + offset
1056 // MEM[index ? _tmp : _reg] = REG[rt]
1057 // if (wback) REG[rn] = _tmp
1058 void ldrh(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
1060 ASSERT(rt != ARMRegisters::pc);
1061 ASSERT(rn != ARMRegisters::pc);
1062 ASSERT(index || wback);
1063 ASSERT(!wback | (rt != rn));
1070 ASSERT((offset & ~0xff) == 0);
1072 offset |= (wback << 8);
1073 offset |= (add << 9);
1074 offset |= (index << 10);
1075 offset |= (1 << 11);
1077 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T3, rn, rt, offset);
1080 void ldrh(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0)
1082 ASSERT(!BadReg(rt)); // Memory hint
1083 ASSERT(rn != ARMRegisters::pc); // LDRH (literal)
1084 ASSERT(!BadReg(rm));
1087 if (!shift && !((rt | rn | rm) & 8))
1088 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDRH_reg_T1, rm, rn, rt);
1090 m_formatter.twoWordOp12Reg4FourFours(OP_LDRH_reg_T2, rn, FourFours(rt, 0, shift, rm));
1093 void ldrb(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
1095 ASSERT(rn != ARMRegisters::pc); // LDR (literal)
1096 ASSERT(imm.isUInt12());
1098 if (!((rt | rn) & 8) && imm.isUInt5())
1099 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDRB_imm_T1, imm.getUInt5(), rn, rt);
1101 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRB_imm_T2, rn, rt, imm.getUInt12());
1104 void ldrb(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
1106 ASSERT(rt != ARMRegisters::pc);
1107 ASSERT(rn != ARMRegisters::pc);
1108 ASSERT(index || wback);
1109 ASSERT(!wback | (rt != rn));
1117 ASSERT(!(offset & ~0xff));
1119 offset |= (wback << 8);
1120 offset |= (add << 9);
1121 offset |= (index << 10);
1122 offset |= (1 << 11);
1124 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRB_imm_T3, rn, rt, offset);
1127 void ldrb(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0)
1129 ASSERT(rn != ARMRegisters::pc); // LDR (literal)
1130 ASSERT(!BadReg(rm));
1133 if (!shift && !((rt | rn | rm) & 8))
1134 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDRB_reg_T1, rm, rn, rt);
1136 m_formatter.twoWordOp12Reg4FourFours(OP_LDRB_reg_T2, rn, FourFours(rt, 0, shift, rm));
1139 void lsl(RegisterID rd, RegisterID rm, int32_t shiftAmount)
1141 ASSERT(!BadReg(rd));
1142 ASSERT(!BadReg(rm));
1143 ShiftTypeAndAmount shift(SRType_LSL, shiftAmount);
1144 m_formatter.twoWordOp16FourFours(OP_LSL_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1147 void lsl(RegisterID rd, RegisterID rn, RegisterID rm)
1149 ASSERT(!BadReg(rd));
1150 ASSERT(!BadReg(rn));
1151 ASSERT(!BadReg(rm));
1152 m_formatter.twoWordOp12Reg4FourFours(OP_LSL_reg_T2, rn, FourFours(0xf, rd, 0, rm));
1155 void lsr(RegisterID rd, RegisterID rm, int32_t shiftAmount)
1157 ASSERT(!BadReg(rd));
1158 ASSERT(!BadReg(rm));
1159 ShiftTypeAndAmount shift(SRType_LSR, shiftAmount);
1160 m_formatter.twoWordOp16FourFours(OP_LSR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1163 void lsr(RegisterID rd, RegisterID rn, RegisterID rm)
1165 ASSERT(!BadReg(rd));
1166 ASSERT(!BadReg(rn));
1167 ASSERT(!BadReg(rm));
1168 m_formatter.twoWordOp12Reg4FourFours(OP_LSR_reg_T2, rn, FourFours(0xf, rd, 0, rm));
1171 void movT3(RegisterID rd, ARMThumbImmediate imm)
1173 ASSERT(imm.isValid());
1174 ASSERT(!imm.isEncodedImm());
1175 ASSERT(!BadReg(rd));
1177 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T3, imm.m_value.imm4, rd, imm);
1180 void mov(RegisterID rd, ARMThumbImmediate imm)
1182 ASSERT(imm.isValid());
1183 ASSERT(!BadReg(rd));
1185 if ((rd < 8) && imm.isUInt8())
1186 m_formatter.oneWordOp5Reg3Imm8(OP_MOV_imm_T1, rd, imm.getUInt8());
1187 else if (imm.isEncodedImm())
1188 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T2, 0xf, rd, imm);
1193 void mov(RegisterID rd, RegisterID rm)
1195 m_formatter.oneWordOp8RegReg143(OP_MOV_reg_T1, rm, rd);
1198 void movt(RegisterID rd, ARMThumbImmediate imm)
1200 ASSERT(imm.isUInt16());
1201 ASSERT(!BadReg(rd));
1202 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOVT, imm.m_value.imm4, rd, imm);
1205 void mvn(RegisterID rd, ARMThumbImmediate imm)
1207 ASSERT(imm.isEncodedImm());
1208 ASSERT(!BadReg(rd));
1210 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MVN_imm, 0xf, rd, imm);
1213 void mvn(RegisterID rd, RegisterID rm, ShiftTypeAndAmount shift)
1215 ASSERT(!BadReg(rd));
1216 ASSERT(!BadReg(rm));
1217 m_formatter.twoWordOp16FourFours(OP_MVN_reg_T2, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1220 void mvn(RegisterID rd, RegisterID rm)
1222 if (!((rd | rm) & 8))
1223 m_formatter.oneWordOp10Reg3Reg3(OP_MVN_reg_T1, rm, rd);
1225 mvn(rd, rm, ShiftTypeAndAmount());
1228 void orr(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
1230 ASSERT(!BadReg(rd));
1231 ASSERT(!BadReg(rn));
1232 ASSERT(imm.isEncodedImm());
1233 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ORR_imm_T1, rn, rd, imm);
1236 void orr(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
1238 ASSERT(!BadReg(rd));
1239 ASSERT(!BadReg(rn));
1240 ASSERT(!BadReg(rm));
1241 m_formatter.twoWordOp12Reg4FourFours(OP_ORR_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1244 void orr(RegisterID rd, RegisterID rn, RegisterID rm)
1246 if ((rd == rn) && !((rd | rm) & 8))
1247 m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rm, rd);
1248 else if ((rd == rm) && !((rd | rn) & 8))
1249 m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rn, rd);
1251 orr(rd, rn, rm, ShiftTypeAndAmount());
1254 void ror(RegisterID rd, RegisterID rm, int32_t shiftAmount)
1256 ASSERT(!BadReg(rd));
1257 ASSERT(!BadReg(rm));
1258 ShiftTypeAndAmount shift(SRType_ROR, shiftAmount);
1259 m_formatter.twoWordOp16FourFours(OP_ROR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1262 void ror(RegisterID rd, RegisterID rn, RegisterID rm)
1264 ASSERT(!BadReg(rd));
1265 ASSERT(!BadReg(rn));
1266 ASSERT(!BadReg(rm));
1267 m_formatter.twoWordOp12Reg4FourFours(OP_ROR_reg_T2, rn, FourFours(0xf, rd, 0, rm));
1270 void smull(RegisterID rdLo, RegisterID rdHi, RegisterID rn, RegisterID rm)
1272 ASSERT(!BadReg(rdLo));
1273 ASSERT(!BadReg(rdHi));
1274 ASSERT(!BadReg(rn));
1275 ASSERT(!BadReg(rm));
1276 ASSERT(rdLo != rdHi);
1277 m_formatter.twoWordOp12Reg4FourFours(OP_SMULL_T1, rn, FourFours(rdLo, rdHi, 0, rm));
1280 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1281 void str(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
1283 ASSERT(rt != ARMRegisters::pc);
1284 ASSERT(rn != ARMRegisters::pc);
1285 ASSERT(imm.isUInt12());
1287 if (!((rt | rn) & 8) && imm.isUInt7())
1288 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_STR_imm_T1, imm.getUInt7() >> 2, rn, rt);
1289 else if ((rn == ARMRegisters::sp) && !(rt & 8) && imm.isUInt10())
1290 m_formatter.oneWordOp5Reg3Imm8(OP_STR_imm_T2, rt, imm.getUInt10() >> 2);
1292 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T3, rn, rt, imm.getUInt12());
1295 // If index is set, this is a regular offset or a pre-indexed store;
1296 // if index is not set then is is a post-index store.
1298 // If wback is set rn is updated - this is a pre or post index store,
1299 // if wback is not set this is a regular offset memory access.
1301 // (-255 <= offset <= 255)
1303 // _tmp = _reg + offset
1304 // MEM[index ? _tmp : _reg] = REG[rt]
1305 // if (wback) REG[rn] = _tmp
1306 void str(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
1308 ASSERT(rt != ARMRegisters::pc);
1309 ASSERT(rn != ARMRegisters::pc);
1310 ASSERT(index || wback);
1311 ASSERT(!wback | (rt != rn));
1318 ASSERT((offset & ~0xff) == 0);
1320 offset |= (wback << 8);
1321 offset |= (add << 9);
1322 offset |= (index << 10);
1323 offset |= (1 << 11);
1325 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T4, rn, rt, offset);
1328 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1329 void str(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0)
1331 ASSERT(rn != ARMRegisters::pc);
1332 ASSERT(!BadReg(rm));
1335 if (!shift && !((rt | rn | rm) & 8))
1336 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_STR_reg_T1, rm, rn, rt);
1338 m_formatter.twoWordOp12Reg4FourFours(OP_STR_reg_T2, rn, FourFours(rt, 0, shift, rm));
1341 void sub(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
1343 // Rd can only be SP if Rn is also SP.
1344 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
1345 ASSERT(rd != ARMRegisters::pc);
1346 ASSERT(rn != ARMRegisters::pc);
1347 ASSERT(imm.isValid());
1349 if ((rn == ARMRegisters::sp) && (rd == ARMRegisters::sp) && imm.isUInt9()) {
1350 m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, imm.getUInt9() >> 2);
1352 } else if (!((rd | rn) & 8)) {
1353 if (imm.isUInt3()) {
1354 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_imm_T1, (RegisterID)imm.getUInt3(), rn, rd);
1356 } else if ((rd == rn) && imm.isUInt8()) {
1357 m_formatter.oneWordOp5Reg3Imm8(OP_SUB_imm_T2, rd, imm.getUInt8());
1362 if (imm.isEncodedImm())
1363 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T3, rn, rd, imm);
1365 ASSERT(imm.isUInt12());
1366 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T4, rn, rd, imm);
1370 void sub(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
1372 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
1373 ASSERT(rd != ARMRegisters::pc);
1374 ASSERT(rn != ARMRegisters::pc);
1375 ASSERT(!BadReg(rm));
1376 m_formatter.twoWordOp12Reg4FourFours(OP_SUB_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1379 // NOTE: In an IT block, add doesn't modify the flags register.
1380 void sub(RegisterID rd, RegisterID rn, RegisterID rm)
1382 if (!((rd | rn | rm) & 8))
1383 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_reg_T1, rm, rn, rd);
1385 sub(rd, rn, rm, ShiftTypeAndAmount());
1388 // Not allowed in an IT (if then) block.
1389 void sub_S(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
1391 // Rd can only be SP if Rn is also SP.
1392 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
1393 ASSERT(rd != ARMRegisters::pc);
1394 ASSERT(rn != ARMRegisters::pc);
1395 ASSERT(imm.isValid());
1397 if ((rn == ARMRegisters::sp) && (rd == ARMRegisters::sp) && imm.isUInt9()) {
1398 m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, imm.getUInt9() >> 2);
1400 } else if (!((rd | rn) & 8)) {
1401 if (imm.isUInt3()) {
1402 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_S_imm_T1, (RegisterID)imm.getUInt3(), rn, rd);
1404 } else if ((rd == rn) && imm.isUInt8()) {
1405 m_formatter.oneWordOp5Reg3Imm8(OP_SUB_S_imm_T2, rd, imm.getUInt8());
1410 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_S_imm_T3, rn, rd, imm);
1413 // Not allowed in an IT (if then) block?
1414 void sub_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
1416 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
1417 ASSERT(rd != ARMRegisters::pc);
1418 ASSERT(rn != ARMRegisters::pc);
1419 ASSERT(!BadReg(rm));
1420 m_formatter.twoWordOp12Reg4FourFours(OP_SUB_S_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1423 // Not allowed in an IT (if then) block.
1424 void sub_S(RegisterID rd, RegisterID rn, RegisterID rm)
1426 if (!((rd | rn | rm) & 8))
1427 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_S_reg_T1, rm, rn, rd);
1429 sub_S(rd, rn, rm, ShiftTypeAndAmount());
1432 void tst(RegisterID rn, ARMThumbImmediate imm)
1434 ASSERT(!BadReg(rn));
1435 ASSERT(imm.isEncodedImm());
1437 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_TST_imm, rn, (RegisterID)0xf, imm);
1440 void tst(RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
1442 ASSERT(!BadReg(rn));
1443 ASSERT(!BadReg(rm));
1444 m_formatter.twoWordOp12Reg4FourFours(OP_TST_reg_T2, rn, FourFours(shift.hi4(), 0xf, shift.lo4(), rm));
1447 void tst(RegisterID rn, RegisterID rm)
1450 tst(rn, rm, ShiftTypeAndAmount());
1452 m_formatter.oneWordOp10Reg3Reg3(OP_TST_reg_T1, rm, rn);
1455 void vadd_F64(FPRegisterID rd, FPRegisterID rn, FPRegisterID rm)
1457 m_formatter.vfpOp(0x0b00ee30 | doubleRegisterMask(rd, 6, 28) | doubleRegisterMask(rn, 23, 0) | doubleRegisterMask(rm, 21, 16));
1460 void vcmp_F64(FPRegisterID rd, FPRegisterID rm)
1462 m_formatter.vfpOp(0x0bc0eeb4 | doubleRegisterMask(rd, 6, 28) | doubleRegisterMask(rm, 21, 16));
1465 void vcvt_F64_S32(FPRegisterID fd, FPRegisterID sm)
1467 m_formatter.vfpOp(0x0bc0eeb8 | doubleRegisterMask(fd, 6, 28) | singleRegisterMask(sm, 16, 21));
1470 void vcvt_S32_F64(FPRegisterID sd, FPRegisterID fm)
1472 m_formatter.vfpOp(0x0bc0eebd | singleRegisterMask(sd, 28, 6) | doubleRegisterMask(fm, 21, 16));
1475 void vldr(FPRegisterID rd, RegisterID rn, int32_t imm)
1477 vmem(rd, rn, imm, true);
1480 void vmov(RegisterID rd, FPRegisterID sn)
1482 m_formatter.vfpOp(0x0a10ee10 | (rd << 28) | singleRegisterMask(sn, 0, 23));
1485 void vmov(FPRegisterID sn, RegisterID rd)
1487 m_formatter.vfpOp(0x0a10ee00 | (rd << 28) | singleRegisterMask(sn, 0, 23));
1490 // move FPSCR flags to APSR.
1491 void vmrs_APSR_nzcv_FPSCR()
1493 m_formatter.vfpOp(0xfa10eef1);
1496 void vmul_F64(FPRegisterID rd, FPRegisterID rn, FPRegisterID rm)
1498 m_formatter.vfpOp(0x0b00ee20 | doubleRegisterMask(rd, 6, 28) | doubleRegisterMask(rn, 23, 0) | doubleRegisterMask(rm, 21, 16));
1501 void vstr(FPRegisterID rd, RegisterID rn, int32_t imm)
1503 vmem(rd, rn, imm, false);
1506 void vsub_F64(FPRegisterID rd, FPRegisterID rn, FPRegisterID rm)
1508 m_formatter.vfpOp(0x0b40ee30 | doubleRegisterMask(rd, 6, 28) | doubleRegisterMask(rn, 23, 0) | doubleRegisterMask(rm, 21, 16));
1514 return JmpDst(m_formatter.size());
1517 JmpDst align(int alignment)
1519 while (!m_formatter.isAligned(alignment))
1525 static void* getRelocatedAddress(void* code, JmpSrc jump)
1527 ASSERT(jump.m_offset != -1);
1529 return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + jump.m_offset);
1532 static void* getRelocatedAddress(void* code, JmpDst destination)
1534 ASSERT(destination.m_offset != -1);
1536 return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + destination.m_offset);
1539 static int getDifferenceBetweenLabels(JmpDst src, JmpDst dst)
1541 return dst.m_offset - src.m_offset;
1544 static int getDifferenceBetweenLabels(JmpDst src, JmpSrc dst)
1546 return dst.m_offset - src.m_offset;
1549 static int getDifferenceBetweenLabels(JmpSrc src, JmpDst dst)
1551 return dst.m_offset - src.m_offset;
1554 // Assembler admin methods:
1558 return m_formatter.size();
1561 void* executableCopy(ExecutablePool* allocator)
1563 void* copy = m_formatter.executableCopy(allocator);
1565 unsigned jumpCount = m_jumpsToLink.size();
1566 for (unsigned i = 0; i < jumpCount; ++i) {
1567 uint16_t* location = reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(copy) + m_jumpsToLink[i].from);
1568 uint16_t* target = reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(copy) + m_jumpsToLink[i].to);
1569 linkJumpAbsolute(location, target);
1571 m_jumpsToLink.clear();
1577 static unsigned getCallReturnOffset(JmpSrc call)
1579 ASSERT(call.m_offset >= 0);
1580 return call.m_offset;
1583 // Linking & patching:
1585 // 'link' and 'patch' methods are for use on unprotected code - such as the code
1586 // within the AssemblerBuffer, and code being patched by the patch buffer. Once
1587 // code has been finalized it is (platform support permitting) within a non-
1588 // writable region of memory; to modify the code in an execute-only execuable
1589 // pool the 'repatch' and 'relink' methods should be used.
1591 void linkJump(JmpSrc from, JmpDst to)
1593 ASSERT(to.m_offset != -1);
1594 ASSERT(from.m_offset != -1);
1595 m_jumpsToLink.append(LinkRecord(from.m_offset, to.m_offset));
1598 static void linkJump(void* code, JmpSrc from, void* to)
1600 ASSERT(from.m_offset != -1);
1602 uint16_t* location = reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
1603 linkJumpAbsolute(location, to);
1606 // bah, this mathod should really be static, since it is used by the LinkBuffer.
1607 // return a bool saying whether the link was successful?
1608 static void linkCall(void* code, JmpSrc from, void* to)
1610 ASSERT(!(reinterpret_cast<intptr_t>(code) & 1));
1611 ASSERT(from.m_offset != -1);
1612 ASSERT(reinterpret_cast<intptr_t>(to) & 1);
1614 setPointer(reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code) + from.m_offset) - 1, to);
1617 static void linkPointer(void* code, JmpDst where, void* value)
1619 setPointer(reinterpret_cast<char*>(code) + where.m_offset, value);
1622 static void relinkJump(void* from, void* to)
1624 ASSERT(!(reinterpret_cast<intptr_t>(from) & 1));
1625 ASSERT(!(reinterpret_cast<intptr_t>(to) & 1));
1627 linkJumpAbsolute(reinterpret_cast<uint16_t*>(from), to);
1629 ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(from) - 5, 5 * sizeof(uint16_t));
1632 static bool canRelinkJump(void* from, void* to)
1637 static void relinkCall(void* from, void* to)
1639 ASSERT(!(reinterpret_cast<intptr_t>(from) & 1));
1640 ASSERT(reinterpret_cast<intptr_t>(to) & 1);
1642 setPointer(reinterpret_cast<uint16_t*>(from) - 1, to);
1644 ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(from) - 5, 4 * sizeof(uint16_t));
1647 static void repatchInt32(void* where, int32_t value)
1649 ASSERT(!(reinterpret_cast<intptr_t>(where) & 1));
1651 setInt32(where, value);
1653 ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(where) - 4, 4 * sizeof(uint16_t));
1656 static void repatchPointer(void* where, void* value)
1658 ASSERT(!(reinterpret_cast<intptr_t>(where) & 1));
1660 setPointer(where, value);
1662 ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(where) - 4, 4 * sizeof(uint16_t));
1665 static void repatchLoadPtrToLEA(void* where)
1667 ASSERT(!(reinterpret_cast<intptr_t>(where) & 1));
1669 uint16_t* loadOp = reinterpret_cast<uint16_t*>(where) + 4;
1670 ASSERT((*loadOp & 0xfff0) == OP_LDR_reg_T2);
1672 *loadOp = OP_ADD_reg_T3 | (*loadOp & 0xf);
1673 ExecutableAllocator::cacheFlush(loadOp, sizeof(uint16_t));
1676 static void repatchLEAToLoadPtr(void* where)
1678 ASSERT(!(reinterpret_cast<intptr_t>(where) & 1));
1680 uint16_t* loadOp = reinterpret_cast<uint16_t*>(where) + 4;
1681 if ((*loadOp & 0xfff0) == OP_LDR_reg_T2)
1684 ASSERT((*loadOp & 0xfff0) == OP_ADD_reg_T3);
1686 *loadOp = OP_LDR_reg_T2 | (*loadOp & 0xf);
1687 ExecutableAllocator::cacheFlush(loadOp, sizeof(uint16_t));
1692 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
1693 // (i.e. +/-(0..255) 32-bit words)
1694 void vmem(FPRegisterID rd, RegisterID rn, int32_t imm, bool isLoad)
1706 // offset is effectively leftshifted by 2 already (the bottom two bits are zero, and not
1707 // reperesented in the instruction. Left shift by 14, to mov it into position 0x00AA0000.
1708 ASSERT((offset & ~(0xff << 2)) == 0);
1711 m_formatter.vfpOp(0x0b00ed00 | offset | (up << 7) | (isLoad << 4) | doubleRegisterMask(rd, 6, 28) | rn);
1714 static void setInt32(void* code, uint32_t value)
1716 uint16_t* location = reinterpret_cast<uint16_t*>(code);
1717 ASSERT(isMOV_imm_T3(location - 4) && isMOVT(location - 2));
1719 ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(value));
1720 ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(value >> 16));
1721 location[-4] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16);
1722 location[-3] = twoWordOp5i6Imm4Reg4EncodedImmSecond((location[-3] >> 8) & 0xf, lo16);
1723 location[-2] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16);
1724 location[-1] = twoWordOp5i6Imm4Reg4EncodedImmSecond((location[-1] >> 8) & 0xf, hi16);
1726 ExecutableAllocator::cacheFlush(location - 4, 4 * sizeof(uint16_t));
1729 static void setPointer(void* code, void* value)
1731 setInt32(code, reinterpret_cast<uint32_t>(value));
1734 static bool isB(void* address)
1736 uint16_t* instruction = static_cast<uint16_t*>(address);
1737 return ((instruction[0] & 0xf800) == OP_B_T4a) && ((instruction[1] & 0xd000) == OP_B_T4b);
1740 static bool isBX(void* address)
1742 uint16_t* instruction = static_cast<uint16_t*>(address);
1743 return (instruction[0] & 0xff87) == OP_BX;
1746 static bool isMOV_imm_T3(void* address)
1748 uint16_t* instruction = static_cast<uint16_t*>(address);
1749 return ((instruction[0] & 0xFBF0) == OP_MOV_imm_T3) && ((instruction[1] & 0x8000) == 0);
1752 static bool isMOVT(void* address)
1754 uint16_t* instruction = static_cast<uint16_t*>(address);
1755 return ((instruction[0] & 0xFBF0) == OP_MOVT) && ((instruction[1] & 0x8000) == 0);
1758 static bool isNOP_T1(void* address)
1760 uint16_t* instruction = static_cast<uint16_t*>(address);
1761 return instruction[0] == OP_NOP_T1;
1764 static bool isNOP_T2(void* address)
1766 uint16_t* instruction = static_cast<uint16_t*>(address);
1767 return (instruction[0] == OP_NOP_T2a) && (instruction[1] == OP_NOP_T2b);
1770 static void linkJumpAbsolute(uint16_t* instruction, void* target)
1772 // FIMXE: this should be up in the MacroAssembler layer. :-(
1773 const uint16_t JUMP_TEMPORARY_REGISTER = ARMRegisters::ip;
1775 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
1776 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
1778 ASSERT( (isMOV_imm_T3(instruction - 5) && isMOVT(instruction - 3) && isBX(instruction - 1))
1779 || (isNOP_T1(instruction - 5) && isNOP_T2(instruction - 4) && isB(instruction - 2)) );
1781 intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction));
1783 // From Cortex-A8 errata:
1784 // If the 32-bit Thumb-2 branch instruction spans two 4KiB regions and
1785 // the target of the branch falls within the first region it is
1786 // possible for the processor to incorrectly determine the branch
1787 // instruction, and it is also possible in some cases for the processor
1788 // to enter a deadlock state.
1789 // The instruction is spanning two pages if it ends at an address ending 0x002
1790 bool spansTwo4K = ((reinterpret_cast<intptr_t>(instruction) & 0xfff) == 0x002);
1791 // The target is in the first page if the jump branch back by [3..0x1002] bytes
1792 bool targetInFirstPage = (relative >= -0x1002) && (relative < -2);
1793 bool wouldTriggerA8Errata = spansTwo4K && targetInFirstPage;
1795 if (((relative << 7) >> 7) == relative && !wouldTriggerA8Errata) {
1796 // ARM encoding for the top two bits below the sign bit is 'peculiar'.
1798 relative ^= 0xC00000;
1800 // All branch offsets should be an even distance.
1801 ASSERT(!(relative & 1));
1802 // There may be a better way to fix this, but right now put the NOPs first, since in the
1803 // case of an conditional branch this will be coming after an ITTT predicating *three*
1804 // instructions! Looking backwards to modify the ITTT to an IT is not easy, due to
1805 // variable wdith encoding - the previous instruction might *look* like an ITTT but
1806 // actually be the second half of a 2-word op.
1807 instruction[-5] = OP_NOP_T1;
1808 instruction[-4] = OP_NOP_T2a;
1809 instruction[-3] = OP_NOP_T2b;
1810 instruction[-2] = OP_B_T4a | ((relative & 0x1000000) >> 14) | ((relative & 0x3ff000) >> 12);
1811 instruction[-1] = OP_B_T4b | ((relative & 0x800000) >> 10) | ((relative & 0x400000) >> 11) | ((relative & 0xffe) >> 1);
1813 ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) + 1));
1814 ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) >> 16));
1815 instruction[-5] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16);
1816 instruction[-4] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, lo16);
1817 instruction[-3] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16);
1818 instruction[-2] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, hi16);
1819 instruction[-1] = OP_BX | (JUMP_TEMPORARY_REGISTER << 3);
1823 static uint16_t twoWordOp5i6Imm4Reg4EncodedImmFirst(uint16_t op, ARMThumbImmediate imm)
1825 return op | (imm.m_value.i << 10) | imm.m_value.imm4;
1827 static uint16_t twoWordOp5i6Imm4Reg4EncodedImmSecond(uint16_t rd, ARMThumbImmediate imm)
1829 return (imm.m_value.imm3 << 12) | (rd << 8) | imm.m_value.imm8;
1832 class ARMInstructionFormatter {
1834 void oneWordOp5Reg3Imm8(OpcodeID op, RegisterID rd, uint8_t imm)
1836 m_buffer.putShort(op | (rd << 8) | imm);
1839 void oneWordOp5Imm5Reg3Reg3(OpcodeID op, uint8_t imm, RegisterID reg1, RegisterID reg2)
1841 m_buffer.putShort(op | (imm << 6) | (reg1 << 3) | reg2);
1844 void oneWordOp7Reg3Reg3Reg3(OpcodeID op, RegisterID reg1, RegisterID reg2, RegisterID reg3)
1846 m_buffer.putShort(op | (reg1 << 6) | (reg2 << 3) | reg3);
1849 void oneWordOp8Imm8(OpcodeID op, uint8_t imm)
1851 m_buffer.putShort(op | imm);
1854 void oneWordOp8RegReg143(OpcodeID op, RegisterID reg1, RegisterID reg2)
1856 m_buffer.putShort(op | ((reg2 & 8) << 4) | (reg1 << 3) | (reg2 & 7));
1858 void oneWordOp9Imm7(OpcodeID op, uint8_t imm)
1860 m_buffer.putShort(op | imm);
1863 void oneWordOp10Reg3Reg3(OpcodeID op, RegisterID reg1, RegisterID reg2)
1865 m_buffer.putShort(op | (reg1 << 3) | reg2);
1868 void twoWordOp12Reg4FourFours(OpcodeID1 op, RegisterID reg, FourFours ff)
1870 m_buffer.putShort(op | reg);
1871 m_buffer.putShort(ff.m_u.value);
1874 void twoWordOp16FourFours(OpcodeID1 op, FourFours ff)
1876 m_buffer.putShort(op);
1877 m_buffer.putShort(ff.m_u.value);
1880 void twoWordOp16Op16(OpcodeID1 op1, OpcodeID2 op2)
1882 m_buffer.putShort(op1);
1883 m_buffer.putShort(op2);
1886 void twoWordOp5i6Imm4Reg4EncodedImm(OpcodeID1 op, int imm4, RegisterID rd, ARMThumbImmediate imm)
1888 ARMThumbImmediate newImm = imm;
1889 newImm.m_value.imm4 = imm4;
1891 m_buffer.putShort(ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmFirst(op, newImm));
1892 m_buffer.putShort(ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmSecond(rd, newImm));
1895 void twoWordOp12Reg4Reg4Imm12(OpcodeID1 op, RegisterID reg1, RegisterID reg2, uint16_t imm)
1897 m_buffer.putShort(op | reg1);
1898 m_buffer.putShort((reg2 << 12) | imm);
1901 void vfpOp(int32_t op)
1903 m_buffer.putInt(op);
1907 // Administrative methods:
1909 size_t size() const { return m_buffer.size(); }
1910 bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); }
1911 void* data() const { return m_buffer.data(); }
1912 void* executableCopy(ExecutablePool* allocator) { return m_buffer.executableCopy(allocator); }
1913 bool oom() const { return m_buffer.oom(); }
1916 AssemblerBuffer m_buffer;
1919 Vector<LinkRecord> m_jumpsToLink;
1924 #endif // ENABLE(ASSEMBLER) && CPU(ARM_THUMB2)
1926 #endif // ARMAssembler_h