2 * Copyright (C) 2009, 2010, 2012, 2013, 2014 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"
34 #include <wtf/Assertions.h>
35 #include <wtf/Vector.h>
40 namespace ARMRegisters
{
42 #define FOR_EACH_CPU_REGISTER(V) \
43 FOR_EACH_CPU_GPREGISTER(V) \
44 FOR_EACH_CPU_SPECIAL_REGISTER(V) \
45 FOR_EACH_CPU_FPREGISTER(V)
47 // The following are defined as pairs of the following value:
48 // 1. type of the storage needed to save the register value by the JIT probe.
49 // 2. name of the register.
50 #define FOR_EACH_CPU_GPREGISTER(V) \
68 #define FOR_EACH_CPU_SPECIAL_REGISTER(V) \
72 #define FOR_EACH_CPU_FPREGISTER(V) \
107 #define DECLARE_REGISTER(_type, _regName) _regName,
108 FOR_EACH_CPU_GPREGISTER(DECLARE_REGISTER
)
109 #undef DECLARE_REGISTER
111 fp
= r7
, // frame pointer
112 sb
= r9
, // static base
113 sl
= r10
, // stack limit
153 } FPSingleRegisterID
;
156 #define DECLARE_REGISTER(_type, _regName) _regName,
157 FOR_EACH_CPU_FPREGISTER(DECLARE_REGISTER
)
158 #undef DECLARE_REGISTER
159 } FPDoubleRegisterID
;
196 inline FPSingleRegisterID
asSingle(FPDoubleRegisterID reg
)
199 return (FPSingleRegisterID
)(reg
<< 1);
202 inline FPDoubleRegisterID
asDouble(FPSingleRegisterID reg
)
205 return (FPDoubleRegisterID
)(reg
>> 1);
208 } // namespace ARMRegisters
210 class ARMv7Assembler
;
211 class ARMThumbImmediate
{
212 friend class ARMv7Assembler
;
214 typedef uint8_t ThumbImmediateType
;
215 static const ThumbImmediateType TypeInvalid
= 0;
216 static const ThumbImmediateType TypeEncoded
= 1;
217 static const ThumbImmediateType TypeUInt16
= 2;
227 // If this is an encoded immediate, then it may describe a shift, or a pattern.
229 unsigned shiftValue7
: 7;
230 unsigned shiftAmount
: 5;
233 unsigned immediate
: 8;
234 unsigned pattern
: 4;
236 } ThumbImmediateValue
;
238 // byte0 contains least significant bit; not using an array to make client code endian agnostic.
249 ALWAYS_INLINE
static void countLeadingZerosPartial(uint32_t& value
, int32_t& zeros
, const int N
)
251 if (value
& ~((1 << N
) - 1)) /* check for any of the top N bits (of 2N bits) are set */
252 value
>>= N
; /* if any were set, lose the bottom N */
253 else /* if none of the top N bits are set, */
254 zeros
+= N
; /* then we have identified N leading zeros */
257 static int32_t countLeadingZeros(uint32_t value
)
263 countLeadingZerosPartial(value
, zeros
, 16);
264 countLeadingZerosPartial(value
, zeros
, 8);
265 countLeadingZerosPartial(value
, zeros
, 4);
266 countLeadingZerosPartial(value
, zeros
, 2);
267 countLeadingZerosPartial(value
, zeros
, 1);
272 : m_type(TypeInvalid
)
277 ARMThumbImmediate(ThumbImmediateType type
, ThumbImmediateValue value
)
283 ARMThumbImmediate(ThumbImmediateType type
, uint16_t value
)
286 // Make sure this constructor is only reached with type TypeUInt16;
287 // this extra parameter makes the code a little clearer by making it
288 // explicit at call sites which type is being constructed
289 ASSERT_UNUSED(type
, type
== TypeUInt16
);
291 m_value
.asInt
= value
;
295 static ARMThumbImmediate
makeEncodedImm(uint32_t value
)
297 ThumbImmediateValue encoding
;
300 // okay, these are easy.
302 encoding
.immediate
= value
;
303 encoding
.pattern
= 0;
304 return ARMThumbImmediate(TypeEncoded
, encoding
);
307 int32_t leadingZeros
= countLeadingZeros(value
);
308 // if there were 24 or more leading zeros, then we'd have hit the (value < 256) case.
309 ASSERT(leadingZeros
< 24);
311 // Given a number with bit fields Z:B:C, where count(Z)+count(B)+count(C) == 32,
312 // Z are the bits known zero, B is the 8-bit immediate, C are the bits to check for
313 // zero. count(B) == 8, so the count of bits to be checked is 24 - count(Z).
314 int32_t rightShiftAmount
= 24 - leadingZeros
;
315 if (value
== ((value
>> rightShiftAmount
) << rightShiftAmount
)) {
316 // Shift the value down to the low byte position. The assign to
317 // shiftValue7 drops the implicit top bit.
318 encoding
.shiftValue7
= value
>> rightShiftAmount
;
319 // The endoded shift amount is the magnitude of a right rotate.
320 encoding
.shiftAmount
= 8 + leadingZeros
;
321 return ARMThumbImmediate(TypeEncoded
, encoding
);
327 if ((bytes
.byte0
== bytes
.byte1
) && (bytes
.byte0
== bytes
.byte2
) && (bytes
.byte0
== bytes
.byte3
)) {
328 encoding
.immediate
= bytes
.byte0
;
329 encoding
.pattern
= 3;
330 return ARMThumbImmediate(TypeEncoded
, encoding
);
333 if ((bytes
.byte0
== bytes
.byte2
) && !(bytes
.byte1
| bytes
.byte3
)) {
334 encoding
.immediate
= bytes
.byte0
;
335 encoding
.pattern
= 1;
336 return ARMThumbImmediate(TypeEncoded
, encoding
);
339 if ((bytes
.byte1
== bytes
.byte3
) && !(bytes
.byte0
| bytes
.byte2
)) {
340 encoding
.immediate
= bytes
.byte1
;
341 encoding
.pattern
= 2;
342 return ARMThumbImmediate(TypeEncoded
, encoding
);
345 return ARMThumbImmediate();
348 static ARMThumbImmediate
makeUInt12(int32_t value
)
350 return (!(value
& 0xfffff000))
351 ? ARMThumbImmediate(TypeUInt16
, (uint16_t)value
)
352 : ARMThumbImmediate();
355 static ARMThumbImmediate
makeUInt12OrEncodedImm(int32_t value
)
357 // If this is not a 12-bit unsigned it, try making an encoded immediate.
358 return (!(value
& 0xfffff000))
359 ? ARMThumbImmediate(TypeUInt16
, (uint16_t)value
)
360 : makeEncodedImm(value
);
363 // The 'make' methods, above, return a !isValid() value if the argument
364 // cannot be represented as the requested type. This methods is called
365 // 'get' since the argument can always be represented.
366 static ARMThumbImmediate
makeUInt16(uint16_t value
)
368 return ARMThumbImmediate(TypeUInt16
, value
);
373 return m_type
!= TypeInvalid
;
376 uint16_t asUInt16() const { return m_value
.asInt
; }
378 // These methods rely on the format of encoded byte values.
379 bool isUInt3() { return !(m_value
.asInt
& 0xfff8); }
380 bool isUInt4() { return !(m_value
.asInt
& 0xfff0); }
381 bool isUInt5() { return !(m_value
.asInt
& 0xffe0); }
382 bool isUInt6() { return !(m_value
.asInt
& 0xffc0); }
383 bool isUInt7() { return !(m_value
.asInt
& 0xff80); }
384 bool isUInt8() { return !(m_value
.asInt
& 0xff00); }
385 bool isUInt9() { return (m_type
== TypeUInt16
) && !(m_value
.asInt
& 0xfe00); }
386 bool isUInt10() { return (m_type
== TypeUInt16
) && !(m_value
.asInt
& 0xfc00); }
387 bool isUInt12() { return (m_type
== TypeUInt16
) && !(m_value
.asInt
& 0xf000); }
388 bool isUInt16() { return m_type
== TypeUInt16
; }
389 uint8_t getUInt3() { ASSERT(isUInt3()); return m_value
.asInt
; }
390 uint8_t getUInt4() { ASSERT(isUInt4()); return m_value
.asInt
; }
391 uint8_t getUInt5() { ASSERT(isUInt5()); return m_value
.asInt
; }
392 uint8_t getUInt6() { ASSERT(isUInt6()); return m_value
.asInt
; }
393 uint8_t getUInt7() { ASSERT(isUInt7()); return m_value
.asInt
; }
394 uint8_t getUInt8() { ASSERT(isUInt8()); return m_value
.asInt
; }
395 uint16_t getUInt9() { ASSERT(isUInt9()); return m_value
.asInt
; }
396 uint16_t getUInt10() { ASSERT(isUInt10()); return m_value
.asInt
; }
397 uint16_t getUInt12() { ASSERT(isUInt12()); return m_value
.asInt
; }
398 uint16_t getUInt16() { ASSERT(isUInt16()); return m_value
.asInt
; }
400 bool isEncodedImm() { return m_type
== TypeEncoded
; }
403 ThumbImmediateType m_type
;
404 ThumbImmediateValue m_value
;
413 SRType_RRX
= SRType_ROR
416 class ShiftTypeAndAmount
{
417 friend class ARMv7Assembler
;
422 m_u
.type
= (ARMShiftType
)0;
426 ShiftTypeAndAmount(ARMShiftType type
, unsigned amount
)
429 m_u
.amount
= amount
& 31;
432 unsigned lo4() { return m_u
.lo4
; }
433 unsigned hi4() { return m_u
.hi4
; }
448 class ARMv7Assembler
{
450 typedef ARMRegisters::RegisterID RegisterID
;
451 typedef ARMRegisters::FPSingleRegisterID FPSingleRegisterID
;
452 typedef ARMRegisters::FPDoubleRegisterID FPDoubleRegisterID
;
453 typedef ARMRegisters::FPQuadRegisterID FPQuadRegisterID
;
454 typedef FPDoubleRegisterID FPRegisterID
;
456 static RegisterID
firstRegister() { return ARMRegisters::r0
; }
457 static RegisterID
lastRegister() { return ARMRegisters::r13
; }
459 static FPRegisterID
firstFPRegister() { return ARMRegisters::d0
; }
460 static FPRegisterID
lastFPRegister() { return ARMRegisters::d31
; }
462 // (HS, LO, HI, LS) -> (AE, B, A, BE)
463 // (VS, VC) -> (O, NO)
465 ConditionEQ
, // Zero / Equal.
466 ConditionNE
, // Non-zero / Not equal.
467 ConditionHS
, ConditionCS
= ConditionHS
, // Unsigned higher or same.
468 ConditionLO
, ConditionCC
= ConditionLO
, // Unsigned lower.
469 ConditionMI
, // Negative.
470 ConditionPL
, // Positive or zero.
471 ConditionVS
, // Overflowed.
472 ConditionVC
, // Not overflowed.
473 ConditionHI
, // Unsigned higher.
474 ConditionLS
, // Unsigned lower or same.
475 ConditionGE
, // Signed greater than or equal.
476 ConditionLT
, // Signed less than.
477 ConditionGT
, // Signed greater than.
478 ConditionLE
, // Signed less than or equal.
479 ConditionAL
, // Unconditional / Always execute.
483 #define JUMP_ENUM_WITH_SIZE(index, value) (((value) << 3) | (index))
484 #define JUMP_ENUM_SIZE(jump) ((jump) >> 3)
485 enum JumpType
{ JumpFixed
= JUMP_ENUM_WITH_SIZE(0, 0),
486 JumpNoCondition
= JUMP_ENUM_WITH_SIZE(1, 5 * sizeof(uint16_t)),
487 JumpCondition
= JUMP_ENUM_WITH_SIZE(2, 6 * sizeof(uint16_t)),
488 JumpNoConditionFixedSize
= JUMP_ENUM_WITH_SIZE(3, 5 * sizeof(uint16_t)),
489 JumpConditionFixedSize
= JUMP_ENUM_WITH_SIZE(4, 6 * sizeof(uint16_t))
492 LinkInvalid
= JUMP_ENUM_WITH_SIZE(0, 0),
493 LinkJumpT1
= JUMP_ENUM_WITH_SIZE(1, sizeof(uint16_t)),
494 LinkJumpT2
= JUMP_ENUM_WITH_SIZE(2, sizeof(uint16_t)),
495 LinkJumpT3
= JUMP_ENUM_WITH_SIZE(3, 2 * sizeof(uint16_t)),
496 LinkJumpT4
= JUMP_ENUM_WITH_SIZE(4, 2 * sizeof(uint16_t)),
497 LinkConditionalJumpT4
= JUMP_ENUM_WITH_SIZE(5, 3 * sizeof(uint16_t)),
498 LinkBX
= JUMP_ENUM_WITH_SIZE(6, 5 * sizeof(uint16_t)),
499 LinkConditionalBX
= JUMP_ENUM_WITH_SIZE(7, 6 * sizeof(uint16_t))
504 LinkRecord(intptr_t from
, intptr_t to
, JumpType type
, Condition condition
)
506 data
.realTypes
.m_from
= from
;
507 data
.realTypes
.m_to
= to
;
508 data
.realTypes
.m_type
= type
;
509 data
.realTypes
.m_linkType
= LinkInvalid
;
510 data
.realTypes
.m_condition
= condition
;
512 void operator=(const LinkRecord
& other
)
514 data
.copyTypes
.content
[0] = other
.data
.copyTypes
.content
[0];
515 data
.copyTypes
.content
[1] = other
.data
.copyTypes
.content
[1];
516 data
.copyTypes
.content
[2] = other
.data
.copyTypes
.content
[2];
518 intptr_t from() const { return data
.realTypes
.m_from
; }
519 void setFrom(intptr_t from
) { data
.realTypes
.m_from
= from
; }
520 intptr_t to() const { return data
.realTypes
.m_to
; }
521 JumpType
type() const { return data
.realTypes
.m_type
; }
522 JumpLinkType
linkType() const { return data
.realTypes
.m_linkType
; }
523 void setLinkType(JumpLinkType linkType
) { ASSERT(data
.realTypes
.m_linkType
== LinkInvalid
); data
.realTypes
.m_linkType
= linkType
; }
524 Condition
condition() const { return data
.realTypes
.m_condition
; }
528 intptr_t m_from
: 31;
531 JumpLinkType m_linkType
: 8;
532 Condition m_condition
: 16;
537 COMPILE_ASSERT(sizeof(RealTypes
) == sizeof(CopyTypes
), LinkRecordCopyStructSizeEqualsRealStruct
);
542 : m_indexOfLastWatchpoint(INT_MIN
)
543 , m_indexOfTailOfLastWatchpoint(INT_MIN
)
547 AssemblerBuffer
& buffer() { return m_formatter
.m_buffer
; }
552 static bool BadReg(RegisterID reg
)
554 return (reg
== ARMRegisters::sp
) || (reg
== ARMRegisters::pc
);
557 uint32_t singleRegisterMask(FPSingleRegisterID rdNum
, int highBitsShift
, int lowBitShift
)
559 uint32_t rdMask
= (rdNum
>> 1) << highBitsShift
;
561 rdMask
|= 1 << lowBitShift
;
565 uint32_t doubleRegisterMask(FPDoubleRegisterID rdNum
, int highBitShift
, int lowBitsShift
)
567 uint32_t rdMask
= (rdNum
& 0xf) << lowBitsShift
;
569 rdMask
|= 1 << highBitShift
;
574 OP_ADD_reg_T1
= 0x1800,
575 OP_SUB_reg_T1
= 0x1A00,
576 OP_ADD_imm_T1
= 0x1C00,
577 OP_SUB_imm_T1
= 0x1E00,
578 OP_MOV_imm_T1
= 0x2000,
579 OP_CMP_imm_T1
= 0x2800,
580 OP_ADD_imm_T2
= 0x3000,
581 OP_SUB_imm_T2
= 0x3800,
582 OP_AND_reg_T1
= 0x4000,
583 OP_EOR_reg_T1
= 0x4040,
584 OP_TST_reg_T1
= 0x4200,
585 OP_RSB_imm_T1
= 0x4240,
586 OP_CMP_reg_T1
= 0x4280,
587 OP_ORR_reg_T1
= 0x4300,
588 OP_MVN_reg_T1
= 0x43C0,
589 OP_ADD_reg_T2
= 0x4400,
590 OP_MOV_reg_T1
= 0x4600,
593 OP_STR_reg_T1
= 0x5000,
594 OP_STRH_reg_T1
= 0x5200,
595 OP_STRB_reg_T1
= 0x5400,
596 OP_LDRSB_reg_T1
= 0x5600,
597 OP_LDR_reg_T1
= 0x5800,
598 OP_LDRH_reg_T1
= 0x5A00,
599 OP_LDRB_reg_T1
= 0x5C00,
600 OP_LDRSH_reg_T1
= 0x5E00,
601 OP_STR_imm_T1
= 0x6000,
602 OP_LDR_imm_T1
= 0x6800,
603 OP_STRB_imm_T1
= 0x7000,
604 OP_LDRB_imm_T1
= 0x7800,
605 OP_STRH_imm_T1
= 0x8000,
606 OP_LDRH_imm_T1
= 0x8800,
607 OP_STR_imm_T2
= 0x9000,
608 OP_LDR_imm_T2
= 0x9800,
609 OP_ADD_SP_imm_T1
= 0xA800,
610 OP_ADD_SP_imm_T2
= 0xB000,
611 OP_SUB_SP_imm_T1
= 0xB080,
624 OP_AND_reg_T2
= 0xEA00,
625 OP_TST_reg_T2
= 0xEA10,
626 OP_ORR_reg_T2
= 0xEA40,
627 OP_ORR_S_reg_T2
= 0xEA50,
628 OP_ASR_imm_T1
= 0xEA4F,
629 OP_LSL_imm_T1
= 0xEA4F,
630 OP_LSR_imm_T1
= 0xEA4F,
631 OP_ROR_imm_T1
= 0xEA4F,
632 OP_MVN_reg_T2
= 0xEA6F,
633 OP_EOR_reg_T2
= 0xEA80,
634 OP_ADD_reg_T3
= 0xEB00,
635 OP_ADD_S_reg_T3
= 0xEB10,
636 OP_SUB_reg_T2
= 0xEBA0,
637 OP_SUB_S_reg_T2
= 0xEBB0,
638 OP_CMP_reg_T2
= 0xEBB0,
639 OP_VMOV_CtoD
= 0xEC00,
640 OP_VMOV_DtoC
= 0xEC10,
645 OP_VMOV_CtoS
= 0xEE00,
646 OP_VMOV_StoC
= 0xEE10,
653 OP_VCVT_FPIVFP
= 0xEEB0,
655 OP_VMOV_IMM_T2
= 0xEEB0,
658 OP_VSQRT_T1
= 0xEEB0,
659 OP_VCVTSD_T1
= 0xEEB0,
660 OP_VCVTDS_T1
= 0xEEB0,
663 OP_AND_imm_T1
= 0xF000,
665 OP_ORR_imm_T1
= 0xF040,
666 OP_MOV_imm_T2
= 0xF040,
668 OP_EOR_imm_T1
= 0xF080,
669 OP_ADD_imm_T3
= 0xF100,
670 OP_ADD_S_imm_T3
= 0xF110,
673 OP_SUB_imm_T3
= 0xF1A0,
674 OP_SUB_S_imm_T3
= 0xF1B0,
675 OP_CMP_imm_T2
= 0xF1B0,
676 OP_RSB_imm_T2
= 0xF1C0,
677 OP_RSB_S_imm_T2
= 0xF1D0,
678 OP_ADD_imm_T4
= 0xF200,
679 OP_MOV_imm_T3
= 0xF240,
680 OP_SUB_imm_T4
= 0xF2A0,
684 OP_DMB_SY_T2a
= 0xF3BF,
685 OP_STRB_imm_T3
= 0xF800,
686 OP_STRB_reg_T2
= 0xF800,
687 OP_LDRB_imm_T3
= 0xF810,
688 OP_LDRB_reg_T2
= 0xF810,
689 OP_STRH_imm_T3
= 0xF820,
690 OP_STRH_reg_T2
= 0xF820,
691 OP_LDRH_reg_T2
= 0xF830,
692 OP_LDRH_imm_T3
= 0xF830,
693 OP_STR_imm_T4
= 0xF840,
694 OP_STR_reg_T2
= 0xF840,
695 OP_LDR_imm_T4
= 0xF850,
696 OP_LDR_reg_T2
= 0xF850,
697 OP_STRB_imm_T2
= 0xF880,
698 OP_LDRB_imm_T2
= 0xF890,
699 OP_STRH_imm_T2
= 0xF8A0,
700 OP_LDRH_imm_T2
= 0xF8B0,
701 OP_STR_imm_T3
= 0xF8C0,
702 OP_LDR_imm_T3
= 0xF8D0,
703 OP_LDRSB_reg_T2
= 0xF910,
704 OP_LDRSH_reg_T2
= 0xF930,
705 OP_LSL_reg_T2
= 0xFA00,
706 OP_LSR_reg_T2
= 0xFA20,
707 OP_ASR_reg_T2
= 0xFA40,
708 OP_ROR_reg_T2
= 0xFA60,
710 OP_SMULL_T1
= 0xFB80,
711 #if HAVE(ARM_IDIV_INSTRUCTIONS)
718 OP_VADD_T2b
= 0x0A00,
722 OP_VMOV_IMM_T2b
= 0x0A00,
723 OP_VMOV_T2b
= 0x0A40,
724 OP_VMUL_T2b
= 0x0A00,
727 OP_VMOV_StoCb
= 0x0A10,
728 OP_VMOV_CtoSb
= 0x0A10,
729 OP_VMOV_DtoCb
= 0x0A10,
730 OP_VMOV_CtoDb
= 0x0A10,
732 OP_VABS_T2b
= 0x0A40,
734 OP_VCVT_FPIVFPb
= 0x0A40,
735 OP_VNEG_T2b
= 0x0A40,
736 OP_VSUB_T2b
= 0x0A40,
737 OP_VSQRT_T1b
= 0x0A40,
738 OP_VCVTSD_T1b
= 0x0A40,
739 OP_VCVTDS_T1b
= 0x0A40,
741 OP_DMB_SY_T2b
= 0x8F5F,
747 FourFours(unsigned f3
, unsigned f2
, unsigned f1
, unsigned f0
)
766 class ARMInstructionFormatter
;
769 static bool ifThenElseConditionBit(Condition condition
, bool isIf
)
771 return isIf
? (condition
& 1) : !(condition
& 1);
773 static uint8_t ifThenElse(Condition condition
, bool inst2if
, bool inst3if
, bool inst4if
)
775 int mask
= (ifThenElseConditionBit(condition
, inst2if
) << 3)
776 | (ifThenElseConditionBit(condition
, inst3if
) << 2)
777 | (ifThenElseConditionBit(condition
, inst4if
) << 1)
779 ASSERT((condition
!= ConditionAL
) || !(mask
& (mask
- 1)));
780 return (condition
<< 4) | mask
;
782 static uint8_t ifThenElse(Condition condition
, bool inst2if
, bool inst3if
)
784 int mask
= (ifThenElseConditionBit(condition
, inst2if
) << 3)
785 | (ifThenElseConditionBit(condition
, inst3if
) << 2)
787 ASSERT((condition
!= ConditionAL
) || !(mask
& (mask
- 1)));
788 return (condition
<< 4) | mask
;
790 static uint8_t ifThenElse(Condition condition
, bool inst2if
)
792 int mask
= (ifThenElseConditionBit(condition
, inst2if
) << 3)
794 ASSERT((condition
!= ConditionAL
) || !(mask
& (mask
- 1)));
795 return (condition
<< 4) | mask
;
798 static uint8_t ifThenElse(Condition condition
)
801 return (condition
<< 4) | mask
;
806 void adc(RegisterID rd
, RegisterID rn
, ARMThumbImmediate imm
)
808 // Rd can only be SP if Rn is also SP.
809 ASSERT((rd
!= ARMRegisters::sp
) || (rn
== ARMRegisters::sp
));
810 ASSERT(rd
!= ARMRegisters::pc
);
811 ASSERT(rn
!= ARMRegisters::pc
);
812 ASSERT(imm
.isEncodedImm());
814 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADC_imm
, rn
, rd
, imm
);
817 void add(RegisterID rd
, RegisterID rn
, ARMThumbImmediate imm
)
819 // Rd can only be SP if Rn is also SP.
820 ASSERT((rd
!= ARMRegisters::sp
) || (rn
== ARMRegisters::sp
));
821 ASSERT(rd
!= ARMRegisters::pc
);
822 ASSERT(rn
!= ARMRegisters::pc
);
823 ASSERT(imm
.isValid());
825 if (rn
== ARMRegisters::sp
&& imm
.isUInt16()) {
826 ASSERT(!(imm
.getUInt16() & 3));
827 if (!(rd
& 8) && imm
.isUInt10()) {
828 m_formatter
.oneWordOp5Reg3Imm8(OP_ADD_SP_imm_T1
, rd
, static_cast<uint8_t>(imm
.getUInt10() >> 2));
830 } else if ((rd
== ARMRegisters::sp
) && imm
.isUInt9()) {
831 m_formatter
.oneWordOp9Imm7(OP_ADD_SP_imm_T2
, static_cast<uint8_t>(imm
.getUInt9() >> 2));
834 } else if (!((rd
| rn
) & 8)) {
836 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_ADD_imm_T1
, (RegisterID
)imm
.getUInt3(), rn
, rd
);
838 } else if ((rd
== rn
) && imm
.isUInt8()) {
839 m_formatter
.oneWordOp5Reg3Imm8(OP_ADD_imm_T2
, rd
, imm
.getUInt8());
844 if (imm
.isEncodedImm())
845 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T3
, rn
, rd
, imm
);
847 ASSERT(imm
.isUInt12());
848 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T4
, rn
, rd
, imm
);
852 ALWAYS_INLINE
void add(RegisterID rd
, RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
854 ASSERT((rd
!= ARMRegisters::sp
) || (rn
== ARMRegisters::sp
));
855 ASSERT(rd
!= ARMRegisters::pc
);
856 ASSERT(rn
!= ARMRegisters::pc
);
858 m_formatter
.twoWordOp12Reg4FourFours(OP_ADD_reg_T3
, rn
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
861 // NOTE: In an IT block, add doesn't modify the flags register.
862 ALWAYS_INLINE
void add(RegisterID rd
, RegisterID rn
, RegisterID rm
)
864 if (rd
== ARMRegisters::sp
) {
870 m_formatter
.oneWordOp8RegReg143(OP_ADD_reg_T2
, rm
, rd
);
872 m_formatter
.oneWordOp8RegReg143(OP_ADD_reg_T2
, rn
, rd
);
873 else if (!((rd
| rn
| rm
) & 8))
874 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_ADD_reg_T1
, rm
, rn
, rd
);
876 add(rd
, rn
, rm
, ShiftTypeAndAmount());
879 // Not allowed in an IT (if then) block.
880 ALWAYS_INLINE
void add_S(RegisterID rd
, RegisterID rn
, ARMThumbImmediate imm
)
882 // Rd can only be SP if Rn is also SP.
883 ASSERT((rd
!= ARMRegisters::sp
) || (rn
== ARMRegisters::sp
));
884 ASSERT(rd
!= ARMRegisters::pc
);
885 ASSERT(rn
!= ARMRegisters::pc
);
886 ASSERT(imm
.isEncodedImm());
888 if (!((rd
| rn
) & 8)) {
890 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_ADD_imm_T1
, (RegisterID
)imm
.getUInt3(), rn
, rd
);
892 } else if ((rd
== rn
) && imm
.isUInt8()) {
893 m_formatter
.oneWordOp5Reg3Imm8(OP_ADD_imm_T2
, rd
, imm
.getUInt8());
898 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_S_imm_T3
, rn
, rd
, imm
);
901 // Not allowed in an IT (if then) block?
902 ALWAYS_INLINE
void add_S(RegisterID rd
, RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
904 ASSERT((rd
!= ARMRegisters::sp
) || (rn
== ARMRegisters::sp
));
905 ASSERT(rd
!= ARMRegisters::pc
);
906 ASSERT(rn
!= ARMRegisters::pc
);
908 m_formatter
.twoWordOp12Reg4FourFours(OP_ADD_S_reg_T3
, rn
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
911 // Not allowed in an IT (if then) block.
912 ALWAYS_INLINE
void add_S(RegisterID rd
, RegisterID rn
, RegisterID rm
)
914 if (!((rd
| rn
| rm
) & 8))
915 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_ADD_reg_T1
, rm
, rn
, rd
);
917 add_S(rd
, rn
, rm
, ShiftTypeAndAmount());
920 ALWAYS_INLINE
void ARM_and(RegisterID rd
, RegisterID rn
, ARMThumbImmediate imm
)
924 ASSERT(imm
.isEncodedImm());
925 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_AND_imm_T1
, rn
, rd
, imm
);
928 ALWAYS_INLINE
void ARM_and(RegisterID rd
, RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
933 m_formatter
.twoWordOp12Reg4FourFours(OP_AND_reg_T2
, rn
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
936 ALWAYS_INLINE
void ARM_and(RegisterID rd
, RegisterID rn
, RegisterID rm
)
938 if ((rd
== rn
) && !((rd
| rm
) & 8))
939 m_formatter
.oneWordOp10Reg3Reg3(OP_AND_reg_T1
, rm
, rd
);
940 else if ((rd
== rm
) && !((rd
| rn
) & 8))
941 m_formatter
.oneWordOp10Reg3Reg3(OP_AND_reg_T1
, rn
, rd
);
943 ARM_and(rd
, rn
, rm
, ShiftTypeAndAmount());
946 ALWAYS_INLINE
void asr(RegisterID rd
, RegisterID rm
, int32_t shiftAmount
)
950 ShiftTypeAndAmount
shift(SRType_ASR
, shiftAmount
);
951 m_formatter
.twoWordOp16FourFours(OP_ASR_imm_T1
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
954 ALWAYS_INLINE
void asr(RegisterID rd
, RegisterID rn
, RegisterID rm
)
959 m_formatter
.twoWordOp12Reg4FourFours(OP_ASR_reg_T2
, rn
, FourFours(0xf, rd
, 0, rm
));
962 // Only allowed in IT (if then) block if last instruction.
963 ALWAYS_INLINE AssemblerLabel
b()
965 m_formatter
.twoWordOp16Op16(OP_B_T4a
, OP_B_T4b
);
966 return m_formatter
.label();
969 // Only allowed in IT (if then) block if last instruction.
970 ALWAYS_INLINE AssemblerLabel
blx(RegisterID rm
)
972 ASSERT(rm
!= ARMRegisters::pc
);
973 m_formatter
.oneWordOp8RegReg143(OP_BLX
, rm
, (RegisterID
)8);
974 return m_formatter
.label();
977 // Only allowed in IT (if then) block if last instruction.
978 ALWAYS_INLINE AssemblerLabel
bx(RegisterID rm
)
980 m_formatter
.oneWordOp8RegReg143(OP_BX
, rm
, (RegisterID
)0);
981 return m_formatter
.label();
984 void bkpt(uint8_t imm
= 0)
986 m_formatter
.oneWordOp8Imm8(OP_BKPT
, imm
);
989 ALWAYS_INLINE
void clz(RegisterID rd
, RegisterID rm
)
993 m_formatter
.twoWordOp12Reg4FourFours(OP_CLZ
, rm
, FourFours(0xf, rd
, 8, rm
));
996 ALWAYS_INLINE
void cmn(RegisterID rn
, ARMThumbImmediate imm
)
998 ASSERT(rn
!= ARMRegisters::pc
);
999 ASSERT(imm
.isEncodedImm());
1001 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMN_imm
, rn
, (RegisterID
)0xf, imm
);
1004 ALWAYS_INLINE
void cmp(RegisterID rn
, ARMThumbImmediate imm
)
1006 ASSERT(rn
!= ARMRegisters::pc
);
1007 ASSERT(imm
.isEncodedImm());
1009 if (!(rn
& 8) && imm
.isUInt8())
1010 m_formatter
.oneWordOp5Reg3Imm8(OP_CMP_imm_T1
, rn
, imm
.getUInt8());
1012 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMP_imm_T2
, rn
, (RegisterID
)0xf, imm
);
1015 ALWAYS_INLINE
void cmp(RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
1017 ASSERT(rn
!= ARMRegisters::pc
);
1018 ASSERT(!BadReg(rm
));
1019 m_formatter
.twoWordOp12Reg4FourFours(OP_CMP_reg_T2
, rn
, FourFours(shift
.hi4(), 0xf, shift
.lo4(), rm
));
1022 ALWAYS_INLINE
void cmp(RegisterID rn
, RegisterID rm
)
1025 cmp(rn
, rm
, ShiftTypeAndAmount());
1027 m_formatter
.oneWordOp10Reg3Reg3(OP_CMP_reg_T1
, rm
, rn
);
1030 // xor is not spelled with an 'e'. :-(
1031 ALWAYS_INLINE
void eor(RegisterID rd
, RegisterID rn
, ARMThumbImmediate imm
)
1033 ASSERT(!BadReg(rd
));
1034 ASSERT(!BadReg(rn
));
1035 ASSERT(imm
.isEncodedImm());
1036 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_EOR_imm_T1
, rn
, rd
, imm
);
1039 // xor is not spelled with an 'e'. :-(
1040 ALWAYS_INLINE
void eor(RegisterID rd
, RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
1042 ASSERT(!BadReg(rd
));
1043 ASSERT(!BadReg(rn
));
1044 ASSERT(!BadReg(rm
));
1045 m_formatter
.twoWordOp12Reg4FourFours(OP_EOR_reg_T2
, rn
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
1048 // xor is not spelled with an 'e'. :-(
1049 void eor(RegisterID rd
, RegisterID rn
, RegisterID rm
)
1051 if ((rd
== rn
) && !((rd
| rm
) & 8))
1052 m_formatter
.oneWordOp10Reg3Reg3(OP_EOR_reg_T1
, rm
, rd
);
1053 else if ((rd
== rm
) && !((rd
| rn
) & 8))
1054 m_formatter
.oneWordOp10Reg3Reg3(OP_EOR_reg_T1
, rn
, rd
);
1056 eor(rd
, rn
, rm
, ShiftTypeAndAmount());
1059 ALWAYS_INLINE
void it(Condition cond
)
1061 m_formatter
.oneWordOp8Imm8(OP_IT
, ifThenElse(cond
));
1064 ALWAYS_INLINE
void it(Condition cond
, bool inst2if
)
1066 m_formatter
.oneWordOp8Imm8(OP_IT
, ifThenElse(cond
, inst2if
));
1069 ALWAYS_INLINE
void it(Condition cond
, bool inst2if
, bool inst3if
)
1071 m_formatter
.oneWordOp8Imm8(OP_IT
, ifThenElse(cond
, inst2if
, inst3if
));
1074 ALWAYS_INLINE
void it(Condition cond
, bool inst2if
, bool inst3if
, bool inst4if
)
1076 m_formatter
.oneWordOp8Imm8(OP_IT
, ifThenElse(cond
, inst2if
, inst3if
, inst4if
));
1079 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1080 ALWAYS_INLINE
void ldr(RegisterID rt
, RegisterID rn
, ARMThumbImmediate imm
)
1082 ASSERT(rn
!= ARMRegisters::pc
); // LDR (literal)
1083 ASSERT(imm
.isUInt12());
1085 if (!((rt
| rn
) & 8) && imm
.isUInt7())
1086 m_formatter
.oneWordOp5Imm5Reg3Reg3(OP_LDR_imm_T1
, imm
.getUInt7() >> 2, rn
, rt
);
1087 else if ((rn
== ARMRegisters::sp
) && !(rt
& 8) && imm
.isUInt10())
1088 m_formatter
.oneWordOp5Reg3Imm8(OP_LDR_imm_T2
, rt
, static_cast<uint8_t>(imm
.getUInt10() >> 2));
1090 m_formatter
.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T3
, rn
, rt
, imm
.getUInt12());
1093 ALWAYS_INLINE
void ldrWide8BitImmediate(RegisterID rt
, RegisterID rn
, uint8_t immediate
)
1095 ASSERT(rn
!= ARMRegisters::pc
);
1096 m_formatter
.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T3
, rn
, rt
, immediate
);
1099 ALWAYS_INLINE
void ldrCompact(RegisterID rt
, RegisterID rn
, ARMThumbImmediate imm
)
1101 ASSERT(rn
!= ARMRegisters::pc
); // LDR (literal)
1102 ASSERT(imm
.isUInt7());
1103 ASSERT(!((rt
| rn
) & 8));
1104 m_formatter
.oneWordOp5Imm5Reg3Reg3(OP_LDR_imm_T1
, imm
.getUInt7() >> 2, rn
, rt
);
1107 // If index is set, this is a regular offset or a pre-indexed load;
1108 // if index is not set then is is a post-index load.
1110 // If wback is set rn is updated - this is a pre or post index load,
1111 // if wback is not set this is a regular offset memory access.
1113 // (-255 <= offset <= 255)
1115 // _tmp = _reg + offset
1116 // MEM[index ? _tmp : _reg] = REG[rt]
1117 // if (wback) REG[rn] = _tmp
1118 ALWAYS_INLINE
void ldr(RegisterID rt
, RegisterID rn
, int offset
, bool index
, bool wback
)
1120 ASSERT(rt
!= ARMRegisters::pc
);
1121 ASSERT(rn
!= ARMRegisters::pc
);
1122 ASSERT(index
|| wback
);
1123 ASSERT(!wback
| (rt
!= rn
));
1130 ASSERT((offset
& ~0xff) == 0);
1132 offset
|= (wback
<< 8);
1133 offset
|= (add
<< 9);
1134 offset
|= (index
<< 10);
1135 offset
|= (1 << 11);
1137 m_formatter
.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T4
, rn
, rt
, offset
);
1140 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1141 ALWAYS_INLINE
void ldr(RegisterID rt
, RegisterID rn
, RegisterID rm
, unsigned shift
= 0)
1143 ASSERT(rn
!= ARMRegisters::pc
); // LDR (literal)
1144 ASSERT(!BadReg(rm
));
1147 if (!shift
&& !((rt
| rn
| rm
) & 8))
1148 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_LDR_reg_T1
, rm
, rn
, rt
);
1150 m_formatter
.twoWordOp12Reg4FourFours(OP_LDR_reg_T2
, rn
, FourFours(rt
, 0, shift
, rm
));
1153 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1154 ALWAYS_INLINE
void ldrh(RegisterID rt
, RegisterID rn
, ARMThumbImmediate imm
)
1156 ASSERT(rn
!= ARMRegisters::pc
); // LDR (literal)
1157 ASSERT(imm
.isUInt12());
1158 ASSERT(!(imm
.getUInt12() & 1));
1160 if (!((rt
| rn
) & 8) && imm
.isUInt6())
1161 m_formatter
.oneWordOp5Imm5Reg3Reg3(OP_LDRH_imm_T1
, imm
.getUInt6() >> 1, rn
, rt
);
1163 m_formatter
.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T2
, rn
, rt
, imm
.getUInt12());
1166 // If index is set, this is a regular offset or a pre-indexed load;
1167 // if index is not set then is is a post-index load.
1169 // If wback is set rn is updated - this is a pre or post index load,
1170 // if wback is not set this is a regular offset memory access.
1172 // (-255 <= offset <= 255)
1174 // _tmp = _reg + offset
1175 // MEM[index ? _tmp : _reg] = REG[rt]
1176 // if (wback) REG[rn] = _tmp
1177 ALWAYS_INLINE
void ldrh(RegisterID rt
, RegisterID rn
, int offset
, bool index
, bool wback
)
1179 ASSERT(rt
!= ARMRegisters::pc
);
1180 ASSERT(rn
!= ARMRegisters::pc
);
1181 ASSERT(index
|| wback
);
1182 ASSERT(!wback
| (rt
!= rn
));
1189 ASSERT((offset
& ~0xff) == 0);
1191 offset
|= (wback
<< 8);
1192 offset
|= (add
<< 9);
1193 offset
|= (index
<< 10);
1194 offset
|= (1 << 11);
1196 m_formatter
.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T3
, rn
, rt
, offset
);
1199 ALWAYS_INLINE
void ldrh(RegisterID rt
, RegisterID rn
, RegisterID rm
, unsigned shift
= 0)
1201 ASSERT(!BadReg(rt
)); // Memory hint
1202 ASSERT(rn
!= ARMRegisters::pc
); // LDRH (literal)
1203 ASSERT(!BadReg(rm
));
1206 if (!shift
&& !((rt
| rn
| rm
) & 8))
1207 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_LDRH_reg_T1
, rm
, rn
, rt
);
1209 m_formatter
.twoWordOp12Reg4FourFours(OP_LDRH_reg_T2
, rn
, FourFours(rt
, 0, shift
, rm
));
1212 void ldrb(RegisterID rt
, RegisterID rn
, ARMThumbImmediate imm
)
1214 ASSERT(rn
!= ARMRegisters::pc
); // LDR (literal)
1215 ASSERT(imm
.isUInt12());
1217 if (!((rt
| rn
) & 8) && imm
.isUInt5())
1218 m_formatter
.oneWordOp5Imm5Reg3Reg3(OP_LDRB_imm_T1
, imm
.getUInt5(), rn
, rt
);
1220 m_formatter
.twoWordOp12Reg4Reg4Imm12(OP_LDRB_imm_T2
, rn
, rt
, imm
.getUInt12());
1223 void ldrb(RegisterID rt
, RegisterID rn
, int offset
, bool index
, bool wback
)
1225 ASSERT(rt
!= ARMRegisters::pc
);
1226 ASSERT(rn
!= ARMRegisters::pc
);
1227 ASSERT(index
|| wback
);
1228 ASSERT(!wback
| (rt
!= rn
));
1236 ASSERT(!(offset
& ~0xff));
1238 offset
|= (wback
<< 8);
1239 offset
|= (add
<< 9);
1240 offset
|= (index
<< 10);
1241 offset
|= (1 << 11);
1243 m_formatter
.twoWordOp12Reg4Reg4Imm12(OP_LDRB_imm_T3
, rn
, rt
, offset
);
1246 ALWAYS_INLINE
void ldrb(RegisterID rt
, RegisterID rn
, RegisterID rm
, unsigned shift
= 0)
1248 ASSERT(rn
!= ARMRegisters::pc
); // LDR (literal)
1249 ASSERT(!BadReg(rm
));
1252 if (!shift
&& !((rt
| rn
| rm
) & 8))
1253 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_LDRB_reg_T1
, rm
, rn
, rt
);
1255 m_formatter
.twoWordOp12Reg4FourFours(OP_LDRB_reg_T2
, rn
, FourFours(rt
, 0, shift
, rm
));
1258 void ldrsb(RegisterID rt
, RegisterID rn
, RegisterID rm
, unsigned shift
= 0)
1260 ASSERT(rn
!= ARMRegisters::pc
);
1261 ASSERT(!BadReg(rm
));
1264 if (!shift
&& !((rt
| rn
| rm
) & 8))
1265 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_LDRSB_reg_T1
, rm
, rn
, rt
);
1267 m_formatter
.twoWordOp12Reg4FourFours(OP_LDRSB_reg_T2
, rn
, FourFours(rt
, 0, shift
, rm
));
1270 void ldrsh(RegisterID rt
, RegisterID rn
, RegisterID rm
, unsigned shift
= 0)
1272 ASSERT(rn
!= ARMRegisters::pc
);
1273 ASSERT(!BadReg(rm
));
1276 if (!shift
&& !((rt
| rn
| rm
) & 8))
1277 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_LDRSH_reg_T1
, rm
, rn
, rt
);
1279 m_formatter
.twoWordOp12Reg4FourFours(OP_LDRSH_reg_T2
, rn
, FourFours(rt
, 0, shift
, rm
));
1282 void lsl(RegisterID rd
, RegisterID rm
, int32_t shiftAmount
)
1284 ASSERT(!BadReg(rd
));
1285 ASSERT(!BadReg(rm
));
1286 ShiftTypeAndAmount
shift(SRType_LSL
, shiftAmount
);
1287 m_formatter
.twoWordOp16FourFours(OP_LSL_imm_T1
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
1290 ALWAYS_INLINE
void lsl(RegisterID rd
, RegisterID rn
, RegisterID rm
)
1292 ASSERT(!BadReg(rd
));
1293 ASSERT(!BadReg(rn
));
1294 ASSERT(!BadReg(rm
));
1295 m_formatter
.twoWordOp12Reg4FourFours(OP_LSL_reg_T2
, rn
, FourFours(0xf, rd
, 0, rm
));
1298 ALWAYS_INLINE
void lsr(RegisterID rd
, RegisterID rm
, int32_t shiftAmount
)
1300 ASSERT(!BadReg(rd
));
1301 ASSERT(!BadReg(rm
));
1302 ShiftTypeAndAmount
shift(SRType_LSR
, shiftAmount
);
1303 m_formatter
.twoWordOp16FourFours(OP_LSR_imm_T1
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
1306 ALWAYS_INLINE
void lsr(RegisterID rd
, RegisterID rn
, RegisterID rm
)
1308 ASSERT(!BadReg(rd
));
1309 ASSERT(!BadReg(rn
));
1310 ASSERT(!BadReg(rm
));
1311 m_formatter
.twoWordOp12Reg4FourFours(OP_LSR_reg_T2
, rn
, FourFours(0xf, rd
, 0, rm
));
1314 ALWAYS_INLINE
void movT3(RegisterID rd
, ARMThumbImmediate imm
)
1316 ASSERT(imm
.isValid());
1317 ASSERT(!imm
.isEncodedImm());
1318 ASSERT(!BadReg(rd
));
1320 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T3
, imm
.m_value
.imm4
, rd
, imm
);
1324 static void revertJumpTo_movT3movtcmpT2(void* instructionStart
, RegisterID left
, RegisterID right
, uintptr_t imm
)
1326 uint16_t* address
= static_cast<uint16_t*>(instructionStart
);
1327 ARMThumbImmediate lo16
= ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(imm
));
1328 ARMThumbImmediate hi16
= ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(imm
>> 16));
1329 address
[0] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3
, lo16
);
1330 address
[1] = twoWordOp5i6Imm4Reg4EncodedImmSecond(right
, lo16
);
1331 address
[2] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT
, hi16
);
1332 address
[3] = twoWordOp5i6Imm4Reg4EncodedImmSecond(right
, hi16
);
1333 address
[4] = OP_CMP_reg_T2
| left
;
1334 cacheFlush(address
, sizeof(uint16_t) * 5);
1337 static void revertJumpTo_movT3(void* instructionStart
, RegisterID rd
, ARMThumbImmediate imm
)
1339 ASSERT(imm
.isValid());
1340 ASSERT(!imm
.isEncodedImm());
1341 ASSERT(!BadReg(rd
));
1343 uint16_t* address
= static_cast<uint16_t*>(instructionStart
);
1344 address
[0] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3
, imm
);
1345 address
[1] = twoWordOp5i6Imm4Reg4EncodedImmSecond(rd
, imm
);
1346 cacheFlush(address
, sizeof(uint16_t) * 2);
1350 ALWAYS_INLINE
void mov(RegisterID rd
, ARMThumbImmediate imm
)
1352 ASSERT(imm
.isValid());
1353 ASSERT(!BadReg(rd
));
1355 if ((rd
< 8) && imm
.isUInt8())
1356 m_formatter
.oneWordOp5Reg3Imm8(OP_MOV_imm_T1
, rd
, imm
.getUInt8());
1357 else if (imm
.isEncodedImm())
1358 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T2
, 0xf, rd
, imm
);
1363 ALWAYS_INLINE
void mov(RegisterID rd
, RegisterID rm
)
1365 m_formatter
.oneWordOp8RegReg143(OP_MOV_reg_T1
, rm
, rd
);
1368 ALWAYS_INLINE
void movt(RegisterID rd
, ARMThumbImmediate imm
)
1370 ASSERT(imm
.isUInt16());
1371 ASSERT(!BadReg(rd
));
1372 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOVT
, imm
.m_value
.imm4
, rd
, imm
);
1375 ALWAYS_INLINE
void mvn(RegisterID rd
, ARMThumbImmediate imm
)
1377 ASSERT(imm
.isEncodedImm());
1378 ASSERT(!BadReg(rd
));
1380 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_MVN_imm
, 0xf, rd
, imm
);
1383 ALWAYS_INLINE
void mvn(RegisterID rd
, RegisterID rm
, ShiftTypeAndAmount shift
)
1385 ASSERT(!BadReg(rd
));
1386 ASSERT(!BadReg(rm
));
1387 m_formatter
.twoWordOp16FourFours(OP_MVN_reg_T2
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
1390 ALWAYS_INLINE
void mvn(RegisterID rd
, RegisterID rm
)
1392 if (!((rd
| rm
) & 8))
1393 m_formatter
.oneWordOp10Reg3Reg3(OP_MVN_reg_T1
, rm
, rd
);
1395 mvn(rd
, rm
, ShiftTypeAndAmount());
1398 ALWAYS_INLINE
void neg(RegisterID rd
, RegisterID rm
)
1400 ARMThumbImmediate zero
= ARMThumbImmediate::makeUInt12(0);
1404 ALWAYS_INLINE
void orr(RegisterID rd
, RegisterID rn
, ARMThumbImmediate imm
)
1406 ASSERT(!BadReg(rd
));
1407 ASSERT(!BadReg(rn
));
1408 ASSERT(imm
.isEncodedImm());
1409 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_ORR_imm_T1
, rn
, rd
, imm
);
1412 ALWAYS_INLINE
void orr(RegisterID rd
, RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
1414 ASSERT(!BadReg(rd
));
1415 ASSERT(!BadReg(rn
));
1416 ASSERT(!BadReg(rm
));
1417 m_formatter
.twoWordOp12Reg4FourFours(OP_ORR_reg_T2
, rn
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
1420 void orr(RegisterID rd
, RegisterID rn
, RegisterID rm
)
1422 if ((rd
== rn
) && !((rd
| rm
) & 8))
1423 m_formatter
.oneWordOp10Reg3Reg3(OP_ORR_reg_T1
, rm
, rd
);
1424 else if ((rd
== rm
) && !((rd
| rn
) & 8))
1425 m_formatter
.oneWordOp10Reg3Reg3(OP_ORR_reg_T1
, rn
, rd
);
1427 orr(rd
, rn
, rm
, ShiftTypeAndAmount());
1430 ALWAYS_INLINE
void orr_S(RegisterID rd
, RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
1432 ASSERT(!BadReg(rd
));
1433 ASSERT(!BadReg(rn
));
1434 ASSERT(!BadReg(rm
));
1435 m_formatter
.twoWordOp12Reg4FourFours(OP_ORR_S_reg_T2
, rn
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
1438 void orr_S(RegisterID rd
, RegisterID rn
, RegisterID rm
)
1440 if ((rd
== rn
) && !((rd
| rm
) & 8))
1441 m_formatter
.oneWordOp10Reg3Reg3(OP_ORR_reg_T1
, rm
, rd
);
1442 else if ((rd
== rm
) && !((rd
| rn
) & 8))
1443 m_formatter
.oneWordOp10Reg3Reg3(OP_ORR_reg_T1
, rn
, rd
);
1445 orr_S(rd
, rn
, rm
, ShiftTypeAndAmount());
1448 ALWAYS_INLINE
void ror(RegisterID rd
, RegisterID rm
, int32_t shiftAmount
)
1450 ASSERT(!BadReg(rd
));
1451 ASSERT(!BadReg(rm
));
1452 ShiftTypeAndAmount
shift(SRType_ROR
, shiftAmount
);
1453 m_formatter
.twoWordOp16FourFours(OP_ROR_imm_T1
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
1456 ALWAYS_INLINE
void ror(RegisterID rd
, RegisterID rn
, RegisterID rm
)
1458 ASSERT(!BadReg(rd
));
1459 ASSERT(!BadReg(rn
));
1460 ASSERT(!BadReg(rm
));
1461 m_formatter
.twoWordOp12Reg4FourFours(OP_ROR_reg_T2
, rn
, FourFours(0xf, rd
, 0, rm
));
1464 ALWAYS_INLINE
void pop(RegisterID dest
)
1466 if (dest
< ARMRegisters::r8
)
1467 m_formatter
.oneWordOp7Imm9(OP_POP_T1
, 1 << dest
);
1469 // Load postindexed with writeback.
1470 ldr(dest
, ARMRegisters::sp
, sizeof(void*), false, true);
1474 ALWAYS_INLINE
void pop(uint32_t registerList
)
1476 ASSERT(WTF::bitCount(registerList
) > 1);
1477 ASSERT(!((1 << ARMRegisters::pc
) & registerList
) || !((1 << ARMRegisters::lr
) & registerList
));
1478 ASSERT(!((1 << ARMRegisters::sp
) & registerList
));
1479 m_formatter
.twoWordOp16Imm16(OP_POP_T2
, registerList
);
1482 ALWAYS_INLINE
void push(RegisterID src
)
1484 if (src
< ARMRegisters::r8
)
1485 m_formatter
.oneWordOp7Imm9(OP_PUSH_T1
, 1 << src
);
1486 else if (src
== ARMRegisters::lr
)
1487 m_formatter
.oneWordOp7Imm9(OP_PUSH_T1
, 0x100);
1489 // Store preindexed with writeback.
1490 str(src
, ARMRegisters::sp
, -sizeof(void*), true, true);
1494 ALWAYS_INLINE
void push(uint32_t registerList
)
1496 ASSERT(WTF::bitCount(registerList
) > 1);
1497 ASSERT(!((1 << ARMRegisters::pc
) & registerList
));
1498 ASSERT(!((1 << ARMRegisters::sp
) & registerList
));
1499 m_formatter
.twoWordOp16Imm16(OP_PUSH_T2
, registerList
);
1502 #if HAVE(ARM_IDIV_INSTRUCTIONS)
1503 template<int datasize
>
1504 ALWAYS_INLINE
void sdiv(RegisterID rd
, RegisterID rn
, RegisterID rm
)
1506 static_assert(datasize
== 32, "sdiv datasize must be 32 for armv7s");
1507 ASSERT(!BadReg(rd
));
1508 ASSERT(!BadReg(rn
));
1509 ASSERT(!BadReg(rm
));
1510 m_formatter
.twoWordOp12Reg4FourFours(OP_SDIV_T1
, rn
, FourFours(0xf, rd
, 0xf, rm
));
1514 ALWAYS_INLINE
void smull(RegisterID rdLo
, RegisterID rdHi
, RegisterID rn
, RegisterID rm
)
1516 ASSERT(!BadReg(rdLo
));
1517 ASSERT(!BadReg(rdHi
));
1518 ASSERT(!BadReg(rn
));
1519 ASSERT(!BadReg(rm
));
1520 ASSERT(rdLo
!= rdHi
);
1521 m_formatter
.twoWordOp12Reg4FourFours(OP_SMULL_T1
, rn
, FourFours(rdLo
, rdHi
, 0, rm
));
1524 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1525 ALWAYS_INLINE
void str(RegisterID rt
, RegisterID rn
, ARMThumbImmediate imm
)
1527 ASSERT(rt
!= ARMRegisters::pc
);
1528 ASSERT(rn
!= ARMRegisters::pc
);
1529 ASSERT(imm
.isUInt12());
1531 if (!((rt
| rn
) & 8) && imm
.isUInt7())
1532 m_formatter
.oneWordOp5Imm5Reg3Reg3(OP_STR_imm_T1
, imm
.getUInt7() >> 2, rn
, rt
);
1533 else if ((rn
== ARMRegisters::sp
) && !(rt
& 8) && imm
.isUInt10())
1534 m_formatter
.oneWordOp5Reg3Imm8(OP_STR_imm_T2
, rt
, static_cast<uint8_t>(imm
.getUInt10() >> 2));
1536 m_formatter
.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T3
, rn
, rt
, imm
.getUInt12());
1539 // If index is set, this is a regular offset or a pre-indexed store;
1540 // if index is not set then is is a post-index store.
1542 // If wback is set rn is updated - this is a pre or post index store,
1543 // if wback is not set this is a regular offset memory access.
1545 // (-255 <= offset <= 255)
1547 // _tmp = _reg + offset
1548 // MEM[index ? _tmp : _reg] = REG[rt]
1549 // if (wback) REG[rn] = _tmp
1550 ALWAYS_INLINE
void str(RegisterID rt
, RegisterID rn
, int offset
, bool index
, bool wback
)
1552 ASSERT(rt
!= ARMRegisters::pc
);
1553 ASSERT(rn
!= ARMRegisters::pc
);
1554 ASSERT(index
|| wback
);
1555 ASSERT(!wback
| (rt
!= rn
));
1562 ASSERT((offset
& ~0xff) == 0);
1564 offset
|= (wback
<< 8);
1565 offset
|= (add
<< 9);
1566 offset
|= (index
<< 10);
1567 offset
|= (1 << 11);
1569 m_formatter
.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T4
, rn
, rt
, offset
);
1572 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1573 ALWAYS_INLINE
void str(RegisterID rt
, RegisterID rn
, RegisterID rm
, unsigned shift
= 0)
1575 ASSERT(rn
!= ARMRegisters::pc
);
1576 ASSERT(!BadReg(rm
));
1579 if (!shift
&& !((rt
| rn
| rm
) & 8))
1580 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_STR_reg_T1
, rm
, rn
, rt
);
1582 m_formatter
.twoWordOp12Reg4FourFours(OP_STR_reg_T2
, rn
, FourFours(rt
, 0, shift
, rm
));
1585 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1586 ALWAYS_INLINE
void strb(RegisterID rt
, RegisterID rn
, ARMThumbImmediate imm
)
1588 ASSERT(rt
!= ARMRegisters::pc
);
1589 ASSERT(rn
!= ARMRegisters::pc
);
1590 ASSERT(imm
.isUInt12());
1592 if (!((rt
| rn
) & 8) && imm
.isUInt7())
1593 m_formatter
.oneWordOp5Imm5Reg3Reg3(OP_STRB_imm_T1
, imm
.getUInt7() >> 2, rn
, rt
);
1595 m_formatter
.twoWordOp12Reg4Reg4Imm12(OP_STRB_imm_T2
, rn
, rt
, imm
.getUInt12());
1598 // If index is set, this is a regular offset or a pre-indexed store;
1599 // if index is not set then is is a post-index store.
1601 // If wback is set rn is updated - this is a pre or post index store,
1602 // if wback is not set this is a regular offset memory access.
1604 // (-255 <= offset <= 255)
1606 // _tmp = _reg + offset
1607 // MEM[index ? _tmp : _reg] = REG[rt]
1608 // if (wback) REG[rn] = _tmp
1609 ALWAYS_INLINE
void strb(RegisterID rt
, RegisterID rn
, int offset
, bool index
, bool wback
)
1611 ASSERT(rt
!= ARMRegisters::pc
);
1612 ASSERT(rn
!= ARMRegisters::pc
);
1613 ASSERT(index
|| wback
);
1614 ASSERT(!wback
| (rt
!= rn
));
1621 ASSERT((offset
& ~0xff) == 0);
1623 offset
|= (wback
<< 8);
1624 offset
|= (add
<< 9);
1625 offset
|= (index
<< 10);
1626 offset
|= (1 << 11);
1628 m_formatter
.twoWordOp12Reg4Reg4Imm12(OP_STRB_imm_T3
, rn
, rt
, offset
);
1631 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1632 ALWAYS_INLINE
void strb(RegisterID rt
, RegisterID rn
, RegisterID rm
, unsigned shift
= 0)
1634 ASSERT(rn
!= ARMRegisters::pc
);
1635 ASSERT(!BadReg(rm
));
1638 if (!shift
&& !((rt
| rn
| rm
) & 8))
1639 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_STRB_reg_T1
, rm
, rn
, rt
);
1641 m_formatter
.twoWordOp12Reg4FourFours(OP_STRB_reg_T2
, rn
, FourFours(rt
, 0, shift
, rm
));
1644 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1645 ALWAYS_INLINE
void strh(RegisterID rt
, RegisterID rn
, ARMThumbImmediate imm
)
1647 ASSERT(rt
!= ARMRegisters::pc
);
1648 ASSERT(rn
!= ARMRegisters::pc
);
1649 ASSERT(imm
.isUInt12());
1651 if (!((rt
| rn
) & 8) && imm
.isUInt6())
1652 m_formatter
.oneWordOp5Imm5Reg3Reg3(OP_STRH_imm_T1
, imm
.getUInt6() >> 1, rn
, rt
);
1654 m_formatter
.twoWordOp12Reg4Reg4Imm12(OP_STRH_imm_T2
, rn
, rt
, imm
.getUInt12());
1657 // If index is set, this is a regular offset or a pre-indexed store;
1658 // if index is not set then is is a post-index store.
1660 // If wback is set rn is updated - this is a pre or post index store,
1661 // if wback is not set this is a regular offset memory access.
1663 // (-255 <= offset <= 255)
1665 // _tmp = _reg + offset
1666 // MEM[index ? _tmp : _reg] = REG[rt]
1667 // if (wback) REG[rn] = _tmp
1668 ALWAYS_INLINE
void strh(RegisterID rt
, RegisterID rn
, int offset
, bool index
, bool wback
)
1670 ASSERT(rt
!= ARMRegisters::pc
);
1671 ASSERT(rn
!= ARMRegisters::pc
);
1672 ASSERT(index
|| wback
);
1673 ASSERT(!wback
| (rt
!= rn
));
1680 ASSERT(!(offset
& ~0xff));
1682 offset
|= (wback
<< 8);
1683 offset
|= (add
<< 9);
1684 offset
|= (index
<< 10);
1685 offset
|= (1 << 11);
1687 m_formatter
.twoWordOp12Reg4Reg4Imm12(OP_STRH_imm_T3
, rn
, rt
, offset
);
1690 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
1691 ALWAYS_INLINE
void strh(RegisterID rt
, RegisterID rn
, RegisterID rm
, unsigned shift
= 0)
1693 ASSERT(rn
!= ARMRegisters::pc
);
1694 ASSERT(!BadReg(rm
));
1697 if (!shift
&& !((rt
| rn
| rm
) & 8))
1698 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_STRH_reg_T1
, rm
, rn
, rt
);
1700 m_formatter
.twoWordOp12Reg4FourFours(OP_STRH_reg_T2
, rn
, FourFours(rt
, 0, shift
, rm
));
1703 ALWAYS_INLINE
void sub(RegisterID rd
, RegisterID rn
, ARMThumbImmediate imm
)
1705 // Rd can only be SP if Rn is also SP.
1706 ASSERT((rd
!= ARMRegisters::sp
) || (rn
== ARMRegisters::sp
));
1707 ASSERT(rd
!= ARMRegisters::pc
);
1708 ASSERT(rn
!= ARMRegisters::pc
);
1709 ASSERT(imm
.isValid());
1711 if ((rn
== ARMRegisters::sp
) && (rd
== ARMRegisters::sp
) && imm
.isUInt9()) {
1712 ASSERT(!(imm
.getUInt16() & 3));
1713 m_formatter
.oneWordOp9Imm7(OP_SUB_SP_imm_T1
, static_cast<uint8_t>(imm
.getUInt9() >> 2));
1715 } else if (!((rd
| rn
) & 8)) {
1716 if (imm
.isUInt3()) {
1717 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_SUB_imm_T1
, (RegisterID
)imm
.getUInt3(), rn
, rd
);
1719 } else if ((rd
== rn
) && imm
.isUInt8()) {
1720 m_formatter
.oneWordOp5Reg3Imm8(OP_SUB_imm_T2
, rd
, imm
.getUInt8());
1725 if (imm
.isEncodedImm())
1726 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T3
, rn
, rd
, imm
);
1728 ASSERT(imm
.isUInt12());
1729 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T4
, rn
, rd
, imm
);
1733 ALWAYS_INLINE
void sub(RegisterID rd
, ARMThumbImmediate imm
, RegisterID rn
)
1735 ASSERT(rd
!= ARMRegisters::pc
);
1736 ASSERT(rn
!= ARMRegisters::pc
);
1737 ASSERT(imm
.isValid());
1738 ASSERT(imm
.isUInt12());
1740 if (!((rd
| rn
) & 8) && !imm
.getUInt12())
1741 m_formatter
.oneWordOp10Reg3Reg3(OP_RSB_imm_T1
, rn
, rd
);
1743 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_RSB_imm_T2
, rn
, rd
, imm
);
1746 ALWAYS_INLINE
void sub(RegisterID rd
, RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
1748 ASSERT((rd
!= ARMRegisters::sp
) || (rn
== ARMRegisters::sp
));
1749 ASSERT(rd
!= ARMRegisters::pc
);
1750 ASSERT(rn
!= ARMRegisters::pc
);
1751 ASSERT(!BadReg(rm
));
1752 m_formatter
.twoWordOp12Reg4FourFours(OP_SUB_reg_T2
, rn
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
1755 // NOTE: In an IT block, add doesn't modify the flags register.
1756 ALWAYS_INLINE
void sub(RegisterID rd
, RegisterID rn
, RegisterID rm
)
1758 if (!((rd
| rn
| rm
) & 8))
1759 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_SUB_reg_T1
, rm
, rn
, rd
);
1761 sub(rd
, rn
, rm
, ShiftTypeAndAmount());
1764 // Not allowed in an IT (if then) block.
1765 void sub_S(RegisterID rd
, RegisterID rn
, ARMThumbImmediate imm
)
1767 // Rd can only be SP if Rn is also SP.
1768 ASSERT((rd
!= ARMRegisters::sp
) || (rn
== ARMRegisters::sp
));
1769 ASSERT(rd
!= ARMRegisters::pc
);
1770 ASSERT(rn
!= ARMRegisters::pc
);
1771 ASSERT(imm
.isValid());
1773 if ((rn
== ARMRegisters::sp
) && (rd
== ARMRegisters::sp
) && imm
.isUInt9()) {
1774 ASSERT(!(imm
.getUInt16() & 3));
1775 m_formatter
.oneWordOp9Imm7(OP_SUB_SP_imm_T1
, static_cast<uint8_t>(imm
.getUInt9() >> 2));
1777 } else if (!((rd
| rn
) & 8)) {
1778 if (imm
.isUInt3()) {
1779 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_SUB_imm_T1
, (RegisterID
)imm
.getUInt3(), rn
, rd
);
1781 } else if ((rd
== rn
) && imm
.isUInt8()) {
1782 m_formatter
.oneWordOp5Reg3Imm8(OP_SUB_imm_T2
, rd
, imm
.getUInt8());
1787 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_S_imm_T3
, rn
, rd
, imm
);
1790 ALWAYS_INLINE
void sub_S(RegisterID rd
, ARMThumbImmediate imm
, RegisterID rn
)
1792 ASSERT(rd
!= ARMRegisters::pc
);
1793 ASSERT(rn
!= ARMRegisters::pc
);
1794 ASSERT(imm
.isValid());
1795 ASSERT(imm
.isUInt12());
1797 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_RSB_S_imm_T2
, rn
, rd
, imm
);
1800 // Not allowed in an IT (if then) block?
1801 ALWAYS_INLINE
void sub_S(RegisterID rd
, RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
1803 ASSERT((rd
!= ARMRegisters::sp
) || (rn
== ARMRegisters::sp
));
1804 ASSERT(rd
!= ARMRegisters::pc
);
1805 ASSERT(rn
!= ARMRegisters::pc
);
1806 ASSERT(!BadReg(rm
));
1807 m_formatter
.twoWordOp12Reg4FourFours(OP_SUB_S_reg_T2
, rn
, FourFours(shift
.hi4(), rd
, shift
.lo4(), rm
));
1810 // Not allowed in an IT (if then) block.
1811 ALWAYS_INLINE
void sub_S(RegisterID rd
, RegisterID rn
, RegisterID rm
)
1813 if (!((rd
| rn
| rm
) & 8))
1814 m_formatter
.oneWordOp7Reg3Reg3Reg3(OP_SUB_reg_T1
, rm
, rn
, rd
);
1816 sub_S(rd
, rn
, rm
, ShiftTypeAndAmount());
1819 ALWAYS_INLINE
void tst(RegisterID rn
, ARMThumbImmediate imm
)
1821 ASSERT(!BadReg(rn
));
1822 ASSERT(imm
.isEncodedImm());
1824 m_formatter
.twoWordOp5i6Imm4Reg4EncodedImm(OP_TST_imm
, rn
, (RegisterID
)0xf, imm
);
1827 ALWAYS_INLINE
void tst(RegisterID rn
, RegisterID rm
, ShiftTypeAndAmount shift
)
1829 ASSERT(!BadReg(rn
));
1830 ASSERT(!BadReg(rm
));
1831 m_formatter
.twoWordOp12Reg4FourFours(OP_TST_reg_T2
, rn
, FourFours(shift
.hi4(), 0xf, shift
.lo4(), rm
));
1834 ALWAYS_INLINE
void tst(RegisterID rn
, RegisterID rm
)
1837 tst(rn
, rm
, ShiftTypeAndAmount());
1839 m_formatter
.oneWordOp10Reg3Reg3(OP_TST_reg_T1
, rm
, rn
);
1842 ALWAYS_INLINE
void ubfx(RegisterID rd
, RegisterID rn
, unsigned lsb
, unsigned width
)
1845 ASSERT((width
>= 1) && (width
<= 32));
1846 ASSERT((lsb
+ width
) <= 32);
1847 m_formatter
.twoWordOp12Reg40Imm3Reg4Imm20Imm5(OP_UBFX_T1
, rd
, rn
, (lsb
& 0x1c) << 10, (lsb
& 0x3) << 6, (width
- 1) & 0x1f);
1850 #if HAVE(ARM_IDIV_INSTRUCTIONS)
1851 ALWAYS_INLINE
void udiv(RegisterID rd
, RegisterID rn
, RegisterID rm
)
1853 ASSERT(!BadReg(rd
));
1854 ASSERT(!BadReg(rn
));
1855 ASSERT(!BadReg(rm
));
1856 m_formatter
.twoWordOp12Reg4FourFours(OP_UDIV_T1
, rn
, FourFours(0xf, rd
, 0xf, rm
));
1860 void vadd(FPDoubleRegisterID rd
, FPDoubleRegisterID rn
, FPDoubleRegisterID rm
)
1862 m_formatter
.vfpOp(OP_VADD_T2
, OP_VADD_T2b
, true, rn
, rd
, rm
);
1865 void vcmp(FPDoubleRegisterID rd
, FPDoubleRegisterID rm
)
1867 m_formatter
.vfpOp(OP_VCMP
, OP_VCMPb
, true, VFPOperand(4), rd
, rm
);
1870 void vcmpz(FPDoubleRegisterID rd
)
1872 m_formatter
.vfpOp(OP_VCMP
, OP_VCMPb
, true, VFPOperand(5), rd
, VFPOperand(0));
1875 void vcvt_signedToFloatingPoint(FPDoubleRegisterID rd
, FPSingleRegisterID rm
)
1877 // boolean values are 64bit (toInt, unsigned, roundZero)
1878 m_formatter
.vfpOp(OP_VCVT_FPIVFP
, OP_VCVT_FPIVFPb
, true, vcvtOp(false, false, false), rd
, rm
);
1881 void vcvt_floatingPointToSigned(FPSingleRegisterID rd
, FPDoubleRegisterID rm
)
1883 // boolean values are 64bit (toInt, unsigned, roundZero)
1884 m_formatter
.vfpOp(OP_VCVT_FPIVFP
, OP_VCVT_FPIVFPb
, true, vcvtOp(true, false, true), rd
, rm
);
1887 void vcvt_floatingPointToUnsigned(FPSingleRegisterID rd
, FPDoubleRegisterID rm
)
1889 // boolean values are 64bit (toInt, unsigned, roundZero)
1890 m_formatter
.vfpOp(OP_VCVT_FPIVFP
, OP_VCVT_FPIVFPb
, true, vcvtOp(true, true, true), rd
, rm
);
1893 void vdiv(FPDoubleRegisterID rd
, FPDoubleRegisterID rn
, FPDoubleRegisterID rm
)
1895 m_formatter
.vfpOp(OP_VDIV
, OP_VDIVb
, true, rn
, rd
, rm
);
1898 void vldr(FPDoubleRegisterID rd
, RegisterID rn
, int32_t imm
)
1900 m_formatter
.vfpMemOp(OP_VLDR
, OP_VLDRb
, true, rn
, rd
, imm
);
1903 void flds(FPSingleRegisterID rd
, RegisterID rn
, int32_t imm
)
1905 m_formatter
.vfpMemOp(OP_FLDS
, OP_FLDSb
, false, rn
, rd
, imm
);
1908 void vmov(RegisterID rd
, FPSingleRegisterID rn
)
1910 ASSERT(!BadReg(rd
));
1911 m_formatter
.vfpOp(OP_VMOV_StoC
, OP_VMOV_StoCb
, false, rn
, rd
, VFPOperand(0));
1914 void vmov(FPSingleRegisterID rd
, RegisterID rn
)
1916 ASSERT(!BadReg(rn
));
1917 m_formatter
.vfpOp(OP_VMOV_CtoS
, OP_VMOV_CtoSb
, false, rd
, rn
, VFPOperand(0));
1920 void vmov(RegisterID rd1
, RegisterID rd2
, FPDoubleRegisterID rn
)
1922 ASSERT(!BadReg(rd1
));
1923 ASSERT(!BadReg(rd2
));
1924 m_formatter
.vfpOp(OP_VMOV_DtoC
, OP_VMOV_DtoCb
, true, rd2
, VFPOperand(rd1
| 16), rn
);
1927 void vmov(FPDoubleRegisterID rd
, RegisterID rn1
, RegisterID rn2
)
1929 ASSERT(!BadReg(rn1
));
1930 ASSERT(!BadReg(rn2
));
1931 m_formatter
.vfpOp(OP_VMOV_CtoD
, OP_VMOV_CtoDb
, true, rn2
, VFPOperand(rn1
| 16), rd
);
1934 void vmov(FPDoubleRegisterID rd
, FPDoubleRegisterID rn
)
1936 m_formatter
.vfpOp(OP_VMOV_T2
, OP_VMOV_T2b
, true, VFPOperand(0), rd
, rn
);
1939 void vmrs(RegisterID reg
= ARMRegisters::pc
)
1941 ASSERT(reg
!= ARMRegisters::sp
);
1942 m_formatter
.vfpOp(OP_VMRS
, OP_VMRSb
, false, VFPOperand(1), VFPOperand(0x10 | reg
), VFPOperand(0));
1945 void vmul(FPDoubleRegisterID rd
, FPDoubleRegisterID rn
, FPDoubleRegisterID rm
)
1947 m_formatter
.vfpOp(OP_VMUL_T2
, OP_VMUL_T2b
, true, rn
, rd
, rm
);
1950 void vstr(FPDoubleRegisterID rd
, RegisterID rn
, int32_t imm
)
1952 m_formatter
.vfpMemOp(OP_VSTR
, OP_VSTRb
, true, rn
, rd
, imm
);
1955 void fsts(FPSingleRegisterID rd
, RegisterID rn
, int32_t imm
)
1957 m_formatter
.vfpMemOp(OP_FSTS
, OP_FSTSb
, false, rn
, rd
, imm
);
1960 void vsub(FPDoubleRegisterID rd
, FPDoubleRegisterID rn
, FPDoubleRegisterID rm
)
1962 m_formatter
.vfpOp(OP_VSUB_T2
, OP_VSUB_T2b
, true, rn
, rd
, rm
);
1965 void vabs(FPDoubleRegisterID rd
, FPDoubleRegisterID rm
)
1967 m_formatter
.vfpOp(OP_VABS_T2
, OP_VABS_T2b
, true, VFPOperand(16), rd
, rm
);
1970 void vneg(FPDoubleRegisterID rd
, FPDoubleRegisterID rm
)
1972 m_formatter
.vfpOp(OP_VNEG_T2
, OP_VNEG_T2b
, true, VFPOperand(1), rd
, rm
);
1975 void vsqrt(FPDoubleRegisterID rd
, FPDoubleRegisterID rm
)
1977 m_formatter
.vfpOp(OP_VSQRT_T1
, OP_VSQRT_T1b
, true, VFPOperand(17), rd
, rm
);
1980 void vcvtds(FPDoubleRegisterID rd
, FPSingleRegisterID rm
)
1982 m_formatter
.vfpOp(OP_VCVTDS_T1
, OP_VCVTDS_T1b
, false, VFPOperand(23), rd
, rm
);
1985 void vcvtsd(FPSingleRegisterID rd
, FPDoubleRegisterID rm
)
1987 m_formatter
.vfpOp(OP_VCVTSD_T1
, OP_VCVTSD_T1b
, true, VFPOperand(23), rd
, rm
);
1992 m_formatter
.oneWordOp8Imm8(OP_NOP_T1
, 0);
1997 m_formatter
.twoWordOp16Op16(OP_NOP_T2a
, OP_NOP_T2b
);
2002 m_formatter
.twoWordOp16Op16(OP_DMB_SY_T2a
, OP_DMB_SY_T2b
);
2005 AssemblerLabel
labelIgnoringWatchpoints()
2007 return m_formatter
.label();
2010 AssemblerLabel
labelForWatchpoint()
2012 AssemblerLabel result
= m_formatter
.label();
2013 if (static_cast<int>(result
.m_offset
) != m_indexOfLastWatchpoint
)
2015 m_indexOfLastWatchpoint
= result
.m_offset
;
2016 m_indexOfTailOfLastWatchpoint
= result
.m_offset
+ maxJumpReplacementSize();
2020 AssemblerLabel
label()
2022 AssemblerLabel result
= m_formatter
.label();
2023 while (UNLIKELY(static_cast<int>(result
.m_offset
) < m_indexOfTailOfLastWatchpoint
)) {
2024 if (UNLIKELY(static_cast<int>(result
.m_offset
) + 4 <= m_indexOfTailOfLastWatchpoint
))
2028 result
= m_formatter
.label();
2033 AssemblerLabel
align(int alignment
)
2035 while (!m_formatter
.isAligned(alignment
))
2041 static void* getRelocatedAddress(void* code
, AssemblerLabel label
)
2043 ASSERT(label
.isSet());
2044 return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code
) + label
.m_offset
);
2047 static int getDifferenceBetweenLabels(AssemblerLabel a
, AssemblerLabel b
)
2049 return b
.m_offset
- a
.m_offset
;
2052 static int jumpSizeDelta(JumpType jumpType
, JumpLinkType jumpLinkType
) { return JUMP_ENUM_SIZE(jumpType
) - JUMP_ENUM_SIZE(jumpLinkType
); }
2054 // Assembler admin methods:
2056 static ALWAYS_INLINE
bool linkRecordSourceComparator(const LinkRecord
& a
, const LinkRecord
& b
)
2058 return a
.from() < b
.from();
2061 static bool canCompact(JumpType jumpType
)
2063 // The following cannot be compacted:
2064 // JumpFixed: represents custom jump sequence
2065 // JumpNoConditionFixedSize: represents unconditional jump that must remain a fixed size
2066 // JumpConditionFixedSize: represents conditional jump that must remain a fixed size
2067 return (jumpType
== JumpNoCondition
) || (jumpType
== JumpCondition
);
2070 static JumpLinkType
computeJumpType(JumpType jumpType
, const uint8_t* from
, const uint8_t* to
)
2072 if (jumpType
== JumpFixed
)
2075 // for patchable jump we must leave space for the longest code sequence
2076 if (jumpType
== JumpNoConditionFixedSize
)
2078 if (jumpType
== JumpConditionFixedSize
)
2079 return LinkConditionalBX
;
2081 const int paddingSize
= JUMP_ENUM_SIZE(jumpType
);
2083 if (jumpType
== JumpCondition
) {
2084 // 2-byte conditional T1
2085 const uint16_t* jumpT1Location
= reinterpret_cast_ptr
<const uint16_t*>(from
- (paddingSize
- JUMP_ENUM_SIZE(LinkJumpT1
)));
2086 if (canBeJumpT1(jumpT1Location
, to
))
2088 // 4-byte conditional T3
2089 const uint16_t* jumpT3Location
= reinterpret_cast_ptr
<const uint16_t*>(from
- (paddingSize
- JUMP_ENUM_SIZE(LinkJumpT3
)));
2090 if (canBeJumpT3(jumpT3Location
, to
))
2092 // 4-byte conditional T4 with IT
2093 const uint16_t* conditionalJumpT4Location
=
2094 reinterpret_cast_ptr
<const uint16_t*>(from
- (paddingSize
- JUMP_ENUM_SIZE(LinkConditionalJumpT4
)));
2095 if (canBeJumpT4(conditionalJumpT4Location
, to
))
2096 return LinkConditionalJumpT4
;
2098 // 2-byte unconditional T2
2099 const uint16_t* jumpT2Location
= reinterpret_cast_ptr
<const uint16_t*>(from
- (paddingSize
- JUMP_ENUM_SIZE(LinkJumpT2
)));
2100 if (canBeJumpT2(jumpT2Location
, to
))
2102 // 4-byte unconditional T4
2103 const uint16_t* jumpT4Location
= reinterpret_cast_ptr
<const uint16_t*>(from
- (paddingSize
- JUMP_ENUM_SIZE(LinkJumpT4
)));
2104 if (canBeJumpT4(jumpT4Location
, to
))
2106 // use long jump sequence
2110 ASSERT(jumpType
== JumpCondition
);
2111 return LinkConditionalBX
;
2114 static JumpLinkType
computeJumpType(LinkRecord
& record
, const uint8_t* from
, const uint8_t* to
)
2116 JumpLinkType linkType
= computeJumpType(record
.type(), from
, to
);
2117 record
.setLinkType(linkType
);
2121 Vector
<LinkRecord
, 0, UnsafeVectorOverflow
>& jumpsToLink()
2123 std::sort(m_jumpsToLink
.begin(), m_jumpsToLink
.end(), linkRecordSourceComparator
);
2124 return m_jumpsToLink
;
2127 static void ALWAYS_INLINE
link(LinkRecord
& record
, uint8_t* from
, uint8_t* to
)
2129 switch (record
.linkType()) {
2131 linkJumpT1(record
.condition(), reinterpret_cast_ptr
<uint16_t*>(from
), to
);
2134 linkJumpT2(reinterpret_cast_ptr
<uint16_t*>(from
), to
);
2137 linkJumpT3(record
.condition(), reinterpret_cast_ptr
<uint16_t*>(from
), to
);
2140 linkJumpT4(reinterpret_cast_ptr
<uint16_t*>(from
), to
);
2142 case LinkConditionalJumpT4
:
2143 linkConditionalJumpT4(record
.condition(), reinterpret_cast_ptr
<uint16_t*>(from
), to
);
2145 case LinkConditionalBX
:
2146 linkConditionalBX(record
.condition(), reinterpret_cast_ptr
<uint16_t*>(from
), to
);
2149 linkBX(reinterpret_cast_ptr
<uint16_t*>(from
), to
);
2152 RELEASE_ASSERT_NOT_REACHED();
2157 void* unlinkedCode() { return m_formatter
.data(); }
2158 size_t codeSize() const { return m_formatter
.codeSize(); }
2160 static unsigned getCallReturnOffset(AssemblerLabel call
)
2162 ASSERT(call
.isSet());
2163 return call
.m_offset
;
2166 // Linking & patching:
2168 // 'link' and 'patch' methods are for use on unprotected code - such as the code
2169 // within the AssemblerBuffer, and code being patched by the patch buffer. Once
2170 // code has been finalized it is (platform support permitting) within a non-
2171 // writable region of memory; to modify the code in an execute-only execuable
2172 // pool the 'repatch' and 'relink' methods should be used.
2174 void linkJump(AssemblerLabel from
, AssemblerLabel to
, JumpType type
, Condition condition
)
2177 ASSERT(from
.isSet());
2178 m_jumpsToLink
.append(LinkRecord(from
.m_offset
, to
.m_offset
, type
, condition
));
2181 static void linkJump(void* code
, AssemblerLabel from
, void* to
)
2183 ASSERT(from
.isSet());
2185 uint16_t* location
= reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code
) + from
.m_offset
);
2186 linkJumpAbsolute(location
, to
);
2189 static void linkCall(void* code
, AssemblerLabel from
, void* to
)
2191 ASSERT(!(reinterpret_cast<intptr_t>(code
) & 1));
2192 ASSERT(from
.isSet());
2194 setPointer(reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code
) + from
.m_offset
) - 1, to
, false);
2197 static void linkPointer(void* code
, AssemblerLabel where
, void* value
)
2199 setPointer(reinterpret_cast<char*>(code
) + where
.m_offset
, value
, false);
2202 static void relinkJump(void* from
, void* to
)
2204 ASSERT(!(reinterpret_cast<intptr_t>(from
) & 1));
2205 ASSERT(!(reinterpret_cast<intptr_t>(to
) & 1));
2207 linkJumpAbsolute(reinterpret_cast<uint16_t*>(from
), to
);
2209 cacheFlush(reinterpret_cast<uint16_t*>(from
) - 5, 5 * sizeof(uint16_t));
2212 static void relinkCall(void* from
, void* to
)
2214 ASSERT(!(reinterpret_cast<intptr_t>(from
) & 1));
2216 setPointer(reinterpret_cast<uint16_t*>(from
) - 1, to
, true);
2219 static void* readCallTarget(void* from
)
2221 return readPointer(reinterpret_cast<uint16_t*>(from
) - 1);
2224 static void repatchInt32(void* where
, int32_t value
)
2226 ASSERT(!(reinterpret_cast<intptr_t>(where
) & 1));
2228 setInt32(where
, value
, true);
2231 static void repatchCompact(void* where
, int32_t offset
)
2233 ASSERT(offset
>= -255 && offset
<= 255);
2241 offset
|= (add
<< 9);
2242 offset
|= (1 << 10);
2243 offset
|= (1 << 11);
2245 uint16_t* location
= reinterpret_cast<uint16_t*>(where
);
2246 location
[1] &= ~((1 << 12) - 1);
2247 location
[1] |= offset
;
2248 cacheFlush(location
, sizeof(uint16_t) * 2);
2251 static void repatchPointer(void* where
, void* value
)
2253 ASSERT(!(reinterpret_cast<intptr_t>(where
) & 1));
2255 setPointer(where
, value
, true);
2258 static void* readPointer(void* where
)
2260 return reinterpret_cast<void*>(readInt32(where
));
2263 static void replaceWithJump(void* instructionStart
, void* to
)
2265 ASSERT(!(bitwise_cast
<uintptr_t>(instructionStart
) & 1));
2266 ASSERT(!(bitwise_cast
<uintptr_t>(to
) & 1));
2269 if (canBeJumpT4(reinterpret_cast<uint16_t*>(instructionStart
), to
)) {
2270 uint16_t* ptr
= reinterpret_cast<uint16_t*>(instructionStart
) + 2;
2271 linkJumpT4(ptr
, to
);
2272 cacheFlush(ptr
- 2, sizeof(uint16_t) * 2);
2274 uint16_t* ptr
= reinterpret_cast<uint16_t*>(instructionStart
) + 5;
2276 cacheFlush(ptr
- 5, sizeof(uint16_t) * 5);
2279 uint16_t* ptr
= reinterpret_cast<uint16_t*>(instructionStart
) + 2;
2280 linkJumpT4(ptr
, to
);
2281 cacheFlush(ptr
- 2, sizeof(uint16_t) * 2);
2285 static ptrdiff_t maxJumpReplacementSize()
2294 static void replaceWithLoad(void* instructionStart
)
2296 ASSERT(!(bitwise_cast
<uintptr_t>(instructionStart
) & 1));
2297 uint16_t* ptr
= reinterpret_cast<uint16_t*>(instructionStart
);
2298 switch (ptr
[0] & 0xFFF0) {
2302 ASSERT(!(ptr
[1] & 0xF000));
2304 ptr
[0] |= OP_LDR_imm_T3
;
2305 ptr
[1] |= (ptr
[1] & 0x0F00) << 4;
2307 cacheFlush(ptr
, sizeof(uint16_t) * 2);
2310 RELEASE_ASSERT_NOT_REACHED();
2314 static void replaceWithAddressComputation(void* instructionStart
)
2316 ASSERT(!(bitwise_cast
<uintptr_t>(instructionStart
) & 1));
2317 uint16_t* ptr
= reinterpret_cast<uint16_t*>(instructionStart
);
2318 switch (ptr
[0] & 0xFFF0) {
2320 ASSERT(!(ptr
[1] & 0x0F00));
2322 ptr
[0] |= OP_ADD_imm_T3
;
2323 ptr
[1] |= (ptr
[1] & 0xF000) >> 4;
2325 cacheFlush(ptr
, sizeof(uint16_t) * 2);
2330 RELEASE_ASSERT_NOT_REACHED();
2334 unsigned debugOffset() { return m_formatter
.debugOffset(); }
2337 static inline void linuxPageFlush(uintptr_t begin
, uintptr_t end
)
2349 : "r" (begin
), "r" (end
)
2350 : "r0", "r1", "r2");
2354 static void cacheFlush(void* code
, size_t size
)
2357 sys_cache_control(kCacheFunctionPrepareForExecution
, code
, size
);
2359 size_t page
= pageSize();
2360 uintptr_t current
= reinterpret_cast<uintptr_t>(code
);
2361 uintptr_t end
= current
+ size
;
2362 uintptr_t firstPageEnd
= (current
& ~(page
- 1)) + page
;
2364 if (end
<= firstPageEnd
) {
2365 linuxPageFlush(current
, end
);
2369 linuxPageFlush(current
, firstPageEnd
);
2371 for (current
= firstPageEnd
; current
+ page
< end
; current
+= page
)
2372 linuxPageFlush(current
, current
+ page
);
2374 linuxPageFlush(current
, end
);
2376 #error "The cacheFlush support is missing on this platform."
2381 // VFP operations commonly take one or more 5-bit operands, typically representing a
2382 // floating point register number. This will commonly be encoded in the instruction
2383 // in two parts, with one single bit field, and one 4-bit field. In the case of
2384 // double precision operands the high bit of the register number will be encoded
2385 // separately, and for single precision operands the high bit of the register number
2386 // will be encoded individually.
2387 // VFPOperand encapsulates a 5-bit VFP operand, with bits 0..3 containing the 4-bit
2388 // field to be encoded together in the instruction (the low 4-bits of a double
2389 // register number, or the high 4-bits of a single register number), and bit 4
2390 // contains the bit value to be encoded individually.
2392 explicit VFPOperand(uint32_t value
)
2395 ASSERT(!(m_value
& ~0x1f));
2398 VFPOperand(FPDoubleRegisterID reg
)
2403 VFPOperand(RegisterID reg
)
2408 VFPOperand(FPSingleRegisterID reg
)
2409 : m_value(((reg
& 1) << 4) | (reg
>> 1)) // rotate the lowest bit of 'reg' to the top.
2415 return m_value
>> 4;
2420 return m_value
& 0xf;
2426 VFPOperand
vcvtOp(bool toInteger
, bool isUnsigned
, bool isRoundZero
)
2428 // Cannot specify rounding when converting to float.
2429 ASSERT(toInteger
|| !isRoundZero
);
2433 // opc2 indicates both toInteger & isUnsigned.
2434 op
|= isUnsigned
? 0x4 : 0x5;
2435 // 'op' field in instruction is isRoundZero
2439 ASSERT(!isRoundZero
);
2440 // 'op' field in instruction is isUnsigned
2444 return VFPOperand(op
);
2447 static void setInt32(void* code
, uint32_t value
, bool flush
)
2449 uint16_t* location
= reinterpret_cast<uint16_t*>(code
);
2450 ASSERT(isMOV_imm_T3(location
- 4) && isMOVT(location
- 2));
2452 ARMThumbImmediate lo16
= ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(value
));
2453 ARMThumbImmediate hi16
= ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(value
>> 16));
2454 location
[-4] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3
, lo16
);
2455 location
[-3] = twoWordOp5i6Imm4Reg4EncodedImmSecond((location
[-3] >> 8) & 0xf, lo16
);
2456 location
[-2] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT
, hi16
);
2457 location
[-1] = twoWordOp5i6Imm4Reg4EncodedImmSecond((location
[-1] >> 8) & 0xf, hi16
);
2460 cacheFlush(location
- 4, 4 * sizeof(uint16_t));
2463 static int32_t readInt32(void* code
)
2465 uint16_t* location
= reinterpret_cast<uint16_t*>(code
);
2466 ASSERT(isMOV_imm_T3(location
- 4) && isMOVT(location
- 2));
2468 ARMThumbImmediate lo16
;
2469 ARMThumbImmediate hi16
;
2470 decodeTwoWordOp5i6Imm4Reg4EncodedImmFirst(lo16
, location
[-4]);
2471 decodeTwoWordOp5i6Imm4Reg4EncodedImmSecond(lo16
, location
[-3]);
2472 decodeTwoWordOp5i6Imm4Reg4EncodedImmFirst(hi16
, location
[-2]);
2473 decodeTwoWordOp5i6Imm4Reg4EncodedImmSecond(hi16
, location
[-1]);
2474 uint32_t result
= hi16
.asUInt16();
2476 result
|= lo16
.asUInt16();
2477 return static_cast<int32_t>(result
);
2480 static void setUInt7ForLoad(void* code
, ARMThumbImmediate imm
)
2482 // Requires us to have planted a LDR_imm_T1
2483 ASSERT(imm
.isValid());
2484 ASSERT(imm
.isUInt7());
2485 uint16_t* location
= reinterpret_cast<uint16_t*>(code
);
2486 location
[0] &= ~((static_cast<uint16_t>(0x7f) >> 2) << 6);
2487 location
[0] |= (imm
.getUInt7() >> 2) << 6;
2488 cacheFlush(location
, sizeof(uint16_t));
2491 static void setPointer(void* code
, void* value
, bool flush
)
2493 setInt32(code
, reinterpret_cast<uint32_t>(value
), flush
);
2496 static bool isB(void* address
)
2498 uint16_t* instruction
= static_cast<uint16_t*>(address
);
2499 return ((instruction
[0] & 0xf800) == OP_B_T4a
) && ((instruction
[1] & 0xd000) == OP_B_T4b
);
2502 static bool isBX(void* address
)
2504 uint16_t* instruction
= static_cast<uint16_t*>(address
);
2505 return (instruction
[0] & 0xff87) == OP_BX
;
2508 static bool isMOV_imm_T3(void* address
)
2510 uint16_t* instruction
= static_cast<uint16_t*>(address
);
2511 return ((instruction
[0] & 0xFBF0) == OP_MOV_imm_T3
) && ((instruction
[1] & 0x8000) == 0);
2514 static bool isMOVT(void* address
)
2516 uint16_t* instruction
= static_cast<uint16_t*>(address
);
2517 return ((instruction
[0] & 0xFBF0) == OP_MOVT
) && ((instruction
[1] & 0x8000) == 0);
2520 static bool isNOP_T1(void* address
)
2522 uint16_t* instruction
= static_cast<uint16_t*>(address
);
2523 return instruction
[0] == OP_NOP_T1
;
2526 static bool isNOP_T2(void* address
)
2528 uint16_t* instruction
= static_cast<uint16_t*>(address
);
2529 return (instruction
[0] == OP_NOP_T2a
) && (instruction
[1] == OP_NOP_T2b
);
2532 static bool canBeJumpT1(const uint16_t* instruction
, const void* target
)
2534 ASSERT(!(reinterpret_cast<intptr_t>(instruction
) & 1));
2535 ASSERT(!(reinterpret_cast<intptr_t>(target
) & 1));
2537 intptr_t relative
= reinterpret_cast<intptr_t>(target
) - (reinterpret_cast<intptr_t>(instruction
));
2538 // It does not appear to be documented in the ARM ARM (big surprise), but
2539 // for OP_B_T1 the branch displacement encoded in the instruction is 2
2540 // less than the actual displacement.
2542 return ((relative
<< 23) >> 23) == relative
;
2545 static bool canBeJumpT2(const uint16_t* instruction
, const void* target
)
2547 ASSERT(!(reinterpret_cast<intptr_t>(instruction
) & 1));
2548 ASSERT(!(reinterpret_cast<intptr_t>(target
) & 1));
2550 intptr_t relative
= reinterpret_cast<intptr_t>(target
) - (reinterpret_cast<intptr_t>(instruction
));
2551 // It does not appear to be documented in the ARM ARM (big surprise), but
2552 // for OP_B_T2 the branch displacement encoded in the instruction is 2
2553 // less than the actual displacement.
2555 return ((relative
<< 20) >> 20) == relative
;
2558 static bool canBeJumpT3(const uint16_t* instruction
, const void* target
)
2560 ASSERT(!(reinterpret_cast<intptr_t>(instruction
) & 1));
2561 ASSERT(!(reinterpret_cast<intptr_t>(target
) & 1));
2563 intptr_t relative
= reinterpret_cast<intptr_t>(target
) - (reinterpret_cast<intptr_t>(instruction
));
2564 return ((relative
<< 11) >> 11) == relative
;
2567 static bool canBeJumpT4(const uint16_t* instruction
, const void* target
)
2569 ASSERT(!(reinterpret_cast<intptr_t>(instruction
) & 1));
2570 ASSERT(!(reinterpret_cast<intptr_t>(target
) & 1));
2572 intptr_t relative
= reinterpret_cast<intptr_t>(target
) - (reinterpret_cast<intptr_t>(instruction
));
2573 return ((relative
<< 7) >> 7) == relative
;
2576 static void linkJumpT1(Condition cond
, uint16_t* instruction
, void* target
)
2578 // FIMXE: this should be up in the MacroAssembler layer. :-(
2579 ASSERT(!(reinterpret_cast<intptr_t>(instruction
) & 1));
2580 ASSERT(!(reinterpret_cast<intptr_t>(target
) & 1));
2581 ASSERT(canBeJumpT1(instruction
, target
));
2583 intptr_t relative
= reinterpret_cast<intptr_t>(target
) - (reinterpret_cast<intptr_t>(instruction
));
2584 // It does not appear to be documented in the ARM ARM (big surprise), but
2585 // for OP_B_T1 the branch displacement encoded in the instruction is 2
2586 // less than the actual displacement.
2589 // All branch offsets should be an even distance.
2590 ASSERT(!(relative
& 1));
2591 instruction
[-1] = OP_B_T1
| ((cond
& 0xf) << 8) | ((relative
& 0x1fe) >> 1);
2594 static void linkJumpT2(uint16_t* instruction
, void* target
)
2596 // FIMXE: this should be up in the MacroAssembler layer. :-(
2597 ASSERT(!(reinterpret_cast<intptr_t>(instruction
) & 1));
2598 ASSERT(!(reinterpret_cast<intptr_t>(target
) & 1));
2599 ASSERT(canBeJumpT2(instruction
, target
));
2601 intptr_t relative
= reinterpret_cast<intptr_t>(target
) - (reinterpret_cast<intptr_t>(instruction
));
2602 // It does not appear to be documented in the ARM ARM (big surprise), but
2603 // for OP_B_T2 the branch displacement encoded in the instruction is 2
2604 // less than the actual displacement.
2607 // All branch offsets should be an even distance.
2608 ASSERT(!(relative
& 1));
2609 instruction
[-1] = OP_B_T2
| ((relative
& 0xffe) >> 1);
2612 static void linkJumpT3(Condition cond
, uint16_t* instruction
, void* target
)
2614 // FIMXE: this should be up in the MacroAssembler layer. :-(
2615 ASSERT(!(reinterpret_cast<intptr_t>(instruction
) & 1));
2616 ASSERT(!(reinterpret_cast<intptr_t>(target
) & 1));
2617 ASSERT(canBeJumpT3(instruction
, target
));
2619 intptr_t relative
= reinterpret_cast<intptr_t>(target
) - (reinterpret_cast<intptr_t>(instruction
));
2621 // All branch offsets should be an even distance.
2622 ASSERT(!(relative
& 1));
2623 instruction
[-2] = OP_B_T3a
| ((relative
& 0x100000) >> 10) | ((cond
& 0xf) << 6) | ((relative
& 0x3f000) >> 12);
2624 instruction
[-1] = OP_B_T3b
| ((relative
& 0x80000) >> 8) | ((relative
& 0x40000) >> 5) | ((relative
& 0xffe) >> 1);
2627 static void linkJumpT4(uint16_t* instruction
, void* target
)
2629 // FIMXE: this should be up in the MacroAssembler layer. :-(
2630 ASSERT(!(reinterpret_cast<intptr_t>(instruction
) & 1));
2631 ASSERT(!(reinterpret_cast<intptr_t>(target
) & 1));
2632 ASSERT(canBeJumpT4(instruction
, target
));
2634 intptr_t relative
= reinterpret_cast<intptr_t>(target
) - (reinterpret_cast<intptr_t>(instruction
));
2635 // ARM encoding for the top two bits below the sign bit is 'peculiar'.
2637 relative
^= 0xC00000;
2639 // All branch offsets should be an even distance.
2640 ASSERT(!(relative
& 1));
2641 instruction
[-2] = OP_B_T4a
| ((relative
& 0x1000000) >> 14) | ((relative
& 0x3ff000) >> 12);
2642 instruction
[-1] = OP_B_T4b
| ((relative
& 0x800000) >> 10) | ((relative
& 0x400000) >> 11) | ((relative
& 0xffe) >> 1);
2645 static void linkConditionalJumpT4(Condition cond
, uint16_t* instruction
, void* target
)
2647 // FIMXE: this should be up in the MacroAssembler layer. :-(
2648 ASSERT(!(reinterpret_cast<intptr_t>(instruction
) & 1));
2649 ASSERT(!(reinterpret_cast<intptr_t>(target
) & 1));
2651 instruction
[-3] = ifThenElse(cond
) | OP_IT
;
2652 linkJumpT4(instruction
, target
);
2655 static void linkBX(uint16_t* instruction
, void* target
)
2657 // FIMXE: this should be up in the MacroAssembler layer. :-(
2658 ASSERT(!(reinterpret_cast<intptr_t>(instruction
) & 1));
2659 ASSERT(!(reinterpret_cast<intptr_t>(target
) & 1));
2661 const uint16_t JUMP_TEMPORARY_REGISTER
= ARMRegisters::ip
;
2662 ARMThumbImmediate lo16
= ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target
) + 1));
2663 ARMThumbImmediate hi16
= ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target
) >> 16));
2664 instruction
[-5] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3
, lo16
);
2665 instruction
[-4] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER
, lo16
);
2666 instruction
[-3] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT
, hi16
);
2667 instruction
[-2] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER
, hi16
);
2668 instruction
[-1] = OP_BX
| (JUMP_TEMPORARY_REGISTER
<< 3);
2671 static void linkConditionalBX(Condition cond
, uint16_t* instruction
, void* target
)
2673 // FIMXE: this should be up in the MacroAssembler layer. :-(
2674 ASSERT(!(reinterpret_cast<intptr_t>(instruction
) & 1));
2675 ASSERT(!(reinterpret_cast<intptr_t>(target
) & 1));
2677 linkBX(instruction
, target
);
2678 instruction
[-6] = ifThenElse(cond
, true, true) | OP_IT
;
2681 static void linkJumpAbsolute(uint16_t* instruction
, void* target
)
2683 // FIMXE: this should be up in the MacroAssembler layer. :-(
2684 ASSERT(!(reinterpret_cast<intptr_t>(instruction
) & 1));
2685 ASSERT(!(reinterpret_cast<intptr_t>(target
) & 1));
2687 ASSERT((isMOV_imm_T3(instruction
- 5) && isMOVT(instruction
- 3) && isBX(instruction
- 1))
2688 || (isNOP_T1(instruction
- 5) && isNOP_T2(instruction
- 4) && isB(instruction
- 2)));
2690 if (canBeJumpT4(instruction
, target
)) {
2691 // There may be a better way to fix this, but right now put the NOPs first, since in the
2692 // case of an conditional branch this will be coming after an ITTT predicating *three*
2693 // instructions! Looking backwards to modify the ITTT to an IT is not easy, due to
2694 // variable wdith encoding - the previous instruction might *look* like an ITTT but
2695 // actually be the second half of a 2-word op.
2696 instruction
[-5] = OP_NOP_T1
;
2697 instruction
[-4] = OP_NOP_T2a
;
2698 instruction
[-3] = OP_NOP_T2b
;
2699 linkJumpT4(instruction
, target
);
2701 const uint16_t JUMP_TEMPORARY_REGISTER
= ARMRegisters::ip
;
2702 ARMThumbImmediate lo16
= ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target
) + 1));
2703 ARMThumbImmediate hi16
= ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target
) >> 16));
2704 instruction
[-5] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3
, lo16
);
2705 instruction
[-4] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER
, lo16
);
2706 instruction
[-3] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT
, hi16
);
2707 instruction
[-2] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER
, hi16
);
2708 instruction
[-1] = OP_BX
| (JUMP_TEMPORARY_REGISTER
<< 3);
2712 static uint16_t twoWordOp5i6Imm4Reg4EncodedImmFirst(uint16_t op
, ARMThumbImmediate imm
)
2714 return op
| (imm
.m_value
.i
<< 10) | imm
.m_value
.imm4
;
2717 static void decodeTwoWordOp5i6Imm4Reg4EncodedImmFirst(ARMThumbImmediate
& result
, uint16_t value
)
2719 result
.m_value
.i
= (value
>> 10) & 1;
2720 result
.m_value
.imm4
= value
& 15;
2723 static uint16_t twoWordOp5i6Imm4Reg4EncodedImmSecond(uint16_t rd
, ARMThumbImmediate imm
)
2725 return (imm
.m_value
.imm3
<< 12) | (rd
<< 8) | imm
.m_value
.imm8
;
2728 static void decodeTwoWordOp5i6Imm4Reg4EncodedImmSecond(ARMThumbImmediate
& result
, uint16_t value
)
2730 result
.m_value
.imm3
= (value
>> 12) & 7;
2731 result
.m_value
.imm8
= value
& 255;
2734 class ARMInstructionFormatter
{
2736 ALWAYS_INLINE
void oneWordOp5Reg3Imm8(OpcodeID op
, RegisterID rd
, uint8_t imm
)
2738 m_buffer
.putShort(op
| (rd
<< 8) | imm
);
2741 ALWAYS_INLINE
void oneWordOp5Imm5Reg3Reg3(OpcodeID op
, uint8_t imm
, RegisterID reg1
, RegisterID reg2
)
2743 m_buffer
.putShort(op
| (imm
<< 6) | (reg1
<< 3) | reg2
);
2746 ALWAYS_INLINE
void oneWordOp7Reg3Reg3Reg3(OpcodeID op
, RegisterID reg1
, RegisterID reg2
, RegisterID reg3
)
2748 m_buffer
.putShort(op
| (reg1
<< 6) | (reg2
<< 3) | reg3
);
2751 ALWAYS_INLINE
void oneWordOp7Imm9(OpcodeID op
, uint16_t imm
)
2753 m_buffer
.putShort(op
| imm
);
2756 ALWAYS_INLINE
void oneWordOp8Imm8(OpcodeID op
, uint8_t imm
)
2758 m_buffer
.putShort(op
| imm
);
2761 ALWAYS_INLINE
void oneWordOp8RegReg143(OpcodeID op
, RegisterID reg1
, RegisterID reg2
)
2763 m_buffer
.putShort(op
| ((reg2
& 8) << 4) | (reg1
<< 3) | (reg2
& 7));
2766 ALWAYS_INLINE
void oneWordOp9Imm7(OpcodeID op
, uint8_t imm
)
2768 m_buffer
.putShort(op
| imm
);
2771 ALWAYS_INLINE
void oneWordOp10Reg3Reg3(OpcodeID op
, RegisterID reg1
, RegisterID reg2
)
2773 m_buffer
.putShort(op
| (reg1
<< 3) | reg2
);
2776 ALWAYS_INLINE
void twoWordOp12Reg4FourFours(OpcodeID1 op
, RegisterID reg
, FourFours ff
)
2778 m_buffer
.putShort(op
| reg
);
2779 m_buffer
.putShort(ff
.m_u
.value
);
2782 ALWAYS_INLINE
void twoWordOp16FourFours(OpcodeID1 op
, FourFours ff
)
2784 m_buffer
.putShort(op
);
2785 m_buffer
.putShort(ff
.m_u
.value
);
2788 ALWAYS_INLINE
void twoWordOp16Op16(OpcodeID1 op1
, OpcodeID2 op2
)
2790 m_buffer
.putShort(op1
);
2791 m_buffer
.putShort(op2
);
2794 ALWAYS_INLINE
void twoWordOp16Imm16(OpcodeID1 op1
, uint16_t imm
)
2796 m_buffer
.putShort(op1
);
2797 m_buffer
.putShort(imm
);
2800 ALWAYS_INLINE
void twoWordOp5i6Imm4Reg4EncodedImm(OpcodeID1 op
, int imm4
, RegisterID rd
, ARMThumbImmediate imm
)
2802 ARMThumbImmediate newImm
= imm
;
2803 newImm
.m_value
.imm4
= imm4
;
2805 m_buffer
.putShort(ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmFirst(op
, newImm
));
2806 m_buffer
.putShort(ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmSecond(rd
, newImm
));
2809 ALWAYS_INLINE
void twoWordOp12Reg4Reg4Imm12(OpcodeID1 op
, RegisterID reg1
, RegisterID reg2
, uint16_t imm
)
2811 m_buffer
.putShort(op
| reg1
);
2812 m_buffer
.putShort((reg2
<< 12) | imm
);
2815 ALWAYS_INLINE
void twoWordOp12Reg40Imm3Reg4Imm20Imm5(OpcodeID1 op
, RegisterID reg1
, RegisterID reg2
, uint16_t imm1
, uint16_t imm2
, uint16_t imm3
)
2817 m_buffer
.putShort(op
| reg1
);
2818 m_buffer
.putShort((imm1
<< 12) | (reg2
<< 8) | (imm2
<< 6) | imm3
);
2821 // Formats up instructions of the pattern:
2822 // 111111111B11aaaa:bbbb222SA2C2cccc
2823 // Where 1s in the pattern come from op1, 2s in the pattern come from op2, S is the provided size bit.
2824 // Operands provide 5 bit values of the form Aaaaa, Bbbbb, Ccccc.
2825 ALWAYS_INLINE
void vfpOp(OpcodeID1 op1
, OpcodeID2 op2
, bool size
, VFPOperand a
, VFPOperand b
, VFPOperand c
)
2827 ASSERT(!(op1
& 0x004f));
2828 ASSERT(!(op2
& 0xf1af));
2829 m_buffer
.putShort(op1
| b
.bits1() << 6 | a
.bits4());
2830 m_buffer
.putShort(op2
| b
.bits4() << 12 | size
<< 8 | a
.bits1() << 7 | c
.bits1() << 5 | c
.bits4());
2833 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
2834 // (i.e. +/-(0..255) 32-bit words)
2835 ALWAYS_INLINE
void vfpMemOp(OpcodeID1 op1
, OpcodeID2 op2
, bool size
, RegisterID rn
, VFPOperand rd
, int32_t imm
)
2843 uint32_t offset
= imm
;
2844 ASSERT(!(offset
& ~0x3fc));
2847 m_buffer
.putShort(op1
| (up
<< 7) | rd
.bits1() << 6 | rn
);
2848 m_buffer
.putShort(op2
| rd
.bits4() << 12 | size
<< 8 | offset
);
2851 // Administrative methods:
2853 size_t codeSize() const { return m_buffer
.codeSize(); }
2854 AssemblerLabel
label() const { return m_buffer
.label(); }
2855 bool isAligned(int alignment
) const { return m_buffer
.isAligned(alignment
); }
2856 void* data() const { return m_buffer
.data(); }
2858 unsigned debugOffset() { return m_buffer
.debugOffset(); }
2860 AssemblerBuffer m_buffer
;
2863 Vector
<LinkRecord
, 0, UnsafeVectorOverflow
> m_jumpsToLink
;
2864 int m_indexOfLastWatchpoint
;
2865 int m_indexOfTailOfLastWatchpoint
;
2870 #endif // ENABLE(ASSEMBLER) && CPU(ARM_THUMB2)
2872 #endif // ARMAssembler_h