2 * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
3 * Copyright (C) 2010 University of Szeged
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #ifndef ARMAssembler_h
28 #define ARMAssembler_h
30 #if ENABLE(ASSEMBLER) && CPU(ARM_THUMB2)
32 #include "AssemblerBuffer.h"
33 #include <wtf/Assertions.h>
34 #include <wtf/Vector.h>
39 namespace ARMRegisters {
48 r7, wr = r7, // thumb work register
50 r9, sb = r9, // static base
51 r10, sl = r10, // stack limit
52 r11, fp = r11, // frame pointer
127 } FPDoubleRegisterID;
164 inline FPSingleRegisterID asSingle(FPDoubleRegisterID reg)
167 return (FPSingleRegisterID)(reg << 1);
170 inline FPDoubleRegisterID asDouble(FPSingleRegisterID reg)
173 return (FPDoubleRegisterID)(reg >> 1);
177 class ARMv7Assembler;
178 class ARMThumbImmediate {
179 friend class ARMv7Assembler;
181 typedef uint8_t ThumbImmediateType;
182 static const ThumbImmediateType TypeInvalid = 0;
183 static const ThumbImmediateType TypeEncoded = 1;
184 static const ThumbImmediateType TypeUInt16 = 2;
194 // If this is an encoded immediate, then it may describe a shift, or a pattern.
196 unsigned shiftValue7 : 7;
197 unsigned shiftAmount : 5;
200 unsigned immediate : 8;
201 unsigned pattern : 4;
203 } ThumbImmediateValue;
205 // byte0 contains least significant bit; not using an array to make client code endian agnostic.
216 ALWAYS_INLINE static void countLeadingZerosPartial(uint32_t& value, int32_t& zeros, const int N)
218 if (value & ~((1 << N) - 1)) /* check for any of the top N bits (of 2N bits) are set */
219 value >>= N; /* if any were set, lose the bottom N */
220 else /* if none of the top N bits are set, */
221 zeros += N; /* then we have identified N leading zeros */
224 static int32_t countLeadingZeros(uint32_t value)
230 countLeadingZerosPartial(value, zeros, 16);
231 countLeadingZerosPartial(value, zeros, 8);
232 countLeadingZerosPartial(value, zeros, 4);
233 countLeadingZerosPartial(value, zeros, 2);
234 countLeadingZerosPartial(value, zeros, 1);
239 : m_type(TypeInvalid)
244 ARMThumbImmediate(ThumbImmediateType type, ThumbImmediateValue value)
250 ARMThumbImmediate(ThumbImmediateType type, uint16_t value)
253 // Make sure this constructor is only reached with type TypeUInt16;
254 // this extra parameter makes the code a little clearer by making it
255 // explicit at call sites which type is being constructed
256 ASSERT_UNUSED(type, type == TypeUInt16);
258 m_value.asInt = value;
262 static ARMThumbImmediate makeEncodedImm(uint32_t value)
264 ThumbImmediateValue encoding;
267 // okay, these are easy.
269 encoding.immediate = value;
270 encoding.pattern = 0;
271 return ARMThumbImmediate(TypeEncoded, encoding);
274 int32_t leadingZeros = countLeadingZeros(value);
275 // if there were 24 or more leading zeros, then we'd have hit the (value < 256) case.
276 ASSERT(leadingZeros < 24);
278 // Given a number with bit fields Z:B:C, where count(Z)+count(B)+count(C) == 32,
279 // Z are the bits known zero, B is the 8-bit immediate, C are the bits to check for
280 // zero. count(B) == 8, so the count of bits to be checked is 24 - count(Z).
281 int32_t rightShiftAmount = 24 - leadingZeros;
282 if (value == ((value >> rightShiftAmount) << rightShiftAmount)) {
283 // Shift the value down to the low byte position. The assign to
284 // shiftValue7 drops the implicit top bit.
285 encoding.shiftValue7 = value >> rightShiftAmount;
286 // The endoded shift amount is the magnitude of a right rotate.
287 encoding.shiftAmount = 8 + leadingZeros;
288 return ARMThumbImmediate(TypeEncoded, encoding);
294 if ((bytes.byte0 == bytes.byte1) && (bytes.byte0 == bytes.byte2) && (bytes.byte0 == bytes.byte3)) {
295 encoding.immediate = bytes.byte0;
296 encoding.pattern = 3;
297 return ARMThumbImmediate(TypeEncoded, encoding);
300 if ((bytes.byte0 == bytes.byte2) && !(bytes.byte1 | bytes.byte3)) {
301 encoding.immediate = bytes.byte0;
302 encoding.pattern = 1;
303 return ARMThumbImmediate(TypeEncoded, encoding);
306 if ((bytes.byte1 == bytes.byte3) && !(bytes.byte0 | bytes.byte2)) {
307 encoding.immediate = bytes.byte1;
308 encoding.pattern = 2;
309 return ARMThumbImmediate(TypeEncoded, encoding);
312 return ARMThumbImmediate();
315 static ARMThumbImmediate makeUInt12(int32_t value)
317 return (!(value & 0xfffff000))
318 ? ARMThumbImmediate(TypeUInt16, (uint16_t)value)
319 : ARMThumbImmediate();
322 static ARMThumbImmediate makeUInt12OrEncodedImm(int32_t value)
324 // If this is not a 12-bit unsigned it, try making an encoded immediate.
325 return (!(value & 0xfffff000))
326 ? ARMThumbImmediate(TypeUInt16, (uint16_t)value)
327 : makeEncodedImm(value);
330 // The 'make' methods, above, return a !isValid() value if the argument
331 // cannot be represented as the requested type. This methods is called
332 // 'get' since the argument can always be represented.
333 static ARMThumbImmediate makeUInt16(uint16_t value)
335 return ARMThumbImmediate(TypeUInt16, value);
340 return m_type != TypeInvalid;
343 uint16_t asUInt16() const { return m_value.asInt; }
345 // These methods rely on the format of encoded byte values.
346 bool isUInt3() { return !(m_value.asInt & 0xfff8); }
347 bool isUInt4() { return !(m_value.asInt & 0xfff0); }
348 bool isUInt5() { return !(m_value.asInt & 0xffe0); }
349 bool isUInt6() { return !(m_value.asInt & 0xffc0); }
350 bool isUInt7() { return !(m_value.asInt & 0xff80); }
351 bool isUInt8() { return !(m_value.asInt & 0xff00); }
352 bool isUInt9() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xfe00); }
353 bool isUInt10() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xfc00); }
354 bool isUInt12() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xf000); }
355 bool isUInt16() { return m_type == TypeUInt16; }
356 uint8_t getUInt3() { ASSERT(isUInt3()); return m_value.asInt; }
357 uint8_t getUInt4() { ASSERT(isUInt4()); return m_value.asInt; }
358 uint8_t getUInt5() { ASSERT(isUInt5()); return m_value.asInt; }
359 uint8_t getUInt6() { ASSERT(isUInt6()); return m_value.asInt; }
360 uint8_t getUInt7() { ASSERT(isUInt7()); return m_value.asInt; }
361 uint8_t getUInt8() { ASSERT(isUInt8()); return m_value.asInt; }
362 uint16_t getUInt9() { ASSERT(isUInt9()); return m_value.asInt; }
363 uint16_t getUInt10() { ASSERT(isUInt10()); return m_value.asInt; }
364 uint16_t getUInt12() { ASSERT(isUInt12()); return m_value.asInt; }
365 uint16_t getUInt16() { ASSERT(isUInt16()); return m_value.asInt; }
367 bool isEncodedImm() { return m_type == TypeEncoded; }
370 ThumbImmediateType m_type;
371 ThumbImmediateValue m_value;
380 SRType_RRX = SRType_ROR
383 class ShiftTypeAndAmount {
384 friend class ARMv7Assembler;
389 m_u.type = (ARMShiftType)0;
393 ShiftTypeAndAmount(ARMShiftType type, unsigned amount)
396 m_u.amount = amount & 31;
399 unsigned lo4() { return m_u.lo4; }
400 unsigned hi4() { return m_u.hi4; }
415 class ARMv7Assembler {
419 ASSERT(m_jumpsToLink.isEmpty());
422 typedef ARMRegisters::RegisterID RegisterID;
423 typedef ARMRegisters::FPSingleRegisterID FPSingleRegisterID;
424 typedef ARMRegisters::FPDoubleRegisterID FPDoubleRegisterID;
425 typedef ARMRegisters::FPQuadRegisterID FPQuadRegisterID;
427 // (HS, LO, HI, LS) -> (AE, B, A, BE)
428 // (VS, VC) -> (O, NO)
432 ConditionHS, ConditionCS = ConditionHS,
433 ConditionLO, ConditionCC = ConditionLO,
448 #define JUMP_ENUM_WITH_SIZE(index, value) (((value) << 3) | (index))
449 #define JUMP_ENUM_SIZE(jump) ((jump) >> 3)
450 enum JumpType { JumpFixed = JUMP_ENUM_WITH_SIZE(0, 0),
451 JumpNoCondition = JUMP_ENUM_WITH_SIZE(1, 5 * sizeof(uint16_t)),
452 JumpCondition = JUMP_ENUM_WITH_SIZE(2, 6 * sizeof(uint16_t)),
453 JumpNoConditionFixedSize = JUMP_ENUM_WITH_SIZE(3, 5 * sizeof(uint16_t)),
454 JumpConditionFixedSize = JUMP_ENUM_WITH_SIZE(4, 6 * sizeof(uint16_t))
457 LinkInvalid = JUMP_ENUM_WITH_SIZE(0, 0),
458 LinkJumpT1 = JUMP_ENUM_WITH_SIZE(1, sizeof(uint16_t)),
459 LinkJumpT2 = JUMP_ENUM_WITH_SIZE(2, sizeof(uint16_t)),
460 LinkJumpT3 = JUMP_ENUM_WITH_SIZE(3, 2 * sizeof(uint16_t)),
461 LinkJumpT4 = JUMP_ENUM_WITH_SIZE(4, 2 * sizeof(uint16_t)),
462 LinkConditionalJumpT4 = JUMP_ENUM_WITH_SIZE(5, 3 * sizeof(uint16_t)),
463 LinkBX = JUMP_ENUM_WITH_SIZE(6, 5 * sizeof(uint16_t)),
464 LinkConditionalBX = JUMP_ENUM_WITH_SIZE(7, 6 * sizeof(uint16_t))
469 LinkRecord(intptr_t from, intptr_t to, JumpType type, Condition condition)
473 , m_linkType(LinkInvalid)
474 , m_condition(condition)
477 intptr_t from() const { return m_from; }
478 void setFrom(intptr_t from) { m_from = from; }
479 intptr_t to() const { return m_to; }
480 JumpType type() const { return m_type; }
481 JumpLinkType linkType() const { return m_linkType; }
482 void setLinkType(JumpLinkType linkType) { ASSERT(m_linkType == LinkInvalid); m_linkType = linkType; }
483 Condition condition() const { return m_condition; }
485 intptr_t m_from : 31;
488 JumpLinkType m_linkType : 8;
489 Condition m_condition : 16;
495 bool BadReg(RegisterID reg)
497 return (reg == ARMRegisters::sp) || (reg == ARMRegisters::pc);
500 uint32_t singleRegisterMask(FPSingleRegisterID rdNum, int highBitsShift, int lowBitShift)
502 uint32_t rdMask = (rdNum >> 1) << highBitsShift;
504 rdMask |= 1 << lowBitShift;
508 uint32_t doubleRegisterMask(FPDoubleRegisterID rdNum, int highBitShift, int lowBitsShift)
510 uint32_t rdMask = (rdNum & 0xf) << lowBitsShift;
512 rdMask |= 1 << highBitShift;
517 OP_ADD_reg_T1 = 0x1800,
518 OP_SUB_reg_T1 = 0x1A00,
519 OP_ADD_imm_T1 = 0x1C00,
520 OP_SUB_imm_T1 = 0x1E00,
521 OP_MOV_imm_T1 = 0x2000,
522 OP_CMP_imm_T1 = 0x2800,
523 OP_ADD_imm_T2 = 0x3000,
524 OP_SUB_imm_T2 = 0x3800,
525 OP_AND_reg_T1 = 0x4000,
526 OP_EOR_reg_T1 = 0x4040,
527 OP_TST_reg_T1 = 0x4200,
528 OP_RSB_imm_T1 = 0x4240,
529 OP_CMP_reg_T1 = 0x4280,
530 OP_ORR_reg_T1 = 0x4300,
531 OP_MVN_reg_T1 = 0x43C0,
532 OP_ADD_reg_T2 = 0x4400,
533 OP_MOV_reg_T1 = 0x4600,
536 OP_STR_reg_T1 = 0x5000,
537 OP_LDR_reg_T1 = 0x5800,
538 OP_LDRH_reg_T1 = 0x5A00,
539 OP_LDRB_reg_T1 = 0x5C00,
540 OP_STR_imm_T1 = 0x6000,
541 OP_LDR_imm_T1 = 0x6800,
542 OP_LDRB_imm_T1 = 0x7800,
543 OP_LDRH_imm_T1 = 0x8800,
544 OP_STR_imm_T2 = 0x9000,
545 OP_LDR_imm_T2 = 0x9800,
546 OP_ADD_SP_imm_T1 = 0xA800,
547 OP_ADD_SP_imm_T2 = 0xB000,
548 OP_SUB_SP_imm_T1 = 0xB080,
557 OP_AND_reg_T2 = 0xEA00,
558 OP_TST_reg_T2 = 0xEA10,
559 OP_ORR_reg_T2 = 0xEA40,
560 OP_ORR_S_reg_T2 = 0xEA50,
561 OP_ASR_imm_T1 = 0xEA4F,
562 OP_LSL_imm_T1 = 0xEA4F,
563 OP_LSR_imm_T1 = 0xEA4F,
564 OP_ROR_imm_T1 = 0xEA4F,
565 OP_MVN_reg_T2 = 0xEA6F,
566 OP_EOR_reg_T2 = 0xEA80,
567 OP_ADD_reg_T3 = 0xEB00,
568 OP_ADD_S_reg_T3 = 0xEB10,
569 OP_SUB_reg_T2 = 0xEBA0,
570 OP_SUB_S_reg_T2 = 0xEBB0,
571 OP_CMP_reg_T2 = 0xEBB0,
574 OP_VMOV_StoC = 0xEE00,
575 OP_VMOV_CtoS = 0xEE10,
581 OP_VCVT_FPIVFP = 0xEEB0,
582 OP_VMOV_IMM_T2 = 0xEEB0,
586 OP_AND_imm_T1 = 0xF000,
588 OP_ORR_imm_T1 = 0xF040,
589 OP_MOV_imm_T2 = 0xF040,
591 OP_EOR_imm_T1 = 0xF080,
592 OP_ADD_imm_T3 = 0xF100,
593 OP_ADD_S_imm_T3 = 0xF110,
595 OP_SUB_imm_T3 = 0xF1A0,
596 OP_SUB_S_imm_T3 = 0xF1B0,
597 OP_CMP_imm_T2 = 0xF1B0,
598 OP_RSB_imm_T2 = 0xF1C0,
599 OP_ADD_imm_T4 = 0xF200,
600 OP_MOV_imm_T3 = 0xF240,
601 OP_SUB_imm_T4 = 0xF2A0,
605 OP_LDRB_imm_T3 = 0xF810,
606 OP_LDRB_reg_T2 = 0xF810,
607 OP_LDRH_reg_T2 = 0xF830,
608 OP_LDRH_imm_T3 = 0xF830,
609 OP_STR_imm_T4 = 0xF840,
610 OP_STR_reg_T2 = 0xF840,
611 OP_LDR_imm_T4 = 0xF850,
612 OP_LDR_reg_T2 = 0xF850,
613 OP_LDRB_imm_T2 = 0xF890,
614 OP_LDRH_imm_T2 = 0xF8B0,
615 OP_STR_imm_T3 = 0xF8C0,
616 OP_LDR_imm_T3 = 0xF8D0,
617 OP_LSL_reg_T2 = 0xFA00,
618 OP_LSR_reg_T2 = 0xFA20,
619 OP_ASR_reg_T2 = 0xFA40,
620 OP_ROR_reg_T2 = 0xFA60,
622 OP_SMULL_T1 = 0xFB80,
626 OP_VADD_T2b = 0x0A00,
629 OP_VMOV_IMM_T2b = 0x0A00,
630 OP_VMUL_T2b = 0x0A00,
632 OP_VMOV_CtoSb = 0x0A10,
633 OP_VMOV_StoCb = 0x0A10,
636 OP_VCVT_FPIVFPb = 0x0A40,
637 OP_VSUB_T2b = 0x0A40,
644 FourFours(unsigned f3, unsigned f2, unsigned f1, unsigned f0)
663 class ARMInstructionFormatter;
666 bool ifThenElseConditionBit(Condition condition, bool isIf)
668 return isIf ? (condition & 1) : !(condition & 1);
670 uint8_t ifThenElse(Condition condition, bool inst2if, bool inst3if, bool inst4if)
672 int mask = (ifThenElseConditionBit(condition, inst2if) << 3)
673 | (ifThenElseConditionBit(condition, inst3if) << 2)
674 | (ifThenElseConditionBit(condition, inst4if) << 1)
676 ASSERT((condition != ConditionAL) || !(mask & (mask - 1)));
677 return (condition << 4) | mask;
679 uint8_t ifThenElse(Condition condition, bool inst2if, bool inst3if)
681 int mask = (ifThenElseConditionBit(condition, inst2if) << 3)
682 | (ifThenElseConditionBit(condition, inst3if) << 2)
684 ASSERT((condition != ConditionAL) || !(mask & (mask - 1)));
685 return (condition << 4) | mask;
687 uint8_t ifThenElse(Condition condition, bool inst2if)
689 int mask = (ifThenElseConditionBit(condition, inst2if) << 3)
691 ASSERT((condition != ConditionAL) || !(mask & (mask - 1)));
692 return (condition << 4) | mask;
695 uint8_t ifThenElse(Condition condition)
698 return (condition << 4) | mask;
703 void add(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
705 // Rd can only be SP if Rn is also SP.
706 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
707 ASSERT(rd != ARMRegisters::pc);
708 ASSERT(rn != ARMRegisters::pc);
709 ASSERT(imm.isValid());
711 if (rn == ARMRegisters::sp) {
712 if (!(rd & 8) && imm.isUInt10()) {
713 m_formatter.oneWordOp5Reg3Imm8(OP_ADD_SP_imm_T1, rd, static_cast<uint8_t>(imm.getUInt10() >> 2));
715 } else if ((rd == ARMRegisters::sp) && imm.isUInt9()) {
716 m_formatter.oneWordOp9Imm7(OP_ADD_SP_imm_T2, static_cast<uint8_t>(imm.getUInt9() >> 2));
719 } else if (!((rd | rn) & 8)) {
721 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_imm_T1, (RegisterID)imm.getUInt3(), rn, rd);
723 } else if ((rd == rn) && imm.isUInt8()) {
724 m_formatter.oneWordOp5Reg3Imm8(OP_ADD_imm_T2, rd, imm.getUInt8());
729 if (imm.isEncodedImm())
730 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T3, rn, rd, imm);
732 ASSERT(imm.isUInt12());
733 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T4, rn, rd, imm);
737 ALWAYS_INLINE void add(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
739 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
740 ASSERT(rd != ARMRegisters::pc);
741 ASSERT(rn != ARMRegisters::pc);
743 m_formatter.twoWordOp12Reg4FourFours(OP_ADD_reg_T3, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
746 // NOTE: In an IT block, add doesn't modify the flags register.
747 ALWAYS_INLINE void add(RegisterID rd, RegisterID rn, RegisterID rm)
750 m_formatter.oneWordOp8RegReg143(OP_ADD_reg_T2, rm, rd);
752 m_formatter.oneWordOp8RegReg143(OP_ADD_reg_T2, rn, rd);
753 else if (!((rd | rn | rm) & 8))
754 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_reg_T1, rm, rn, rd);
756 add(rd, rn, rm, ShiftTypeAndAmount());
759 // Not allowed in an IT (if then) block.
760 ALWAYS_INLINE void add_S(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
762 // Rd can only be SP if Rn is also SP.
763 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
764 ASSERT(rd != ARMRegisters::pc);
765 ASSERT(rn != ARMRegisters::pc);
766 ASSERT(imm.isEncodedImm());
768 if (!((rd | rn) & 8)) {
770 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_imm_T1, (RegisterID)imm.getUInt3(), rn, rd);
772 } else if ((rd == rn) && imm.isUInt8()) {
773 m_formatter.oneWordOp5Reg3Imm8(OP_ADD_imm_T2, rd, imm.getUInt8());
778 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_S_imm_T3, rn, rd, imm);
781 // Not allowed in an IT (if then) block?
782 ALWAYS_INLINE void add_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
784 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
785 ASSERT(rd != ARMRegisters::pc);
786 ASSERT(rn != ARMRegisters::pc);
788 m_formatter.twoWordOp12Reg4FourFours(OP_ADD_S_reg_T3, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
791 // Not allowed in an IT (if then) block.
792 ALWAYS_INLINE void add_S(RegisterID rd, RegisterID rn, RegisterID rm)
794 if (!((rd | rn | rm) & 8))
795 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_reg_T1, rm, rn, rd);
797 add_S(rd, rn, rm, ShiftTypeAndAmount());
800 ALWAYS_INLINE void ARM_and(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
804 ASSERT(imm.isEncodedImm());
805 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_AND_imm_T1, rn, rd, imm);
808 ALWAYS_INLINE void ARM_and(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
813 m_formatter.twoWordOp12Reg4FourFours(OP_AND_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
816 ALWAYS_INLINE void ARM_and(RegisterID rd, RegisterID rn, RegisterID rm)
818 if ((rd == rn) && !((rd | rm) & 8))
819 m_formatter.oneWordOp10Reg3Reg3(OP_AND_reg_T1, rm, rd);
820 else if ((rd == rm) && !((rd | rn) & 8))
821 m_formatter.oneWordOp10Reg3Reg3(OP_AND_reg_T1, rn, rd);
823 ARM_and(rd, rn, rm, ShiftTypeAndAmount());
826 ALWAYS_INLINE void asr(RegisterID rd, RegisterID rm, int32_t shiftAmount)
830 ShiftTypeAndAmount shift(SRType_ASR, shiftAmount);
831 m_formatter.twoWordOp16FourFours(OP_ASR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
834 ALWAYS_INLINE void asr(RegisterID rd, RegisterID rn, RegisterID rm)
839 m_formatter.twoWordOp12Reg4FourFours(OP_ASR_reg_T2, rn, FourFours(0xf, rd, 0, rm));
842 // Only allowed in IT (if then) block if last instruction.
843 ALWAYS_INLINE AssemblerLabel b()
845 m_formatter.twoWordOp16Op16(OP_B_T4a, OP_B_T4b);
846 return m_formatter.label();
849 // Only allowed in IT (if then) block if last instruction.
850 ALWAYS_INLINE AssemblerLabel blx(RegisterID rm)
852 ASSERT(rm != ARMRegisters::pc);
853 m_formatter.oneWordOp8RegReg143(OP_BLX, rm, (RegisterID)8);
854 return m_formatter.label();
857 // Only allowed in IT (if then) block if last instruction.
858 ALWAYS_INLINE AssemblerLabel bx(RegisterID rm)
860 m_formatter.oneWordOp8RegReg143(OP_BX, rm, (RegisterID)0);
861 return m_formatter.label();
864 void bkpt(uint8_t imm=0)
866 m_formatter.oneWordOp8Imm8(OP_BKPT, imm);
869 ALWAYS_INLINE void clz(RegisterID rd, RegisterID rm)
873 m_formatter.twoWordOp12Reg4FourFours(OP_CLZ, rm, FourFours(0xf, rd, 8, rm));
876 ALWAYS_INLINE void cmn(RegisterID rn, ARMThumbImmediate imm)
878 ASSERT(rn != ARMRegisters::pc);
879 ASSERT(imm.isEncodedImm());
881 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMN_imm, rn, (RegisterID)0xf, imm);
884 ALWAYS_INLINE void cmp(RegisterID rn, ARMThumbImmediate imm)
886 ASSERT(rn != ARMRegisters::pc);
887 ASSERT(imm.isEncodedImm());
889 if (!(rn & 8) && imm.isUInt8())
890 m_formatter.oneWordOp5Reg3Imm8(OP_CMP_imm_T1, rn, imm.getUInt8());
892 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMP_imm_T2, rn, (RegisterID)0xf, imm);
895 ALWAYS_INLINE void cmp(RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
897 ASSERT(rn != ARMRegisters::pc);
899 m_formatter.twoWordOp12Reg4FourFours(OP_CMP_reg_T2, rn, FourFours(shift.hi4(), 0xf, shift.lo4(), rm));
902 ALWAYS_INLINE void cmp(RegisterID rn, RegisterID rm)
905 cmp(rn, rm, ShiftTypeAndAmount());
907 m_formatter.oneWordOp10Reg3Reg3(OP_CMP_reg_T1, rm, rn);
910 // xor is not spelled with an 'e'. :-(
911 ALWAYS_INLINE void eor(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
915 ASSERT(imm.isEncodedImm());
916 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_EOR_imm_T1, rn, rd, imm);
919 // xor is not spelled with an 'e'. :-(
920 ALWAYS_INLINE void eor(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
925 m_formatter.twoWordOp12Reg4FourFours(OP_EOR_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
928 // xor is not spelled with an 'e'. :-(
929 void eor(RegisterID rd, RegisterID rn, RegisterID rm)
931 if ((rd == rn) && !((rd | rm) & 8))
932 m_formatter.oneWordOp10Reg3Reg3(OP_EOR_reg_T1, rm, rd);
933 else if ((rd == rm) && !((rd | rn) & 8))
934 m_formatter.oneWordOp10Reg3Reg3(OP_EOR_reg_T1, rn, rd);
936 eor(rd, rn, rm, ShiftTypeAndAmount());
939 ALWAYS_INLINE void it(Condition cond)
941 m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond));
944 ALWAYS_INLINE void it(Condition cond, bool inst2if)
946 m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if));
949 ALWAYS_INLINE void it(Condition cond, bool inst2if, bool inst3if)
951 m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if, inst3if));
954 ALWAYS_INLINE void it(Condition cond, bool inst2if, bool inst3if, bool inst4if)
956 m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if, inst3if, inst4if));
959 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
960 ALWAYS_INLINE void ldr(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
962 ASSERT(rn != ARMRegisters::pc); // LDR (literal)
963 ASSERT(imm.isUInt12());
965 if (!((rt | rn) & 8) && imm.isUInt7())
966 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDR_imm_T1, imm.getUInt7() >> 2, rn, rt);
967 else if ((rn == ARMRegisters::sp) && !(rt & 8) && imm.isUInt10())
968 m_formatter.oneWordOp5Reg3Imm8(OP_LDR_imm_T2, rt, static_cast<uint8_t>(imm.getUInt10() >> 2));
970 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T3, rn, rt, imm.getUInt12());
973 ALWAYS_INLINE void ldrCompact(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
975 ASSERT(rn != ARMRegisters::pc); // LDR (literal)
976 ASSERT(imm.isUInt7());
977 ASSERT(!((rt | rn) & 8));
978 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDR_imm_T1, imm.getUInt7() >> 2, rn, rt);
981 // If index is set, this is a regular offset or a pre-indexed load;
982 // if index is not set then is is a post-index load.
984 // If wback is set rn is updated - this is a pre or post index load,
985 // if wback is not set this is a regular offset memory access.
987 // (-255 <= offset <= 255)
989 // _tmp = _reg + offset
990 // MEM[index ? _tmp : _reg] = REG[rt]
991 // if (wback) REG[rn] = _tmp
992 ALWAYS_INLINE void ldr(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
994 ASSERT(rt != ARMRegisters::pc);
995 ASSERT(rn != ARMRegisters::pc);
996 ASSERT(index || wback);
997 ASSERT(!wback | (rt != rn));
1004 ASSERT((offset & ~0xff) == 0);
1006 offset |= (wback << 8);
1007 offset |= (add << 9);
1008 offset |= (index << 10);
1009 offset |= (1 << 11);
1011 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T4, rn, rt, offset);
1014 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1015 ALWAYS_INLINE void ldr(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0)
1017 ASSERT(rn != ARMRegisters::pc); // LDR (literal)
1018 ASSERT(!BadReg(rm));
1021 if (!shift && !((rt | rn | rm) & 8))
1022 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDR_reg_T1, rm, rn, rt);
1024 m_formatter.twoWordOp12Reg4FourFours(OP_LDR_reg_T2, rn, FourFours(rt, 0, shift, rm));
1027 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1028 ALWAYS_INLINE void ldrh(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
1030 ASSERT(rn != ARMRegisters::pc); // LDR (literal)
1031 ASSERT(imm.isUInt12());
1033 if (!((rt | rn) & 8) && imm.isUInt6())
1034 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDRH_imm_T1, imm.getUInt6() >> 2, rn, rt);
1036 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T2, rn, rt, imm.getUInt12());
1039 // If index is set, this is a regular offset or a pre-indexed load;
1040 // if index is not set then is is a post-index load.
1042 // If wback is set rn is updated - this is a pre or post index load,
1043 // if wback is not set this is a regular offset memory access.
1045 // (-255 <= offset <= 255)
1047 // _tmp = _reg + offset
1048 // MEM[index ? _tmp : _reg] = REG[rt]
1049 // if (wback) REG[rn] = _tmp
1050 ALWAYS_INLINE void ldrh(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
1052 ASSERT(rt != ARMRegisters::pc);
1053 ASSERT(rn != ARMRegisters::pc);
1054 ASSERT(index || wback);
1055 ASSERT(!wback | (rt != rn));
1062 ASSERT((offset & ~0xff) == 0);
1064 offset |= (wback << 8);
1065 offset |= (add << 9);
1066 offset |= (index << 10);
1067 offset |= (1 << 11);
1069 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T3, rn, rt, offset);
1072 ALWAYS_INLINE void ldrh(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0)
1074 ASSERT(!BadReg(rt)); // Memory hint
1075 ASSERT(rn != ARMRegisters::pc); // LDRH (literal)
1076 ASSERT(!BadReg(rm));
1079 if (!shift && !((rt | rn | rm) & 8))
1080 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDRH_reg_T1, rm, rn, rt);
1082 m_formatter.twoWordOp12Reg4FourFours(OP_LDRH_reg_T2, rn, FourFours(rt, 0, shift, rm));
1085 void ldrb(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
1087 ASSERT(rn != ARMRegisters::pc); // LDR (literal)
1088 ASSERT(imm.isUInt12());
1090 if (!((rt | rn) & 8) && imm.isUInt5())
1091 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDRB_imm_T1, imm.getUInt5(), rn, rt);
1093 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRB_imm_T2, rn, rt, imm.getUInt12());
1096 void ldrb(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
1098 ASSERT(rt != ARMRegisters::pc);
1099 ASSERT(rn != ARMRegisters::pc);
1100 ASSERT(index || wback);
1101 ASSERT(!wback | (rt != rn));
1109 ASSERT(!(offset & ~0xff));
1111 offset |= (wback << 8);
1112 offset |= (add << 9);
1113 offset |= (index << 10);
1114 offset |= (1 << 11);
1116 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRB_imm_T3, rn, rt, offset);
1119 ALWAYS_INLINE void ldrb(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0)
1121 ASSERT(rn != ARMRegisters::pc); // LDR (literal)
1122 ASSERT(!BadReg(rm));
1125 if (!shift && !((rt | rn | rm) & 8))
1126 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDRB_reg_T1, rm, rn, rt);
1128 m_formatter.twoWordOp12Reg4FourFours(OP_LDRB_reg_T2, rn, FourFours(rt, 0, shift, rm));
1131 void lsl(RegisterID rd, RegisterID rm, int32_t shiftAmount)
1133 ASSERT(!BadReg(rd));
1134 ASSERT(!BadReg(rm));
1135 ShiftTypeAndAmount shift(SRType_LSL, shiftAmount);
1136 m_formatter.twoWordOp16FourFours(OP_LSL_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1139 ALWAYS_INLINE void lsl(RegisterID rd, RegisterID rn, RegisterID rm)
1141 ASSERT(!BadReg(rd));
1142 ASSERT(!BadReg(rn));
1143 ASSERT(!BadReg(rm));
1144 m_formatter.twoWordOp12Reg4FourFours(OP_LSL_reg_T2, rn, FourFours(0xf, rd, 0, rm));
1147 ALWAYS_INLINE void lsr(RegisterID rd, RegisterID rm, int32_t shiftAmount)
1149 ASSERT(!BadReg(rd));
1150 ASSERT(!BadReg(rm));
1151 ShiftTypeAndAmount shift(SRType_LSR, shiftAmount);
1152 m_formatter.twoWordOp16FourFours(OP_LSR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1155 ALWAYS_INLINE void lsr(RegisterID rd, RegisterID rn, RegisterID rm)
1157 ASSERT(!BadReg(rd));
1158 ASSERT(!BadReg(rn));
1159 ASSERT(!BadReg(rm));
1160 m_formatter.twoWordOp12Reg4FourFours(OP_LSR_reg_T2, rn, FourFours(0xf, rd, 0, rm));
1163 ALWAYS_INLINE void movT3(RegisterID rd, ARMThumbImmediate imm)
1165 ASSERT(imm.isValid());
1166 ASSERT(!imm.isEncodedImm());
1167 ASSERT(!BadReg(rd));
1169 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T3, imm.m_value.imm4, rd, imm);
1172 ALWAYS_INLINE void mov(RegisterID rd, ARMThumbImmediate imm)
1174 ASSERT(imm.isValid());
1175 ASSERT(!BadReg(rd));
1177 if ((rd < 8) && imm.isUInt8())
1178 m_formatter.oneWordOp5Reg3Imm8(OP_MOV_imm_T1, rd, imm.getUInt8());
1179 else if (imm.isEncodedImm())
1180 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T2, 0xf, rd, imm);
1185 ALWAYS_INLINE void mov(RegisterID rd, RegisterID rm)
1187 m_formatter.oneWordOp8RegReg143(OP_MOV_reg_T1, rm, rd);
1190 ALWAYS_INLINE void movt(RegisterID rd, ARMThumbImmediate imm)
1192 ASSERT(imm.isUInt16());
1193 ASSERT(!BadReg(rd));
1194 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOVT, imm.m_value.imm4, rd, imm);
1197 ALWAYS_INLINE void mvn(RegisterID rd, ARMThumbImmediate imm)
1199 ASSERT(imm.isEncodedImm());
1200 ASSERT(!BadReg(rd));
1202 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MVN_imm, 0xf, rd, imm);
1205 ALWAYS_INLINE void mvn(RegisterID rd, RegisterID rm, ShiftTypeAndAmount shift)
1207 ASSERT(!BadReg(rd));
1208 ASSERT(!BadReg(rm));
1209 m_formatter.twoWordOp16FourFours(OP_MVN_reg_T2, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1212 ALWAYS_INLINE void mvn(RegisterID rd, RegisterID rm)
1214 if (!((rd | rm) & 8))
1215 m_formatter.oneWordOp10Reg3Reg3(OP_MVN_reg_T1, rm, rd);
1217 mvn(rd, rm, ShiftTypeAndAmount());
1220 ALWAYS_INLINE void neg(RegisterID rd, RegisterID rm)
1222 ARMThumbImmediate zero = ARMThumbImmediate::makeUInt12(0);
1226 ALWAYS_INLINE void orr(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
1228 ASSERT(!BadReg(rd));
1229 ASSERT(!BadReg(rn));
1230 ASSERT(imm.isEncodedImm());
1231 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ORR_imm_T1, rn, rd, imm);
1234 ALWAYS_INLINE void orr(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
1236 ASSERT(!BadReg(rd));
1237 ASSERT(!BadReg(rn));
1238 ASSERT(!BadReg(rm));
1239 m_formatter.twoWordOp12Reg4FourFours(OP_ORR_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1242 void orr(RegisterID rd, RegisterID rn, RegisterID rm)
1244 if ((rd == rn) && !((rd | rm) & 8))
1245 m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rm, rd);
1246 else if ((rd == rm) && !((rd | rn) & 8))
1247 m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rn, rd);
1249 orr(rd, rn, rm, ShiftTypeAndAmount());
1252 ALWAYS_INLINE void orr_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
1254 ASSERT(!BadReg(rd));
1255 ASSERT(!BadReg(rn));
1256 ASSERT(!BadReg(rm));
1257 m_formatter.twoWordOp12Reg4FourFours(OP_ORR_S_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1260 void orr_S(RegisterID rd, RegisterID rn, RegisterID rm)
1262 if ((rd == rn) && !((rd | rm) & 8))
1263 m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rm, rd);
1264 else if ((rd == rm) && !((rd | rn) & 8))
1265 m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rn, rd);
1267 orr_S(rd, rn, rm, ShiftTypeAndAmount());
1270 ALWAYS_INLINE void ror(RegisterID rd, RegisterID rm, int32_t shiftAmount)
1272 ASSERT(!BadReg(rd));
1273 ASSERT(!BadReg(rm));
1274 ShiftTypeAndAmount shift(SRType_ROR, shiftAmount);
1275 m_formatter.twoWordOp16FourFours(OP_ROR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1278 ALWAYS_INLINE void ror(RegisterID rd, RegisterID rn, RegisterID rm)
1280 ASSERT(!BadReg(rd));
1281 ASSERT(!BadReg(rn));
1282 ASSERT(!BadReg(rm));
1283 m_formatter.twoWordOp12Reg4FourFours(OP_ROR_reg_T2, rn, FourFours(0xf, rd, 0, rm));
1286 ALWAYS_INLINE void smull(RegisterID rdLo, RegisterID rdHi, RegisterID rn, RegisterID rm)
1288 ASSERT(!BadReg(rdLo));
1289 ASSERT(!BadReg(rdHi));
1290 ASSERT(!BadReg(rn));
1291 ASSERT(!BadReg(rm));
1292 ASSERT(rdLo != rdHi);
1293 m_formatter.twoWordOp12Reg4FourFours(OP_SMULL_T1, rn, FourFours(rdLo, rdHi, 0, rm));
1296 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1297 ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
1299 ASSERT(rt != ARMRegisters::pc);
1300 ASSERT(rn != ARMRegisters::pc);
1301 ASSERT(imm.isUInt12());
1303 if (!((rt | rn) & 8) && imm.isUInt7())
1304 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_STR_imm_T1, imm.getUInt7() >> 2, rn, rt);
1305 else if ((rn == ARMRegisters::sp) && !(rt & 8) && imm.isUInt10())
1306 m_formatter.oneWordOp5Reg3Imm8(OP_STR_imm_T2, rt, static_cast<uint8_t>(imm.getUInt10() >> 2));
1308 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T3, rn, rt, imm.getUInt12());
1311 // If index is set, this is a regular offset or a pre-indexed store;
1312 // if index is not set then is is a post-index store.
1314 // If wback is set rn is updated - this is a pre or post index store,
1315 // if wback is not set this is a regular offset memory access.
1317 // (-255 <= offset <= 255)
1319 // _tmp = _reg + offset
1320 // MEM[index ? _tmp : _reg] = REG[rt]
1321 // if (wback) REG[rn] = _tmp
1322 ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
1324 ASSERT(rt != ARMRegisters::pc);
1325 ASSERT(rn != ARMRegisters::pc);
1326 ASSERT(index || wback);
1327 ASSERT(!wback | (rt != rn));
1334 ASSERT((offset & ~0xff) == 0);
1336 offset |= (wback << 8);
1337 offset |= (add << 9);
1338 offset |= (index << 10);
1339 offset |= (1 << 11);
1341 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T4, rn, rt, offset);
1344 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1345 ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0)
1347 ASSERT(rn != ARMRegisters::pc);
1348 ASSERT(!BadReg(rm));
1351 if (!shift && !((rt | rn | rm) & 8))
1352 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_STR_reg_T1, rm, rn, rt);
1354 m_formatter.twoWordOp12Reg4FourFours(OP_STR_reg_T2, rn, FourFours(rt, 0, shift, rm));
1357 ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
1359 // Rd can only be SP if Rn is also SP.
1360 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
1361 ASSERT(rd != ARMRegisters::pc);
1362 ASSERT(rn != ARMRegisters::pc);
1363 ASSERT(imm.isValid());
1365 if ((rn == ARMRegisters::sp) && (rd == ARMRegisters::sp) && imm.isUInt9()) {
1366 m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, static_cast<uint8_t>(imm.getUInt9() >> 2));
1368 } else if (!((rd | rn) & 8)) {
1369 if (imm.isUInt3()) {
1370 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_imm_T1, (RegisterID)imm.getUInt3(), rn, rd);
1372 } else if ((rd == rn) && imm.isUInt8()) {
1373 m_formatter.oneWordOp5Reg3Imm8(OP_SUB_imm_T2, rd, imm.getUInt8());
1378 if (imm.isEncodedImm())
1379 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T3, rn, rd, imm);
1381 ASSERT(imm.isUInt12());
1382 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T4, rn, rd, imm);
1386 ALWAYS_INLINE void sub(RegisterID rd, ARMThumbImmediate imm, RegisterID rn)
1388 ASSERT(rd != ARMRegisters::pc);
1389 ASSERT(rn != ARMRegisters::pc);
1390 ASSERT(imm.isValid());
1391 ASSERT(imm.isUInt12());
1393 if (!((rd | rn) & 8) && !imm.getUInt12())
1394 m_formatter.oneWordOp10Reg3Reg3(OP_RSB_imm_T1, rn, rd);
1396 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_RSB_imm_T2, rn, rd, imm);
1399 ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
1401 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
1402 ASSERT(rd != ARMRegisters::pc);
1403 ASSERT(rn != ARMRegisters::pc);
1404 ASSERT(!BadReg(rm));
1405 m_formatter.twoWordOp12Reg4FourFours(OP_SUB_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1408 // NOTE: In an IT block, add doesn't modify the flags register.
1409 ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, RegisterID rm)
1411 if (!((rd | rn | rm) & 8))
1412 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_reg_T1, rm, rn, rd);
1414 sub(rd, rn, rm, ShiftTypeAndAmount());
1417 // Not allowed in an IT (if then) block.
1418 void sub_S(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
1420 // Rd can only be SP if Rn is also SP.
1421 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
1422 ASSERT(rd != ARMRegisters::pc);
1423 ASSERT(rn != ARMRegisters::pc);
1424 ASSERT(imm.isValid());
1426 if ((rn == ARMRegisters::sp) && (rd == ARMRegisters::sp) && imm.isUInt9()) {
1427 m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, static_cast<uint8_t>(imm.getUInt9() >> 2));
1429 } else if (!((rd | rn) & 8)) {
1430 if (imm.isUInt3()) {
1431 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_imm_T1, (RegisterID)imm.getUInt3(), rn, rd);
1433 } else if ((rd == rn) && imm.isUInt8()) {
1434 m_formatter.oneWordOp5Reg3Imm8(OP_SUB_imm_T2, rd, imm.getUInt8());
1439 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_S_imm_T3, rn, rd, imm);
1442 // Not allowed in an IT (if then) block?
1443 ALWAYS_INLINE void sub_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
1445 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
1446 ASSERT(rd != ARMRegisters::pc);
1447 ASSERT(rn != ARMRegisters::pc);
1448 ASSERT(!BadReg(rm));
1449 m_formatter.twoWordOp12Reg4FourFours(OP_SUB_S_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
1452 // Not allowed in an IT (if then) block.
1453 ALWAYS_INLINE void sub_S(RegisterID rd, RegisterID rn, RegisterID rm)
1455 if (!((rd | rn | rm) & 8))
1456 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_reg_T1, rm, rn, rd);
1458 sub_S(rd, rn, rm, ShiftTypeAndAmount());
1461 ALWAYS_INLINE void tst(RegisterID rn, ARMThumbImmediate imm)
1463 ASSERT(!BadReg(rn));
1464 ASSERT(imm.isEncodedImm());
1466 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_TST_imm, rn, (RegisterID)0xf, imm);
1469 ALWAYS_INLINE void tst(RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
1471 ASSERT(!BadReg(rn));
1472 ASSERT(!BadReg(rm));
1473 m_formatter.twoWordOp12Reg4FourFours(OP_TST_reg_T2, rn, FourFours(shift.hi4(), 0xf, shift.lo4(), rm));
1476 ALWAYS_INLINE void tst(RegisterID rn, RegisterID rm)
1479 tst(rn, rm, ShiftTypeAndAmount());
1481 m_formatter.oneWordOp10Reg3Reg3(OP_TST_reg_T1, rm, rn);
1484 ALWAYS_INLINE void ubfx(RegisterID rd, RegisterID rn, unsigned lsb, unsigned width)
1487 ASSERT((width >= 1) && (width <= 32));
1488 ASSERT((lsb + width) <= 32);
1489 m_formatter.twoWordOp12Reg40Imm3Reg4Imm20Imm5(OP_UBFX_T1, rd, rn, (lsb & 0x1c) << 10, (lsb & 0x3) << 6, (width - 1) & 0x1f);
1492 void vadd_F64(FPDoubleRegisterID rd, FPDoubleRegisterID rn, FPDoubleRegisterID rm)
1494 m_formatter.vfpOp(OP_VADD_T2, OP_VADD_T2b, true, rn, rd, rm);
1497 void vcmp_F64(FPDoubleRegisterID rd, FPDoubleRegisterID rm)
1499 m_formatter.vfpOp(OP_VCMP, OP_VCMPb, true, VFPOperand(4), rd, rm);
1502 void vcmpz_F64(FPDoubleRegisterID rd)
1504 m_formatter.vfpOp(OP_VCMP, OP_VCMPb, true, VFPOperand(5), rd, VFPOperand(0));
1507 void vcvt_F64_S32(FPDoubleRegisterID rd, FPSingleRegisterID rm)
1509 // boolean values are 64bit (toInt, unsigned, roundZero)
1510 m_formatter.vfpOp(OP_VCVT_FPIVFP, OP_VCVT_FPIVFPb, true, vcvtOp(false, false, false), rd, rm);
1513 void vcvtr_S32_F64(FPSingleRegisterID rd, FPDoubleRegisterID rm)
1515 // boolean values are 64bit (toInt, unsigned, roundZero)
1516 m_formatter.vfpOp(OP_VCVT_FPIVFP, OP_VCVT_FPIVFPb, true, vcvtOp(true, false, true), rd, rm);
1519 void vdiv_F64(FPDoubleRegisterID rd, FPDoubleRegisterID rn, FPDoubleRegisterID rm)
1521 m_formatter.vfpOp(OP_VDIV, OP_VDIVb, true, rn, rd, rm);
1524 void vldr(FPDoubleRegisterID rd, RegisterID rn, int32_t imm)
1526 m_formatter.vfpMemOp(OP_VLDR, OP_VLDRb, true, rn, rd, imm);
1529 void vmov(RegisterID rd, FPSingleRegisterID rn)
1531 ASSERT(!BadReg(rd));
1532 m_formatter.vfpOp(OP_VMOV_CtoS, OP_VMOV_CtoSb, false, rn, rd, VFPOperand(0));
1535 void vmov(FPSingleRegisterID rd, RegisterID rn)
1537 ASSERT(!BadReg(rn));
1538 m_formatter.vfpOp(OP_VMOV_StoC, OP_VMOV_StoCb, false, rd, rn, VFPOperand(0));
1541 void vmrs(RegisterID reg = ARMRegisters::pc)
1543 ASSERT(reg != ARMRegisters::sp);
1544 m_formatter.vfpOp(OP_VMRS, OP_VMRSb, false, VFPOperand(1), VFPOperand(0x10 | reg), VFPOperand(0));
1547 void vmul_F64(FPDoubleRegisterID rd, FPDoubleRegisterID rn, FPDoubleRegisterID rm)
1549 m_formatter.vfpOp(OP_VMUL_T2, OP_VMUL_T2b, true, rn, rd, rm);
1552 void vstr(FPDoubleRegisterID rd, RegisterID rn, int32_t imm)
1554 m_formatter.vfpMemOp(OP_VSTR, OP_VSTRb, true, rn, rd, imm);
1557 void vsub_F64(FPDoubleRegisterID rd, FPDoubleRegisterID rn, FPDoubleRegisterID rm)
1559 m_formatter.vfpOp(OP_VSUB_T2, OP_VSUB_T2b, true, rn, rd, rm);
1564 m_formatter.oneWordOp8Imm8(OP_NOP_T1, 0);
1567 AssemblerLabel label()
1569 return m_formatter.label();
1572 AssemblerLabel align(int alignment)
1574 while (!m_formatter.isAligned(alignment))
1580 static void* getRelocatedAddress(void* code, AssemblerLabel label)
1582 ASSERT(label.isSet());
1583 return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + label.m_offset);
1586 static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b)
1588 return b.m_offset - a.m_offset;
1591 int executableOffsetFor(int location)
1595 return static_cast<int32_t*>(m_formatter.data())[location / sizeof(int32_t) - 1];
1598 int jumpSizeDelta(JumpType jumpType, JumpLinkType jumpLinkType) { return JUMP_ENUM_SIZE(jumpType) - JUMP_ENUM_SIZE(jumpLinkType); }
1600 // Assembler admin methods:
1602 static ALWAYS_INLINE bool linkRecordSourceComparator(const LinkRecord& a, const LinkRecord& b)
1604 return a.from() < b.from();
1607 bool canCompact(JumpType jumpType)
1609 // The following cannot be compacted:
1610 // JumpFixed: represents custom jump sequence
1611 // JumpNoConditionFixedSize: represents unconditional jump that must remain a fixed size
1612 // JumpConditionFixedSize: represents conditional jump that must remain a fixed size
1613 return (jumpType == JumpNoCondition) || (jumpType == JumpCondition);
1616 JumpLinkType computeJumpType(JumpType jumpType, const uint8_t* from, const uint8_t* to)
1618 if (jumpType == JumpFixed)
1621 // for patchable jump we must leave space for the longest code sequence
1622 if (jumpType == JumpNoConditionFixedSize)
1624 if (jumpType == JumpConditionFixedSize)
1625 return LinkConditionalBX;
1627 const int paddingSize = JUMP_ENUM_SIZE(jumpType);
1628 bool mayTriggerErrata = false;
1630 if (jumpType == JumpCondition) {
1631 // 2-byte conditional T1
1632 const uint16_t* jumpT1Location = reinterpret_cast<const uint16_t*>(from - (paddingSize - JUMP_ENUM_SIZE(LinkJumpT1)));
1633 if (canBeJumpT1(jumpT1Location, to))
1635 // 4-byte conditional T3
1636 const uint16_t* jumpT3Location = reinterpret_cast<const uint16_t*>(from - (paddingSize - JUMP_ENUM_SIZE(LinkJumpT3)));
1637 if (canBeJumpT3(jumpT3Location, to, mayTriggerErrata)) {
1638 if (!mayTriggerErrata)
1641 // 4-byte conditional T4 with IT
1642 const uint16_t* conditionalJumpT4Location =
1643 reinterpret_cast<const uint16_t*>(from - (paddingSize - JUMP_ENUM_SIZE(LinkConditionalJumpT4)));
1644 if (canBeJumpT4(conditionalJumpT4Location, to, mayTriggerErrata)) {
1645 if (!mayTriggerErrata)
1646 return LinkConditionalJumpT4;
1649 // 2-byte unconditional T2
1650 const uint16_t* jumpT2Location = reinterpret_cast<const uint16_t*>(from - (paddingSize - JUMP_ENUM_SIZE(LinkJumpT2)));
1651 if (canBeJumpT2(jumpT2Location, to))
1653 // 4-byte unconditional T4
1654 const uint16_t* jumpT4Location = reinterpret_cast<const uint16_t*>(from - (paddingSize - JUMP_ENUM_SIZE(LinkJumpT4)));
1655 if (canBeJumpT4(jumpT4Location, to, mayTriggerErrata)) {
1656 if (!mayTriggerErrata)
1659 // use long jump sequence
1663 ASSERT(jumpType == JumpCondition);
1664 return LinkConditionalBX;
1667 JumpLinkType computeJumpType(LinkRecord& record, const uint8_t* from, const uint8_t* to)
1669 JumpLinkType linkType = computeJumpType(record.type(), from, to);
1670 record.setLinkType(linkType);
1674 void recordLinkOffsets(int32_t regionStart, int32_t regionEnd, int32_t offset)
1676 int32_t ptr = regionStart / sizeof(int32_t);
1677 const int32_t end = regionEnd / sizeof(int32_t);
1678 int32_t* offsets = static_cast<int32_t*>(m_formatter.data());
1680 offsets[ptr++] = offset;
1683 Vector<LinkRecord>& jumpsToLink()
1685 std::sort(m_jumpsToLink.begin(), m_jumpsToLink.end(), linkRecordSourceComparator);
1686 return m_jumpsToLink;
1689 void ALWAYS_INLINE link(LinkRecord& record, uint8_t* from, uint8_t* to)
1691 switch (record.linkType()) {
1693 linkJumpT1(record.condition(), reinterpret_cast<uint16_t*>(from), to);
1696 linkJumpT2(reinterpret_cast<uint16_t*>(from), to);
1699 linkJumpT3(record.condition(), reinterpret_cast<uint16_t*>(from), to);
1702 linkJumpT4(reinterpret_cast<uint16_t*>(from), to);
1704 case LinkConditionalJumpT4:
1705 linkConditionalJumpT4(record.condition(), reinterpret_cast<uint16_t*>(from), to);
1707 case LinkConditionalBX:
1708 linkConditionalBX(record.condition(), reinterpret_cast<uint16_t*>(from), to);
1711 linkBX(reinterpret_cast<uint16_t*>(from), to);
1714 ASSERT_NOT_REACHED();
1719 void* unlinkedCode() { return m_formatter.data(); }
1720 size_t codeSize() const { return m_formatter.codeSize(); }
1722 static unsigned getCallReturnOffset(AssemblerLabel call)
1724 ASSERT(call.isSet());
1725 return call.m_offset;
1728 // Linking & patching:
1730 // 'link' and 'patch' methods are for use on unprotected code - such as the code
1731 // within the AssemblerBuffer, and code being patched by the patch buffer. Once
1732 // code has been finalized it is (platform support permitting) within a non-
1733 // writable region of memory; to modify the code in an execute-only execuable
1734 // pool the 'repatch' and 'relink' methods should be used.
1736 void linkJump(AssemblerLabel from, AssemblerLabel to, JumpType type, Condition condition)
1739 ASSERT(from.isSet());
1740 m_jumpsToLink.append(LinkRecord(from.m_offset, to.m_offset, type, condition));
1743 static void linkJump(void* code, AssemblerLabel from, void* to)
1745 ASSERT(from.isSet());
1747 uint16_t* location = reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
1748 linkJumpAbsolute(location, to);
1751 static void linkCall(void* code, AssemblerLabel from, void* to)
1753 ASSERT(!(reinterpret_cast<intptr_t>(code) & 1));
1754 ASSERT(from.isSet());
1755 ASSERT(reinterpret_cast<intptr_t>(to) & 1);
1757 setPointer(reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code) + from.m_offset) - 1, to);
1760 static void linkPointer(void* code, AssemblerLabel where, void* value)
1762 setPointer(reinterpret_cast<char*>(code) + where.m_offset, value);
1765 static void relinkJump(void* from, void* to)
1767 ASSERT(!(reinterpret_cast<intptr_t>(from) & 1));
1768 ASSERT(!(reinterpret_cast<intptr_t>(to) & 1));
1770 linkJumpAbsolute(reinterpret_cast<uint16_t*>(from), to);
1772 ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(from) - 5, 5 * sizeof(uint16_t));
1775 static void relinkCall(void* from, void* to)
1777 ASSERT(!(reinterpret_cast<intptr_t>(from) & 1));
1778 ASSERT(reinterpret_cast<intptr_t>(to) & 1);
1780 setPointer(reinterpret_cast<uint16_t*>(from) - 1, to);
1783 static void repatchInt32(void* where, int32_t value)
1785 ASSERT(!(reinterpret_cast<intptr_t>(where) & 1));
1787 setInt32(where, value);
1790 static void repatchCompact(void* where, int32_t value)
1793 ASSERT(ARMThumbImmediate::makeUInt12(value).isUInt7());
1794 setUInt7ForLoad(where, ARMThumbImmediate::makeUInt12(value));
1797 static void repatchPointer(void* where, void* value)
1799 ASSERT(!(reinterpret_cast<intptr_t>(where) & 1));
1801 setPointer(where, value);
1804 static void* readPointer(void* where)
1806 return reinterpret_cast<void*>(readInt32(where));
1810 // VFP operations commonly take one or more 5-bit operands, typically representing a
1811 // floating point register number. This will commonly be encoded in the instruction
1812 // in two parts, with one single bit field, and one 4-bit field. In the case of
1813 // double precision operands the high bit of the register number will be encoded
1814 // separately, and for single precision operands the high bit of the register number
1815 // will be encoded individually.
1816 // VFPOperand encapsulates a 5-bit VFP operand, with bits 0..3 containing the 4-bit
1817 // field to be encoded together in the instruction (the low 4-bits of a double
1818 // register number, or the high 4-bits of a single register number), and bit 4
1819 // contains the bit value to be encoded individually.
1821 explicit VFPOperand(uint32_t value)
1824 ASSERT(!(m_value & ~0x1f));
1827 VFPOperand(FPDoubleRegisterID reg)
1832 VFPOperand(RegisterID reg)
1837 VFPOperand(FPSingleRegisterID reg)
1838 : m_value(((reg & 1) << 4) | (reg >> 1)) // rotate the lowest bit of 'reg' to the top.
1844 return m_value >> 4;
1849 return m_value & 0xf;
1855 VFPOperand vcvtOp(bool toInteger, bool isUnsigned, bool isRoundZero)
1857 // Cannot specify rounding when converting to float.
1858 ASSERT(toInteger || !isRoundZero);
1862 // opc2 indicates both toInteger & isUnsigned.
1863 op |= isUnsigned ? 0x4 : 0x5;
1864 // 'op' field in instruction is isRoundZero
1868 // 'op' field in instruction is isUnsigned
1872 return VFPOperand(op);
1875 static void setInt32(void* code, uint32_t value)
1877 uint16_t* location = reinterpret_cast<uint16_t*>(code);
1878 ASSERT(isMOV_imm_T3(location - 4) && isMOVT(location - 2));
1880 ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(value));
1881 ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(value >> 16));
1882 location[-4] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16);
1883 location[-3] = twoWordOp5i6Imm4Reg4EncodedImmSecond((location[-3] >> 8) & 0xf, lo16);
1884 location[-2] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16);
1885 location[-1] = twoWordOp5i6Imm4Reg4EncodedImmSecond((location[-1] >> 8) & 0xf, hi16);
1887 ExecutableAllocator::cacheFlush(location - 4, 4 * sizeof(uint16_t));
1890 static int32_t readInt32(void* code)
1892 uint16_t* location = reinterpret_cast<uint16_t*>(code);
1893 ASSERT(isMOV_imm_T3(location - 4) && isMOVT(location - 2));
1895 ARMThumbImmediate lo16;
1896 ARMThumbImmediate hi16;
1897 decodeTwoWordOp5i6Imm4Reg4EncodedImmFirst(lo16, location[-4]);
1898 decodeTwoWordOp5i6Imm4Reg4EncodedImmSecond(lo16, location[-3]);
1899 decodeTwoWordOp5i6Imm4Reg4EncodedImmFirst(hi16, location[-2]);
1900 decodeTwoWordOp5i6Imm4Reg4EncodedImmSecond(hi16, location[-1]);
1901 uint32_t result = hi16.asUInt16();
1903 result |= lo16.asUInt16();
1904 return static_cast<int32_t>(result);
1907 static void setUInt7ForLoad(void* code, ARMThumbImmediate imm)
1909 // Requires us to have planted a LDR_imm_T1
1910 ASSERT(imm.isValid());
1911 ASSERT(imm.isUInt7());
1912 uint16_t* location = reinterpret_cast<uint16_t*>(code);
1913 location[0] |= (imm.getUInt7() >> 2) << 6;
1914 ExecutableAllocator::cacheFlush(location, sizeof(uint16_t));
1917 static void setPointer(void* code, void* value)
1919 setInt32(code, reinterpret_cast<uint32_t>(value));
1922 static bool isB(void* address)
1924 uint16_t* instruction = static_cast<uint16_t*>(address);
1925 return ((instruction[0] & 0xf800) == OP_B_T4a) && ((instruction[1] & 0xd000) == OP_B_T4b);
1928 static bool isBX(void* address)
1930 uint16_t* instruction = static_cast<uint16_t*>(address);
1931 return (instruction[0] & 0xff87) == OP_BX;
1934 static bool isMOV_imm_T3(void* address)
1936 uint16_t* instruction = static_cast<uint16_t*>(address);
1937 return ((instruction[0] & 0xFBF0) == OP_MOV_imm_T3) && ((instruction[1] & 0x8000) == 0);
1940 static bool isMOVT(void* address)
1942 uint16_t* instruction = static_cast<uint16_t*>(address);
1943 return ((instruction[0] & 0xFBF0) == OP_MOVT) && ((instruction[1] & 0x8000) == 0);
1946 static bool isNOP_T1(void* address)
1948 uint16_t* instruction = static_cast<uint16_t*>(address);
1949 return instruction[0] == OP_NOP_T1;
1952 static bool isNOP_T2(void* address)
1954 uint16_t* instruction = static_cast<uint16_t*>(address);
1955 return (instruction[0] == OP_NOP_T2a) && (instruction[1] == OP_NOP_T2b);
1958 static bool canBeJumpT1(const uint16_t* instruction, const void* target)
1960 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
1961 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
1963 intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction));
1964 // It does not appear to be documented in the ARM ARM (big surprise), but
1965 // for OP_B_T1 the branch displacement encoded in the instruction is 2
1966 // less than the actual displacement.
1968 return ((relative << 23) >> 23) == relative;
1971 static bool canBeJumpT2(const uint16_t* instruction, const void* target)
1973 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
1974 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
1976 intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction));
1977 // It does not appear to be documented in the ARM ARM (big surprise), but
1978 // for OP_B_T2 the branch displacement encoded in the instruction is 2
1979 // less than the actual displacement.
1981 return ((relative << 20) >> 20) == relative;
1984 static bool canBeJumpT3(const uint16_t* instruction, const void* target, bool& mayTriggerErrata)
1986 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
1987 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
1989 intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction));
1990 // From Cortex-A8 errata:
1991 // If the 32-bit Thumb-2 branch instruction spans two 4KiB regions and
1992 // the target of the branch falls within the first region it is
1993 // possible for the processor to incorrectly determine the branch
1994 // instruction, and it is also possible in some cases for the processor
1995 // to enter a deadlock state.
1996 // The instruction is spanning two pages if it ends at an address ending 0x002
1997 bool spansTwo4K = ((reinterpret_cast<intptr_t>(instruction) & 0xfff) == 0x002);
1998 mayTriggerErrata = spansTwo4K;
1999 // The target is in the first page if the jump branch back by [3..0x1002] bytes
2000 bool targetInFirstPage = (relative >= -0x1002) && (relative < -2);
2001 bool wouldTriggerA8Errata = spansTwo4K && targetInFirstPage;
2002 return ((relative << 11) >> 11) == relative && !wouldTriggerA8Errata;
2005 static bool canBeJumpT4(const uint16_t* instruction, const void* target, bool& mayTriggerErrata)
2007 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
2008 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
2010 intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction));
2011 // From Cortex-A8 errata:
2012 // If the 32-bit Thumb-2 branch instruction spans two 4KiB regions and
2013 // the target of the branch falls within the first region it is
2014 // possible for the processor to incorrectly determine the branch
2015 // instruction, and it is also possible in some cases for the processor
2016 // to enter a deadlock state.
2017 // The instruction is spanning two pages if it ends at an address ending 0x002
2018 bool spansTwo4K = ((reinterpret_cast<intptr_t>(instruction) & 0xfff) == 0x002);
2019 mayTriggerErrata = spansTwo4K;
2020 // The target is in the first page if the jump branch back by [3..0x1002] bytes
2021 bool targetInFirstPage = (relative >= -0x1002) && (relative < -2);
2022 bool wouldTriggerA8Errata = spansTwo4K && targetInFirstPage;
2023 return ((relative << 7) >> 7) == relative && !wouldTriggerA8Errata;
2026 void linkJumpT1(Condition cond, uint16_t* instruction, void* target)
2028 // FIMXE: this should be up in the MacroAssembler layer. :-(
2029 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
2030 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
2031 ASSERT(canBeJumpT1(instruction, target));
2033 intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction));
2034 // It does not appear to be documented in the ARM ARM (big surprise), but
2035 // for OP_B_T1 the branch displacement encoded in the instruction is 2
2036 // less than the actual displacement.
2039 // All branch offsets should be an even distance.
2040 ASSERT(!(relative & 1));
2041 instruction[-1] = OP_B_T1 | ((cond & 0xf) << 8) | ((relative & 0x1fe) >> 1);
2044 static void linkJumpT2(uint16_t* instruction, void* target)
2046 // FIMXE: this should be up in the MacroAssembler layer. :-(
2047 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
2048 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
2049 ASSERT(canBeJumpT2(instruction, target));
2051 intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction));
2052 // It does not appear to be documented in the ARM ARM (big surprise), but
2053 // for OP_B_T2 the branch displacement encoded in the instruction is 2
2054 // less than the actual displacement.
2057 // All branch offsets should be an even distance.
2058 ASSERT(!(relative & 1));
2059 instruction[-1] = OP_B_T2 | ((relative & 0xffe) >> 1);
2062 void linkJumpT3(Condition cond, uint16_t* instruction, void* target)
2064 // FIMXE: this should be up in the MacroAssembler layer. :-(
2065 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
2066 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
2068 UNUSED_PARAM(scratch);
2069 ASSERT(canBeJumpT3(instruction, target, scratch));
2071 intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction));
2073 // All branch offsets should be an even distance.
2074 ASSERT(!(relative & 1));
2075 instruction[-2] = OP_B_T3a | ((relative & 0x100000) >> 10) | ((cond & 0xf) << 6) | ((relative & 0x3f000) >> 12);
2076 instruction[-1] = OP_B_T3b | ((relative & 0x80000) >> 8) | ((relative & 0x40000) >> 5) | ((relative & 0xffe) >> 1);
2079 static void linkJumpT4(uint16_t* instruction, void* target)
2081 // FIMXE: this should be up in the MacroAssembler layer. :-(
2082 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
2083 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
2085 UNUSED_PARAM(scratch);
2086 ASSERT(canBeJumpT4(instruction, target, scratch));
2088 intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction));
2089 // ARM encoding for the top two bits below the sign bit is 'peculiar'.
2091 relative ^= 0xC00000;
2093 // All branch offsets should be an even distance.
2094 ASSERT(!(relative & 1));
2095 instruction[-2] = OP_B_T4a | ((relative & 0x1000000) >> 14) | ((relative & 0x3ff000) >> 12);
2096 instruction[-1] = OP_B_T4b | ((relative & 0x800000) >> 10) | ((relative & 0x400000) >> 11) | ((relative & 0xffe) >> 1);
2099 void linkConditionalJumpT4(Condition cond, uint16_t* instruction, void* target)
2101 // FIMXE: this should be up in the MacroAssembler layer. :-(
2102 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
2103 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
2105 instruction[-3] = ifThenElse(cond) | OP_IT;
2106 linkJumpT4(instruction, target);
2109 static void linkBX(uint16_t* instruction, void* target)
2111 // FIMXE: this should be up in the MacroAssembler layer. :-(
2112 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
2113 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
2115 const uint16_t JUMP_TEMPORARY_REGISTER = ARMRegisters::ip;
2116 ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) + 1));
2117 ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) >> 16));
2118 instruction[-5] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16);
2119 instruction[-4] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, lo16);
2120 instruction[-3] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16);
2121 instruction[-2] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, hi16);
2122 instruction[-1] = OP_BX | (JUMP_TEMPORARY_REGISTER << 3);
2125 void linkConditionalBX(Condition cond, uint16_t* instruction, void* target)
2127 // FIMXE: this should be up in the MacroAssembler layer. :-(
2128 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
2129 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
2131 linkBX(instruction, target);
2132 instruction[-6] = ifThenElse(cond, true, true) | OP_IT;
2135 static void linkJumpAbsolute(uint16_t* instruction, void* target)
2137 // FIMXE: this should be up in the MacroAssembler layer. :-(
2138 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
2139 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
2141 ASSERT((isMOV_imm_T3(instruction - 5) && isMOVT(instruction - 3) && isBX(instruction - 1))
2142 || (isNOP_T1(instruction - 5) && isNOP_T2(instruction - 4) && isB(instruction - 2)));
2145 if (canBeJumpT4(instruction, target, scratch)) {
2146 // There may be a better way to fix this, but right now put the NOPs first, since in the
2147 // case of an conditional branch this will be coming after an ITTT predicating *three*
2148 // instructions! Looking backwards to modify the ITTT to an IT is not easy, due to
2149 // variable wdith encoding - the previous instruction might *look* like an ITTT but
2150 // actually be the second half of a 2-word op.
2151 instruction[-5] = OP_NOP_T1;
2152 instruction[-4] = OP_NOP_T2a;
2153 instruction[-3] = OP_NOP_T2b;
2154 linkJumpT4(instruction, target);
2156 const uint16_t JUMP_TEMPORARY_REGISTER = ARMRegisters::ip;
2157 ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) + 1));
2158 ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) >> 16));
2159 instruction[-5] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16);
2160 instruction[-4] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, lo16);
2161 instruction[-3] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16);
2162 instruction[-2] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, hi16);
2163 instruction[-1] = OP_BX | (JUMP_TEMPORARY_REGISTER << 3);
2167 static uint16_t twoWordOp5i6Imm4Reg4EncodedImmFirst(uint16_t op, ARMThumbImmediate imm)
2169 return op | (imm.m_value.i << 10) | imm.m_value.imm4;
2172 static void decodeTwoWordOp5i6Imm4Reg4EncodedImmFirst(ARMThumbImmediate& result, uint16_t value)
2174 result.m_value.i = (value >> 10) & 1;
2175 result.m_value.imm4 = value & 15;
2178 static uint16_t twoWordOp5i6Imm4Reg4EncodedImmSecond(uint16_t rd, ARMThumbImmediate imm)
2180 return (imm.m_value.imm3 << 12) | (rd << 8) | imm.m_value.imm8;
2183 static void decodeTwoWordOp5i6Imm4Reg4EncodedImmSecond(ARMThumbImmediate& result, uint16_t value)
2185 result.m_value.imm3 = (value >> 12) & 7;
2186 result.m_value.imm8 = value & 255;
2189 class ARMInstructionFormatter {
2191 ALWAYS_INLINE void oneWordOp5Reg3Imm8(OpcodeID op, RegisterID rd, uint8_t imm)
2193 m_buffer.putShort(op | (rd << 8) | imm);
2196 ALWAYS_INLINE void oneWordOp5Imm5Reg3Reg3(OpcodeID op, uint8_t imm, RegisterID reg1, RegisterID reg2)
2198 m_buffer.putShort(op | (imm << 6) | (reg1 << 3) | reg2);
2201 ALWAYS_INLINE void oneWordOp7Reg3Reg3Reg3(OpcodeID op, RegisterID reg1, RegisterID reg2, RegisterID reg3)
2203 m_buffer.putShort(op | (reg1 << 6) | (reg2 << 3) | reg3);
2206 ALWAYS_INLINE void oneWordOp8Imm8(OpcodeID op, uint8_t imm)
2208 m_buffer.putShort(op | imm);
2211 ALWAYS_INLINE void oneWordOp8RegReg143(OpcodeID op, RegisterID reg1, RegisterID reg2)
2213 m_buffer.putShort(op | ((reg2 & 8) << 4) | (reg1 << 3) | (reg2 & 7));
2216 ALWAYS_INLINE void oneWordOp9Imm7(OpcodeID op, uint8_t imm)
2218 m_buffer.putShort(op | imm);
2221 ALWAYS_INLINE void oneWordOp10Reg3Reg3(OpcodeID op, RegisterID reg1, RegisterID reg2)
2223 m_buffer.putShort(op | (reg1 << 3) | reg2);
2226 ALWAYS_INLINE void twoWordOp12Reg4FourFours(OpcodeID1 op, RegisterID reg, FourFours ff)
2228 m_buffer.putShort(op | reg);
2229 m_buffer.putShort(ff.m_u.value);
2232 ALWAYS_INLINE void twoWordOp16FourFours(OpcodeID1 op, FourFours ff)
2234 m_buffer.putShort(op);
2235 m_buffer.putShort(ff.m_u.value);
2238 ALWAYS_INLINE void twoWordOp16Op16(OpcodeID1 op1, OpcodeID2 op2)
2240 m_buffer.putShort(op1);
2241 m_buffer.putShort(op2);
2244 ALWAYS_INLINE void twoWordOp5i6Imm4Reg4EncodedImm(OpcodeID1 op, int imm4, RegisterID rd, ARMThumbImmediate imm)
2246 ARMThumbImmediate newImm = imm;
2247 newImm.m_value.imm4 = imm4;
2249 m_buffer.putShort(ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmFirst(op, newImm));
2250 m_buffer.putShort(ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmSecond(rd, newImm));
2253 ALWAYS_INLINE void twoWordOp12Reg4Reg4Imm12(OpcodeID1 op, RegisterID reg1, RegisterID reg2, uint16_t imm)
2255 m_buffer.putShort(op | reg1);
2256 m_buffer.putShort((reg2 << 12) | imm);
2259 ALWAYS_INLINE void twoWordOp12Reg40Imm3Reg4Imm20Imm5(OpcodeID1 op, RegisterID reg1, RegisterID reg2, uint16_t imm1, uint16_t imm2, uint16_t imm3)
2261 m_buffer.putShort(op | reg1);
2262 m_buffer.putShort((imm1 << 12) | (reg2 << 8) | (imm2 << 6) | imm3);
2265 // Formats up instructions of the pattern:
2266 // 111111111B11aaaa:bbbb222SA2C2cccc
2267 // Where 1s in the pattern come from op1, 2s in the pattern come from op2, S is the provided size bit.
2268 // Operands provide 5 bit values of the form Aaaaa, Bbbbb, Ccccc.
2269 ALWAYS_INLINE void vfpOp(OpcodeID1 op1, OpcodeID2 op2, bool size, VFPOperand a, VFPOperand b, VFPOperand c)
2271 ASSERT(!(op1 & 0x004f));
2272 ASSERT(!(op2 & 0xf1af));
2273 m_buffer.putShort(op1 | b.bits1() << 6 | a.bits4());
2274 m_buffer.putShort(op2 | b.bits4() << 12 | size << 8 | a.bits1() << 7 | c.bits1() << 5 | c.bits4());
2277 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
2278 // (i.e. +/-(0..255) 32-bit words)
2279 ALWAYS_INLINE void vfpMemOp(OpcodeID1 op1, OpcodeID2 op2, bool size, RegisterID rn, VFPOperand rd, int32_t imm)
2287 uint32_t offset = imm;
2288 ASSERT(!(offset & ~0x3fc));
2291 m_buffer.putShort(op1 | (up << 7) | rd.bits1() << 6 | rn);
2292 m_buffer.putShort(op2 | rd.bits4() << 12 | size << 8 | offset);
2295 // Administrative methods:
2297 size_t codeSize() const { return m_buffer.codeSize(); }
2298 AssemblerLabel label() const { return m_buffer.label(); }
2299 bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); }
2300 void* data() const { return m_buffer.data(); }
2303 unsigned debugOffset() { return m_buffer.debugOffset(); }
2307 AssemblerBuffer m_buffer;
2310 Vector<LinkRecord> m_jumpsToLink;
2311 Vector<int32_t> m_offsets;
2316 #endif // ENABLE(ASSEMBLER) && CPU(ARM_THUMB2)
2318 #endif // ARMAssembler_h