1 /* 2 * Copyright (C) 2009, 2010, 2012, 2013 Apple Inc. All rights reserved. 3 * Copyright (C) 2010 University of Szeged 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 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. 13 * 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. 25 */ 26 27 #ifndef ARMAssembler_h 28 #define ARMAssembler_h 29 30 #if ENABLE(ASSEMBLER) && CPU(ARM_THUMB2) 31 32 #include "AssemblerBuffer.h" 33 #include "MacroAssemblerCodeRef.h" 34 #include "AbstractMacroAssembler.h" 35 #include <wtf/Assertions.h> 36 #include <wtf/Vector.h> 37 #include <stdint.h> 38 39 #if OS(IOS) 40 #include <libkern/OSCacheControl.h> 41 #endif 42 43 #if OS(RTEMS) 44 #include <rtems/rtems/cache.h> 45 #endif 46 47 namespace JSC { 48 49 namespace ARMRegisters { 50 typedef enum { 51 r0, 52 r1, 53 r2, 54 r3, 55 r4, 56 r5, 57 r6, 58 r7, wr = r7, // thumb work register 59 r8, 60 r9, sb = r9, // static base 61 r10, sl = r10, // stack limit 62 r11, fp = r11, // frame pointer 63 r12, ip = r12, 64 r13, sp = r13, 65 r14, lr = r14, 66 r15, pc = r15, 67 } RegisterID; 68 69 typedef enum { 70 s0, 71 s1, 72 s2, 73 s3, 74 s4, 75 s5, 76 s6, 77 s7, 78 s8, 79 s9, 80 s10, 81 s11, 82 s12, 83 s13, 84 s14, 85 s15, 86 s16, 87 s17, 88 s18, 89 s19, 90 s20, 91 s21, 92 s22, 93 s23, 94 s24, 95 s25, 96 s26, 97 s27, 98 s28, 99 s29, 100 s30, 101 s31, 102 } FPSingleRegisterID; 103 104 typedef enum { 105 d0, 106 d1, 107 d2, 108 d3, 109 d4, 110 d5, 111 d6, 112 d7, 113 d8, 114 d9, 115 d10, 116 d11, 117 d12, 118 d13, 119 d14, 120 d15, 121 d16, 122 d17, 123 d18, 124 d19, 125 d20, 126 d21, 127 d22, 128 d23, 129 d24, 130 d25, 131 d26, 132 d27, 133 d28, 134 d29, 135 d30, 136 d31, 137 } FPDoubleRegisterID; 138 139 typedef enum { 140 q0, 141 q1, 142 q2, 143 q3, 144 q4, 145 q5, 146 q6, 147 q7, 148 q8, 149 q9, 150 q10, 151 q11, 152 q12, 153 q13, 154 q14, 155 q15, 156 q16, 157 q17, 158 q18, 159 q19, 160 q20, 161 q21, 162 q22, 163 q23, 164 q24, 165 q25, 166 q26, 167 q27, 168 q28, 169 q29, 170 q30, 171 q31, 172 } FPQuadRegisterID; 173 asSingle(FPDoubleRegisterID reg)174 inline FPSingleRegisterID asSingle(FPDoubleRegisterID reg) 175 { 176 ASSERT(reg < d16); 177 return (FPSingleRegisterID)(reg << 1); 178 } 179 asDouble(FPSingleRegisterID reg)180 inline FPDoubleRegisterID asDouble(FPSingleRegisterID reg) 181 { 182 ASSERT(!(reg & 1)); 183 return (FPDoubleRegisterID)(reg >> 1); 184 } 185 } 186 187 class ARMv7Assembler; 188 class ARMThumbImmediate { 189 friend class ARMv7Assembler; 190 191 typedef uint8_t ThumbImmediateType; 192 static const ThumbImmediateType TypeInvalid = 0; 193 static const ThumbImmediateType TypeEncoded = 1; 194 static const ThumbImmediateType TypeUInt16 = 2; 195 196 typedef union { 197 int16_t asInt; 198 struct { 199 unsigned imm8 : 8; 200 unsigned imm3 : 3; 201 unsigned i : 1; 202 unsigned imm4 : 4; 203 }; 204 // If this is an encoded immediate, then it may describe a shift, or a pattern. 205 struct { 206 unsigned shiftValue7 : 7; 207 unsigned shiftAmount : 5; 208 }; 209 struct { 210 unsigned immediate : 8; 211 unsigned pattern : 4; 212 }; 213 } ThumbImmediateValue; 214 215 // byte0 contains least significant bit; not using an array to make client code endian agnostic. 216 typedef union { 217 int32_t asInt; 218 struct { 219 uint8_t byte0; 220 uint8_t byte1; 221 uint8_t byte2; 222 uint8_t byte3; 223 }; 224 } PatternBytes; 225 countLeadingZerosPartial(uint32_t & value,int32_t & zeros,const int N)226 ALWAYS_INLINE static void countLeadingZerosPartial(uint32_t& value, int32_t& zeros, const int N) 227 { 228 if (value & ~((1 << N) - 1)) /* check for any of the top N bits (of 2N bits) are set */ 229 value >>= N; /* if any were set, lose the bottom N */ 230 else /* if none of the top N bits are set, */ 231 zeros += N; /* then we have identified N leading zeros */ 232 } 233 countLeadingZeros(uint32_t value)234 static int32_t countLeadingZeros(uint32_t value) 235 { 236 if (!value) 237 return 32; 238 239 int32_t zeros = 0; 240 countLeadingZerosPartial(value, zeros, 16); 241 countLeadingZerosPartial(value, zeros, 8); 242 countLeadingZerosPartial(value, zeros, 4); 243 countLeadingZerosPartial(value, zeros, 2); 244 countLeadingZerosPartial(value, zeros, 1); 245 return zeros; 246 } 247 ARMThumbImmediate()248 ARMThumbImmediate() 249 : m_type(TypeInvalid) 250 { 251 m_value.asInt = 0; 252 } 253 ARMThumbImmediate(ThumbImmediateType type,ThumbImmediateValue value)254 ARMThumbImmediate(ThumbImmediateType type, ThumbImmediateValue value) 255 : m_type(type) 256 , m_value(value) 257 { 258 } 259 ARMThumbImmediate(ThumbImmediateType type,uint16_t value)260 ARMThumbImmediate(ThumbImmediateType type, uint16_t value) 261 : m_type(TypeUInt16) 262 { 263 // Make sure this constructor is only reached with type TypeUInt16; 264 // this extra parameter makes the code a little clearer by making it 265 // explicit at call sites which type is being constructed 266 ASSERT_UNUSED(type, type == TypeUInt16); 267 268 m_value.asInt = value; 269 } 270 271 public: makeEncodedImm(uint32_t value)272 static ARMThumbImmediate makeEncodedImm(uint32_t value) 273 { 274 ThumbImmediateValue encoding; 275 encoding.asInt = 0; 276 277 // okay, these are easy. 278 if (value < 256) { 279 encoding.immediate = value; 280 encoding.pattern = 0; 281 return ARMThumbImmediate(TypeEncoded, encoding); 282 } 283 284 int32_t leadingZeros = countLeadingZeros(value); 285 // if there were 24 or more leading zeros, then we'd have hit the (value < 256) case. 286 ASSERT(leadingZeros < 24); 287 288 // Given a number with bit fields Z:B:C, where count(Z)+count(B)+count(C) == 32, 289 // Z are the bits known zero, B is the 8-bit immediate, C are the bits to check for 290 // zero. count(B) == 8, so the count of bits to be checked is 24 - count(Z). 291 int32_t rightShiftAmount = 24 - leadingZeros; 292 if (value == ((value >> rightShiftAmount) << rightShiftAmount)) { 293 // Shift the value down to the low byte position. The assign to 294 // shiftValue7 drops the implicit top bit. 295 encoding.shiftValue7 = value >> rightShiftAmount; 296 // The endoded shift amount is the magnitude of a right rotate. 297 encoding.shiftAmount = 8 + leadingZeros; 298 return ARMThumbImmediate(TypeEncoded, encoding); 299 } 300 301 PatternBytes bytes; 302 bytes.asInt = value; 303 304 if ((bytes.byte0 == bytes.byte1) && (bytes.byte0 == bytes.byte2) && (bytes.byte0 == bytes.byte3)) { 305 encoding.immediate = bytes.byte0; 306 encoding.pattern = 3; 307 return ARMThumbImmediate(TypeEncoded, encoding); 308 } 309 310 if ((bytes.byte0 == bytes.byte2) && !(bytes.byte1 | bytes.byte3)) { 311 encoding.immediate = bytes.byte0; 312 encoding.pattern = 1; 313 return ARMThumbImmediate(TypeEncoded, encoding); 314 } 315 316 if ((bytes.byte1 == bytes.byte3) && !(bytes.byte0 | bytes.byte2)) { 317 encoding.immediate = bytes.byte1; 318 encoding.pattern = 2; 319 return ARMThumbImmediate(TypeEncoded, encoding); 320 } 321 322 return ARMThumbImmediate(); 323 } 324 makeUInt12(int32_t value)325 static ARMThumbImmediate makeUInt12(int32_t value) 326 { 327 return (!(value & 0xfffff000)) 328 ? ARMThumbImmediate(TypeUInt16, (uint16_t)value) 329 : ARMThumbImmediate(); 330 } 331 makeUInt12OrEncodedImm(int32_t value)332 static ARMThumbImmediate makeUInt12OrEncodedImm(int32_t value) 333 { 334 // If this is not a 12-bit unsigned it, try making an encoded immediate. 335 return (!(value & 0xfffff000)) 336 ? ARMThumbImmediate(TypeUInt16, (uint16_t)value) 337 : makeEncodedImm(value); 338 } 339 340 // The 'make' methods, above, return a !isValid() value if the argument 341 // cannot be represented as the requested type. This methods is called 342 // 'get' since the argument can always be represented. makeUInt16(uint16_t value)343 static ARMThumbImmediate makeUInt16(uint16_t value) 344 { 345 return ARMThumbImmediate(TypeUInt16, value); 346 } 347 isValid()348 bool isValid() 349 { 350 return m_type != TypeInvalid; 351 } 352 asUInt16()353 uint16_t asUInt16() const { return m_value.asInt; } 354 355 // These methods rely on the format of encoded byte values. isUInt3()356 bool isUInt3() { return !(m_value.asInt & 0xfff8); } isUInt4()357 bool isUInt4() { return !(m_value.asInt & 0xfff0); } isUInt5()358 bool isUInt5() { return !(m_value.asInt & 0xffe0); } isUInt6()359 bool isUInt6() { return !(m_value.asInt & 0xffc0); } isUInt7()360 bool isUInt7() { return !(m_value.asInt & 0xff80); } isUInt8()361 bool isUInt8() { return !(m_value.asInt & 0xff00); } isUInt9()362 bool isUInt9() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xfe00); } isUInt10()363 bool isUInt10() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xfc00); } isUInt12()364 bool isUInt12() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xf000); } isUInt16()365 bool isUInt16() { return m_type == TypeUInt16; } getUInt3()366 uint8_t getUInt3() { ASSERT(isUInt3()); return m_value.asInt; } getUInt4()367 uint8_t getUInt4() { ASSERT(isUInt4()); return m_value.asInt; } getUInt5()368 uint8_t getUInt5() { ASSERT(isUInt5()); return m_value.asInt; } getUInt6()369 uint8_t getUInt6() { ASSERT(isUInt6()); return m_value.asInt; } getUInt7()370 uint8_t getUInt7() { ASSERT(isUInt7()); return m_value.asInt; } getUInt8()371 uint8_t getUInt8() { ASSERT(isUInt8()); return m_value.asInt; } getUInt9()372 uint16_t getUInt9() { ASSERT(isUInt9()); return m_value.asInt; } getUInt10()373 uint16_t getUInt10() { ASSERT(isUInt10()); return m_value.asInt; } getUInt12()374 uint16_t getUInt12() { ASSERT(isUInt12()); return m_value.asInt; } getUInt16()375 uint16_t getUInt16() { ASSERT(isUInt16()); return m_value.asInt; } 376 isEncodedImm()377 bool isEncodedImm() { return m_type == TypeEncoded; } 378 379 private: 380 ThumbImmediateType m_type; 381 ThumbImmediateValue m_value; 382 }; 383 384 typedef enum { 385 SRType_LSL, 386 SRType_LSR, 387 SRType_ASR, 388 SRType_ROR, 389 390 SRType_RRX = SRType_ROR 391 } ARMShiftType; 392 393 class ShiftTypeAndAmount { 394 friend class ARMv7Assembler; 395 396 public: ShiftTypeAndAmount()397 ShiftTypeAndAmount() 398 { 399 m_u.type = (ARMShiftType)0; 400 m_u.amount = 0; 401 } 402 ShiftTypeAndAmount(ARMShiftType type,unsigned amount)403 ShiftTypeAndAmount(ARMShiftType type, unsigned amount) 404 { 405 m_u.type = type; 406 m_u.amount = amount & 31; 407 } 408 lo4()409 unsigned lo4() { return m_u.lo4; } hi4()410 unsigned hi4() { return m_u.hi4; } 411 412 private: 413 union { 414 struct { 415 unsigned lo4 : 4; 416 unsigned hi4 : 4; 417 }; 418 struct { 419 unsigned type : 2; 420 unsigned amount : 6; 421 }; 422 } m_u; 423 }; 424 425 class ARMv7Assembler { 426 public: 427 typedef ARMRegisters::RegisterID RegisterID; 428 typedef ARMRegisters::FPSingleRegisterID FPSingleRegisterID; 429 typedef ARMRegisters::FPDoubleRegisterID FPDoubleRegisterID; 430 typedef ARMRegisters::FPQuadRegisterID FPQuadRegisterID; 431 typedef ARMRegisters::FPDoubleRegisterID FPRegisterID; 432 433 // (HS, LO, HI, LS) -> (AE, B, A, BE) 434 // (VS, VC) -> (O, NO) 435 typedef enum { 436 ConditionEQ, 437 ConditionNE, 438 ConditionHS, ConditionCS = ConditionHS, 439 ConditionLO, ConditionCC = ConditionLO, 440 ConditionMI, 441 ConditionPL, 442 ConditionVS, 443 ConditionVC, 444 ConditionHI, 445 ConditionLS, 446 ConditionGE, 447 ConditionLT, 448 ConditionGT, 449 ConditionLE, 450 ConditionAL, 451 ConditionInvalid 452 } Condition; 453 454 #define JUMP_ENUM_WITH_SIZE(index, value) (((value) << 3) | (index)) 455 #define JUMP_ENUM_SIZE(jump) ((jump) >> 3) 456 enum JumpType { JumpFixed = JUMP_ENUM_WITH_SIZE(0, 0), 457 JumpNoCondition = JUMP_ENUM_WITH_SIZE(1, 5 * sizeof(uint16_t)), 458 JumpCondition = JUMP_ENUM_WITH_SIZE(2, 6 * sizeof(uint16_t)), 459 JumpNoConditionFixedSize = JUMP_ENUM_WITH_SIZE(3, 5 * sizeof(uint16_t)), 460 JumpConditionFixedSize = JUMP_ENUM_WITH_SIZE(4, 6 * sizeof(uint16_t)) 461 }; 462 enum JumpLinkType { 463 LinkInvalid = JUMP_ENUM_WITH_SIZE(0, 0), 464 LinkJumpT1 = JUMP_ENUM_WITH_SIZE(1, sizeof(uint16_t)), 465 LinkJumpT2 = JUMP_ENUM_WITH_SIZE(2, sizeof(uint16_t)), 466 LinkJumpT3 = JUMP_ENUM_WITH_SIZE(3, 2 * sizeof(uint16_t)), 467 LinkJumpT4 = JUMP_ENUM_WITH_SIZE(4, 2 * sizeof(uint16_t)), 468 LinkConditionalJumpT4 = JUMP_ENUM_WITH_SIZE(5, 3 * sizeof(uint16_t)), 469 LinkBX = JUMP_ENUM_WITH_SIZE(6, 5 * sizeof(uint16_t)), 470 LinkConditionalBX = JUMP_ENUM_WITH_SIZE(7, 6 * sizeof(uint16_t)) 471 }; 472 473 class LinkRecord { 474 public: LinkRecord(intptr_t from,intptr_t to,JumpType type,Condition condition)475 LinkRecord(intptr_t from, intptr_t to, JumpType type, Condition condition) 476 { 477 data.realTypes.m_from = from; 478 data.realTypes.m_to = to; 479 data.realTypes.m_type = type; 480 data.realTypes.m_linkType = LinkInvalid; 481 data.realTypes.m_condition = condition; 482 } 483 void operator=(const LinkRecord& other) 484 { 485 data.copyTypes.content[0] = other.data.copyTypes.content[0]; 486 data.copyTypes.content[1] = other.data.copyTypes.content[1]; 487 data.copyTypes.content[2] = other.data.copyTypes.content[2]; 488 } from()489 intptr_t from() const { return data.realTypes.m_from; } setFrom(intptr_t from)490 void setFrom(intptr_t from) { data.realTypes.m_from = from; } to()491 intptr_t to() const { return data.realTypes.m_to; } type()492 JumpType type() const { return data.realTypes.m_type; } linkType()493 JumpLinkType linkType() const { return data.realTypes.m_linkType; } setLinkType(JumpLinkType linkType)494 void setLinkType(JumpLinkType linkType) { ASSERT(data.realTypes.m_linkType == LinkInvalid); data.realTypes.m_linkType = linkType; } condition()495 Condition condition() const { return data.realTypes.m_condition; } 496 private: 497 union { 498 struct RealTypes { 499 int32_t m_from : 31; 500 int32_t m_to : 31; 501 JumpType m_type : 8; 502 JumpLinkType m_linkType : 8; 503 Condition m_condition : 16; 504 } realTypes; 505 struct CopyTypes { 506 uint32_t content[3]; 507 } copyTypes; 508 COMPILE_ASSERT(sizeof(RealTypes) == sizeof(CopyTypes), LinkRecordCopyStructSizeEqualsRealStruct); 509 } data; 510 }; 511 ARMv7Assembler()512 ARMv7Assembler() 513 : m_indexOfLastWatchpoint(INT_MIN) 514 , m_indexOfTailOfLastWatchpoint(INT_MIN) 515 { 516 } 517 518 519 // Jump: 520 // 521 // A jump object is a reference to a jump instruction that has been planted 522 // into the code buffer - it is typically used to link the jump, setting the 523 // relative offset such that when executed it will jump to the desired 524 // destination. 525 template <typename LabelType> 526 class Jump { 527 template<class TemplateAssemblerType> friend class AbstractMacroAssembler; 528 friend class Call; 529 template <typename, template <typename> class> friend class LinkBufferBase;; 530 public: Jump()531 Jump() 532 { 533 } 534 535 // Fixme: this information should be stored in the instruction stream, not in the Jump object. 536 Jump(AssemblerLabel jmp, ARMv7Assembler::JumpType type = ARMv7Assembler::JumpNoCondition, ARMv7Assembler::Condition condition = ARMv7Assembler::ConditionInvalid) m_label(jmp)537 : m_label(jmp) 538 , m_type(type) 539 , m_condition(condition) 540 { 541 } 542 label()543 LabelType label() const 544 { 545 LabelType result; 546 result.m_label = m_label; 547 return result; 548 } 549 link(AbstractMacroAssembler<ARMv7Assembler> * masm)550 void link(AbstractMacroAssembler<ARMv7Assembler>* masm) const 551 { 552 masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition); 553 } 554 linkTo(LabelType label,AbstractMacroAssembler<ARMv7Assembler> * masm)555 void linkTo(LabelType label, AbstractMacroAssembler<ARMv7Assembler>* masm) const 556 { 557 masm->m_assembler.linkJump(m_label, label.label(), m_type, m_condition); 558 } 559 isSet()560 bool isSet() const { return m_label.isSet(); } 561 562 private: 563 AssemblerLabel m_label; 564 ARMv7Assembler::JumpType m_type; 565 ARMv7Assembler::Condition m_condition; 566 }; 567 568 private: 569 570 // ARMv7, Appx-A.6.3 BadReg(RegisterID reg)571 static bool BadReg(RegisterID reg) 572 { 573 return (reg == ARMRegisters::sp) || (reg == ARMRegisters::pc); 574 } 575 singleRegisterMask(FPSingleRegisterID rdNum,int highBitsShift,int lowBitShift)576 uint32_t singleRegisterMask(FPSingleRegisterID rdNum, int highBitsShift, int lowBitShift) 577 { 578 uint32_t rdMask = (rdNum >> 1) << highBitsShift; 579 if (rdNum & 1) 580 rdMask |= 1 << lowBitShift; 581 return rdMask; 582 } 583 doubleRegisterMask(FPDoubleRegisterID rdNum,int highBitShift,int lowBitsShift)584 uint32_t doubleRegisterMask(FPDoubleRegisterID rdNum, int highBitShift, int lowBitsShift) 585 { 586 uint32_t rdMask = (rdNum & 0xf) << lowBitsShift; 587 if (rdNum & 16) 588 rdMask |= 1 << highBitShift; 589 return rdMask; 590 } 591 592 typedef enum { 593 OP_ADD_reg_T1 = 0x1800, 594 OP_SUB_reg_T1 = 0x1A00, 595 OP_ADD_imm_T1 = 0x1C00, 596 OP_SUB_imm_T1 = 0x1E00, 597 OP_MOV_imm_T1 = 0x2000, 598 OP_CMP_imm_T1 = 0x2800, 599 OP_ADD_imm_T2 = 0x3000, 600 OP_SUB_imm_T2 = 0x3800, 601 OP_AND_reg_T1 = 0x4000, 602 OP_EOR_reg_T1 = 0x4040, 603 OP_TST_reg_T1 = 0x4200, 604 OP_RSB_imm_T1 = 0x4240, 605 OP_CMP_reg_T1 = 0x4280, 606 OP_ORR_reg_T1 = 0x4300, 607 OP_MVN_reg_T1 = 0x43C0, 608 OP_ADD_reg_T2 = 0x4400, 609 OP_MOV_reg_T1 = 0x4600, 610 OP_BLX = 0x4700, 611 OP_BX = 0x4700, 612 OP_STR_reg_T1 = 0x5000, 613 OP_STRH_reg_T1 = 0x5200, 614 OP_STRB_reg_T1 = 0x5400, 615 OP_LDRSB_reg_T1 = 0x5600, 616 OP_LDR_reg_T1 = 0x5800, 617 OP_LDRH_reg_T1 = 0x5A00, 618 OP_LDRB_reg_T1 = 0x5C00, 619 OP_LDRSH_reg_T1 = 0x5E00, 620 OP_STR_imm_T1 = 0x6000, 621 OP_LDR_imm_T1 = 0x6800, 622 OP_STRB_imm_T1 = 0x7000, 623 OP_LDRB_imm_T1 = 0x7800, 624 OP_STRH_imm_T1 = 0x8000, 625 OP_LDRH_imm_T1 = 0x8800, 626 OP_STR_imm_T2 = 0x9000, 627 OP_LDR_imm_T2 = 0x9800, 628 OP_ADD_SP_imm_T1 = 0xA800, 629 OP_ADD_SP_imm_T2 = 0xB000, 630 OP_SUB_SP_imm_T1 = 0xB080, 631 OP_BKPT = 0xBE00, 632 OP_IT = 0xBF00, 633 OP_NOP_T1 = 0xBF00, 634 } OpcodeID; 635 636 typedef enum { 637 OP_B_T1 = 0xD000, 638 OP_B_T2 = 0xE000, 639 OP_AND_reg_T2 = 0xEA00, 640 OP_TST_reg_T2 = 0xEA10, 641 OP_ORR_reg_T2 = 0xEA40, 642 OP_ORR_S_reg_T2 = 0xEA50, 643 OP_ASR_imm_T1 = 0xEA4F, 644 OP_LSL_imm_T1 = 0xEA4F, 645 OP_LSR_imm_T1 = 0xEA4F, 646 OP_ROR_imm_T1 = 0xEA4F, 647 OP_MVN_reg_T2 = 0xEA6F, 648 OP_EOR_reg_T2 = 0xEA80, 649 OP_ADD_reg_T3 = 0xEB00, 650 OP_ADD_S_reg_T3 = 0xEB10, 651 OP_SUB_reg_T2 = 0xEBA0, 652 OP_SUB_S_reg_T2 = 0xEBB0, 653 OP_CMP_reg_T2 = 0xEBB0, 654 OP_VMOV_CtoD = 0xEC00, 655 OP_VMOV_DtoC = 0xEC10, 656 OP_FSTS = 0xED00, 657 OP_VSTR = 0xED00, 658 OP_FLDS = 0xED10, 659 OP_VLDR = 0xED10, 660 OP_VMOV_CtoS = 0xEE00, 661 OP_VMOV_StoC = 0xEE10, 662 OP_VMUL_T2 = 0xEE20, 663 OP_VADD_T2 = 0xEE30, 664 OP_VSUB_T2 = 0xEE30, 665 OP_VDIV = 0xEE80, 666 OP_VABS_T2 = 0xEEB0, 667 OP_VCMP = 0xEEB0, 668 OP_VCVT_FPIVFP = 0xEEB0, 669 OP_VMOV_T2 = 0xEEB0, 670 OP_VMOV_IMM_T2 = 0xEEB0, 671 OP_VMRS = 0xEEB0, 672 OP_VNEG_T2 = 0xEEB0, 673 OP_VSQRT_T1 = 0xEEB0, 674 OP_VCVTSD_T1 = 0xEEB0, 675 OP_VCVTDS_T1 = 0xEEB0, 676 OP_B_T3a = 0xF000, 677 OP_B_T4a = 0xF000, 678 OP_AND_imm_T1 = 0xF000, 679 OP_TST_imm = 0xF010, 680 OP_ORR_imm_T1 = 0xF040, 681 OP_MOV_imm_T2 = 0xF040, 682 OP_MVN_imm = 0xF060, 683 OP_EOR_imm_T1 = 0xF080, 684 OP_ADD_imm_T3 = 0xF100, 685 OP_ADD_S_imm_T3 = 0xF110, 686 OP_CMN_imm = 0xF110, 687 OP_ADC_imm = 0xF140, 688 OP_SUB_imm_T3 = 0xF1A0, 689 OP_SUB_S_imm_T3 = 0xF1B0, 690 OP_CMP_imm_T2 = 0xF1B0, 691 OP_RSB_imm_T2 = 0xF1C0, 692 OP_RSB_S_imm_T2 = 0xF1D0, 693 OP_ADD_imm_T4 = 0xF200, 694 OP_MOV_imm_T3 = 0xF240, 695 OP_SUB_imm_T4 = 0xF2A0, 696 OP_MOVT = 0xF2C0, 697 OP_UBFX_T1 = 0xF3C0, 698 OP_NOP_T2a = 0xF3AF, 699 OP_STRB_imm_T3 = 0xF800, 700 OP_STRB_reg_T2 = 0xF800, 701 OP_LDRB_imm_T3 = 0xF810, 702 OP_LDRB_reg_T2 = 0xF810, 703 OP_STRH_imm_T3 = 0xF820, 704 OP_STRH_reg_T2 = 0xF820, 705 OP_LDRH_reg_T2 = 0xF830, 706 OP_LDRH_imm_T3 = 0xF830, 707 OP_STR_imm_T4 = 0xF840, 708 OP_STR_reg_T2 = 0xF840, 709 OP_LDR_imm_T4 = 0xF850, 710 OP_LDR_reg_T2 = 0xF850, 711 OP_STRB_imm_T2 = 0xF880, 712 OP_LDRB_imm_T2 = 0xF890, 713 OP_STRH_imm_T2 = 0xF8A0, 714 OP_LDRH_imm_T2 = 0xF8B0, 715 OP_STR_imm_T3 = 0xF8C0, 716 OP_LDR_imm_T3 = 0xF8D0, 717 OP_LDRSB_reg_T2 = 0xF910, 718 OP_LDRSH_reg_T2 = 0xF930, 719 OP_LSL_reg_T2 = 0xFA00, 720 OP_LSR_reg_T2 = 0xFA20, 721 OP_ASR_reg_T2 = 0xFA40, 722 OP_ROR_reg_T2 = 0xFA60, 723 OP_CLZ = 0xFAB0, 724 OP_SMULL_T1 = 0xFB80, 725 #if CPU(APPLE_ARMV7S) 726 OP_SDIV_T1 = 0xFB90, 727 OP_UDIV_T1 = 0xFBB0, 728 #endif 729 } OpcodeID1; 730 731 typedef enum { 732 OP_VADD_T2b = 0x0A00, 733 OP_VDIVb = 0x0A00, 734 OP_FLDSb = 0x0A00, 735 OP_VLDRb = 0x0A00, 736 OP_VMOV_IMM_T2b = 0x0A00, 737 OP_VMOV_T2b = 0x0A40, 738 OP_VMUL_T2b = 0x0A00, 739 OP_FSTSb = 0x0A00, 740 OP_VSTRb = 0x0A00, 741 OP_VMOV_StoCb = 0x0A10, 742 OP_VMOV_CtoSb = 0x0A10, 743 OP_VMOV_DtoCb = 0x0A10, 744 OP_VMOV_CtoDb = 0x0A10, 745 OP_VMRSb = 0x0A10, 746 OP_VABS_T2b = 0x0A40, 747 OP_VCMPb = 0x0A40, 748 OP_VCVT_FPIVFPb = 0x0A40, 749 OP_VNEG_T2b = 0x0A40, 750 OP_VSUB_T2b = 0x0A40, 751 OP_VSQRT_T1b = 0x0A40, 752 OP_VCVTSD_T1b = 0x0A40, 753 OP_VCVTDS_T1b = 0x0A40, 754 OP_NOP_T2b = 0x8000, 755 OP_B_T3b = 0x8000, 756 OP_B_T4b = 0x9000, 757 } OpcodeID2; 758 759 struct FourFours { FourFoursFourFours760 FourFours(unsigned f3, unsigned f2, unsigned f1, unsigned f0) 761 { 762 m_u.f0 = f0; 763 m_u.f1 = f1; 764 m_u.f2 = f2; 765 m_u.f3 = f3; 766 } 767 768 union { 769 unsigned value; 770 struct { 771 unsigned f0 : 4; 772 unsigned f1 : 4; 773 unsigned f2 : 4; 774 unsigned f3 : 4; 775 }; 776 } m_u; 777 }; 778 779 class ARMInstructionFormatter; 780 781 // false means else! ifThenElseConditionBit(Condition condition,bool isIf)782 bool ifThenElseConditionBit(Condition condition, bool isIf) 783 { 784 return isIf ? (condition & 1) : !(condition & 1); 785 } ifThenElse(Condition condition,bool inst2if,bool inst3if,bool inst4if)786 uint8_t ifThenElse(Condition condition, bool inst2if, bool inst3if, bool inst4if) 787 { 788 int mask = (ifThenElseConditionBit(condition, inst2if) << 3) 789 | (ifThenElseConditionBit(condition, inst3if) << 2) 790 | (ifThenElseConditionBit(condition, inst4if) << 1) 791 | 1; 792 ASSERT((condition != ConditionAL) || !(mask & (mask - 1))); 793 return (condition << 4) | mask; 794 } ifThenElse(Condition condition,bool inst2if,bool inst3if)795 uint8_t ifThenElse(Condition condition, bool inst2if, bool inst3if) 796 { 797 int mask = (ifThenElseConditionBit(condition, inst2if) << 3) 798 | (ifThenElseConditionBit(condition, inst3if) << 2) 799 | 2; 800 ASSERT((condition != ConditionAL) || !(mask & (mask - 1))); 801 return (condition << 4) | mask; 802 } ifThenElse(Condition condition,bool inst2if)803 uint8_t ifThenElse(Condition condition, bool inst2if) 804 { 805 int mask = (ifThenElseConditionBit(condition, inst2if) << 3) 806 | 4; 807 ASSERT((condition != ConditionAL) || !(mask & (mask - 1))); 808 return (condition << 4) | mask; 809 } 810 ifThenElse(Condition condition)811 uint8_t ifThenElse(Condition condition) 812 { 813 int mask = 8; 814 return (condition << 4) | mask; 815 } 816 817 public: 818 adc(RegisterID rd,RegisterID rn,ARMThumbImmediate imm)819 void adc(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) 820 { 821 // Rd can only be SP if Rn is also SP. 822 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); 823 ASSERT(rd != ARMRegisters::pc); 824 ASSERT(rn != ARMRegisters::pc); 825 ASSERT(imm.isEncodedImm()); 826 827 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADC_imm, rn, rd, imm); 828 } 829 add(RegisterID rd,RegisterID rn,ARMThumbImmediate imm)830 void add(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) 831 { 832 // Rd can only be SP if Rn is also SP. 833 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); 834 ASSERT(rd != ARMRegisters::pc); 835 ASSERT(rn != ARMRegisters::pc); 836 ASSERT(imm.isValid()); 837 838 if (rn == ARMRegisters::sp) { 839 ASSERT(!(imm.getUInt16() & 3)); 840 if (!(rd & 8) && imm.isUInt10()) { 841 m_formatter.oneWordOp5Reg3Imm8(OP_ADD_SP_imm_T1, rd, static_cast<uint8_t>(imm.getUInt10() >> 2)); 842 return; 843 } else if ((rd == ARMRegisters::sp) && imm.isUInt9()) { 844 m_formatter.oneWordOp9Imm7(OP_ADD_SP_imm_T2, static_cast<uint8_t>(imm.getUInt9() >> 2)); 845 return; 846 } 847 } else if (!((rd | rn) & 8)) { 848 if (imm.isUInt3()) { 849 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_imm_T1, (RegisterID)imm.getUInt3(), rn, rd); 850 return; 851 } else if ((rd == rn) && imm.isUInt8()) { 852 m_formatter.oneWordOp5Reg3Imm8(OP_ADD_imm_T2, rd, imm.getUInt8()); 853 return; 854 } 855 } 856 857 if (imm.isEncodedImm()) 858 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T3, rn, rd, imm); 859 else { 860 ASSERT(imm.isUInt12()); 861 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T4, rn, rd, imm); 862 } 863 } 864 add(RegisterID rd,RegisterID rn,RegisterID rm,ShiftTypeAndAmount shift)865 ALWAYS_INLINE void add(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) 866 { 867 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); 868 ASSERT(rd != ARMRegisters::pc); 869 ASSERT(rn != ARMRegisters::pc); 870 ASSERT(!BadReg(rm)); 871 m_formatter.twoWordOp12Reg4FourFours(OP_ADD_reg_T3, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); 872 } 873 874 // NOTE: In an IT block, add doesn't modify the flags register. add(RegisterID rd,RegisterID rn,RegisterID rm)875 ALWAYS_INLINE void add(RegisterID rd, RegisterID rn, RegisterID rm) 876 { 877 if (rd == rn) 878 m_formatter.oneWordOp8RegReg143(OP_ADD_reg_T2, rm, rd); 879 else if (rd == rm) 880 m_formatter.oneWordOp8RegReg143(OP_ADD_reg_T2, rn, rd); 881 else if (!((rd | rn | rm) & 8)) 882 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_reg_T1, rm, rn, rd); 883 else 884 add(rd, rn, rm, ShiftTypeAndAmount()); 885 } 886 887 // Not allowed in an IT (if then) block. add_S(RegisterID rd,RegisterID rn,ARMThumbImmediate imm)888 ALWAYS_INLINE void add_S(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) 889 { 890 // Rd can only be SP if Rn is also SP. 891 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); 892 ASSERT(rd != ARMRegisters::pc); 893 ASSERT(rn != ARMRegisters::pc); 894 ASSERT(imm.isEncodedImm()); 895 896 if (!((rd | rn) & 8)) { 897 if (imm.isUInt3()) { 898 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_imm_T1, (RegisterID)imm.getUInt3(), rn, rd); 899 return; 900 } else if ((rd == rn) && imm.isUInt8()) { 901 m_formatter.oneWordOp5Reg3Imm8(OP_ADD_imm_T2, rd, imm.getUInt8()); 902 return; 903 } 904 } 905 906 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_S_imm_T3, rn, rd, imm); 907 } 908 909 // Not allowed in an IT (if then) block? add_S(RegisterID rd,RegisterID rn,RegisterID rm,ShiftTypeAndAmount shift)910 ALWAYS_INLINE void add_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) 911 { 912 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); 913 ASSERT(rd != ARMRegisters::pc); 914 ASSERT(rn != ARMRegisters::pc); 915 ASSERT(!BadReg(rm)); 916 m_formatter.twoWordOp12Reg4FourFours(OP_ADD_S_reg_T3, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); 917 } 918 919 // Not allowed in an IT (if then) block. add_S(RegisterID rd,RegisterID rn,RegisterID rm)920 ALWAYS_INLINE void add_S(RegisterID rd, RegisterID rn, RegisterID rm) 921 { 922 if (!((rd | rn | rm) & 8)) 923 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_reg_T1, rm, rn, rd); 924 else 925 add_S(rd, rn, rm, ShiftTypeAndAmount()); 926 } 927 ARM_and(RegisterID rd,RegisterID rn,ARMThumbImmediate imm)928 ALWAYS_INLINE void ARM_and(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) 929 { 930 ASSERT(!BadReg(rd)); 931 ASSERT(!BadReg(rn)); 932 ASSERT(imm.isEncodedImm()); 933 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_AND_imm_T1, rn, rd, imm); 934 } 935 ARM_and(RegisterID rd,RegisterID rn,RegisterID rm,ShiftTypeAndAmount shift)936 ALWAYS_INLINE void ARM_and(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) 937 { 938 ASSERT(!BadReg(rd)); 939 ASSERT(!BadReg(rn)); 940 ASSERT(!BadReg(rm)); 941 m_formatter.twoWordOp12Reg4FourFours(OP_AND_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); 942 } 943 ARM_and(RegisterID rd,RegisterID rn,RegisterID rm)944 ALWAYS_INLINE void ARM_and(RegisterID rd, RegisterID rn, RegisterID rm) 945 { 946 if ((rd == rn) && !((rd | rm) & 8)) 947 m_formatter.oneWordOp10Reg3Reg3(OP_AND_reg_T1, rm, rd); 948 else if ((rd == rm) && !((rd | rn) & 8)) 949 m_formatter.oneWordOp10Reg3Reg3(OP_AND_reg_T1, rn, rd); 950 else 951 ARM_and(rd, rn, rm, ShiftTypeAndAmount()); 952 } 953 asr(RegisterID rd,RegisterID rm,int32_t shiftAmount)954 ALWAYS_INLINE void asr(RegisterID rd, RegisterID rm, int32_t shiftAmount) 955 { 956 ASSERT(!BadReg(rd)); 957 ASSERT(!BadReg(rm)); 958 ShiftTypeAndAmount shift(SRType_ASR, shiftAmount); 959 m_formatter.twoWordOp16FourFours(OP_ASR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm)); 960 } 961 asr(RegisterID rd,RegisterID rn,RegisterID rm)962 ALWAYS_INLINE void asr(RegisterID rd, RegisterID rn, RegisterID rm) 963 { 964 ASSERT(!BadReg(rd)); 965 ASSERT(!BadReg(rn)); 966 ASSERT(!BadReg(rm)); 967 m_formatter.twoWordOp12Reg4FourFours(OP_ASR_reg_T2, rn, FourFours(0xf, rd, 0, rm)); 968 } 969 970 // Only allowed in IT (if then) block if last instruction. b()971 ALWAYS_INLINE AssemblerLabel b() 972 { 973 m_formatter.twoWordOp16Op16(OP_B_T4a, OP_B_T4b); 974 return m_formatter.label(); 975 } 976 977 // Only allowed in IT (if then) block if last instruction. blx(RegisterID rm)978 ALWAYS_INLINE AssemblerLabel blx(RegisterID rm) 979 { 980 ASSERT(rm != ARMRegisters::pc); 981 m_formatter.oneWordOp8RegReg143(OP_BLX, rm, (RegisterID)8); 982 return m_formatter.label(); 983 } 984 985 // Only allowed in IT (if then) block if last instruction. bx(RegisterID rm)986 ALWAYS_INLINE AssemblerLabel bx(RegisterID rm) 987 { 988 m_formatter.oneWordOp8RegReg143(OP_BX, rm, (RegisterID)0); 989 return m_formatter.label(); 990 } 991 992 void bkpt(uint8_t imm = 0) 993 { 994 m_formatter.oneWordOp8Imm8(OP_BKPT, imm); 995 } 996 clz(RegisterID rd,RegisterID rm)997 ALWAYS_INLINE void clz(RegisterID rd, RegisterID rm) 998 { 999 ASSERT(!BadReg(rd)); 1000 ASSERT(!BadReg(rm)); 1001 m_formatter.twoWordOp12Reg4FourFours(OP_CLZ, rm, FourFours(0xf, rd, 8, rm)); 1002 } 1003 cmn(RegisterID rn,ARMThumbImmediate imm)1004 ALWAYS_INLINE void cmn(RegisterID rn, ARMThumbImmediate imm) 1005 { 1006 ASSERT(rn != ARMRegisters::pc); 1007 ASSERT(imm.isEncodedImm()); 1008 1009 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMN_imm, rn, (RegisterID)0xf, imm); 1010 } 1011 cmp(RegisterID rn,ARMThumbImmediate imm)1012 ALWAYS_INLINE void cmp(RegisterID rn, ARMThumbImmediate imm) 1013 { 1014 ASSERT(rn != ARMRegisters::pc); 1015 ASSERT(imm.isEncodedImm()); 1016 1017 if (!(rn & 8) && imm.isUInt8()) 1018 m_formatter.oneWordOp5Reg3Imm8(OP_CMP_imm_T1, rn, imm.getUInt8()); 1019 else 1020 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMP_imm_T2, rn, (RegisterID)0xf, imm); 1021 } 1022 cmp(RegisterID rn,RegisterID rm,ShiftTypeAndAmount shift)1023 ALWAYS_INLINE void cmp(RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) 1024 { 1025 ASSERT(rn != ARMRegisters::pc); 1026 ASSERT(!BadReg(rm)); 1027 m_formatter.twoWordOp12Reg4FourFours(OP_CMP_reg_T2, rn, FourFours(shift.hi4(), 0xf, shift.lo4(), rm)); 1028 } 1029 cmp(RegisterID rn,RegisterID rm)1030 ALWAYS_INLINE void cmp(RegisterID rn, RegisterID rm) 1031 { 1032 if ((rn | rm) & 8) 1033 cmp(rn, rm, ShiftTypeAndAmount()); 1034 else 1035 m_formatter.oneWordOp10Reg3Reg3(OP_CMP_reg_T1, rm, rn); 1036 } 1037 1038 // xor is not spelled with an 'e'. :-( eor(RegisterID rd,RegisterID rn,ARMThumbImmediate imm)1039 ALWAYS_INLINE void eor(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) 1040 { 1041 ASSERT(!BadReg(rd)); 1042 ASSERT(!BadReg(rn)); 1043 ASSERT(imm.isEncodedImm()); 1044 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_EOR_imm_T1, rn, rd, imm); 1045 } 1046 1047 // xor is not spelled with an 'e'. :-( eor(RegisterID rd,RegisterID rn,RegisterID rm,ShiftTypeAndAmount shift)1048 ALWAYS_INLINE void eor(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) 1049 { 1050 ASSERT(!BadReg(rd)); 1051 ASSERT(!BadReg(rn)); 1052 ASSERT(!BadReg(rm)); 1053 m_formatter.twoWordOp12Reg4FourFours(OP_EOR_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); 1054 } 1055 1056 // xor is not spelled with an 'e'. :-( eor(RegisterID rd,RegisterID rn,RegisterID rm)1057 void eor(RegisterID rd, RegisterID rn, RegisterID rm) 1058 { 1059 if ((rd == rn) && !((rd | rm) & 8)) 1060 m_formatter.oneWordOp10Reg3Reg3(OP_EOR_reg_T1, rm, rd); 1061 else if ((rd == rm) && !((rd | rn) & 8)) 1062 m_formatter.oneWordOp10Reg3Reg3(OP_EOR_reg_T1, rn, rd); 1063 else 1064 eor(rd, rn, rm, ShiftTypeAndAmount()); 1065 } 1066 it(Condition cond)1067 ALWAYS_INLINE void it(Condition cond) 1068 { 1069 m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond)); 1070 } 1071 it(Condition cond,bool inst2if)1072 ALWAYS_INLINE void it(Condition cond, bool inst2if) 1073 { 1074 m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if)); 1075 } 1076 it(Condition cond,bool inst2if,bool inst3if)1077 ALWAYS_INLINE void it(Condition cond, bool inst2if, bool inst3if) 1078 { 1079 m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if, inst3if)); 1080 } 1081 it(Condition cond,bool inst2if,bool inst3if,bool inst4if)1082 ALWAYS_INLINE void it(Condition cond, bool inst2if, bool inst3if, bool inst4if) 1083 { 1084 m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if, inst3if, inst4if)); 1085 } 1086 1087 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. ldr(RegisterID rt,RegisterID rn,ARMThumbImmediate imm)1088 ALWAYS_INLINE void ldr(RegisterID rt, RegisterID rn, ARMThumbImmediate imm) 1089 { 1090 ASSERT(rn != ARMRegisters::pc); // LDR (literal) 1091 ASSERT(imm.isUInt12()); 1092 1093 if (!((rt | rn) & 8) && imm.isUInt7()) 1094 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDR_imm_T1, imm.getUInt7() >> 2, rn, rt); 1095 else if ((rn == ARMRegisters::sp) && !(rt & 8) && imm.isUInt10()) 1096 m_formatter.oneWordOp5Reg3Imm8(OP_LDR_imm_T2, rt, static_cast<uint8_t>(imm.getUInt10() >> 2)); 1097 else 1098 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T3, rn, rt, imm.getUInt12()); 1099 } 1100 ldrWide8BitImmediate(RegisterID rt,RegisterID rn,uint8_t immediate)1101 ALWAYS_INLINE void ldrWide8BitImmediate(RegisterID rt, RegisterID rn, uint8_t immediate) 1102 { 1103 ASSERT(rn != ARMRegisters::pc); 1104 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T3, rn, rt, immediate); 1105 } 1106 ldrCompact(RegisterID rt,RegisterID rn,ARMThumbImmediate imm)1107 ALWAYS_INLINE void ldrCompact(RegisterID rt, RegisterID rn, ARMThumbImmediate imm) 1108 { 1109 ASSERT(rn != ARMRegisters::pc); // LDR (literal) 1110 ASSERT(imm.isUInt7()); 1111 ASSERT(!((rt | rn) & 8)); 1112 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDR_imm_T1, imm.getUInt7() >> 2, rn, rt); 1113 } 1114 1115 // If index is set, this is a regular offset or a pre-indexed load; 1116 // if index is not set then is is a post-index load. 1117 // 1118 // If wback is set rn is updated - this is a pre or post index load, 1119 // if wback is not set this is a regular offset memory access. 1120 // 1121 // (-255 <= offset <= 255) 1122 // _reg = REG[rn] 1123 // _tmp = _reg + offset 1124 // MEM[index ? _tmp : _reg] = REG[rt] 1125 // if (wback) REG[rn] = _tmp ldr(RegisterID rt,RegisterID rn,int offset,bool index,bool wback)1126 ALWAYS_INLINE void ldr(RegisterID rt, RegisterID rn, int offset, bool index, bool wback) 1127 { 1128 ASSERT(rt != ARMRegisters::pc); 1129 ASSERT(rn != ARMRegisters::pc); 1130 ASSERT(index || wback); 1131 ASSERT(!wback | (rt != rn)); 1132 1133 bool add = true; 1134 if (offset < 0) { 1135 add = false; 1136 offset = -offset; 1137 } 1138 ASSERT((offset & ~0xff) == 0); 1139 1140 offset |= (wback << 8); 1141 offset |= (add << 9); 1142 offset |= (index << 10); 1143 offset |= (1 << 11); 1144 1145 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T4, rn, rt, offset); 1146 } 1147 1148 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. 1149 ALWAYS_INLINE void ldr(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0) 1150 { 1151 ASSERT(rn != ARMRegisters::pc); // LDR (literal) 1152 ASSERT(!BadReg(rm)); 1153 ASSERT(shift <= 3); 1154 1155 if (!shift && !((rt | rn | rm) & 8)) 1156 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDR_reg_T1, rm, rn, rt); 1157 else 1158 m_formatter.twoWordOp12Reg4FourFours(OP_LDR_reg_T2, rn, FourFours(rt, 0, shift, rm)); 1159 } 1160 1161 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. ldrh(RegisterID rt,RegisterID rn,ARMThumbImmediate imm)1162 ALWAYS_INLINE void ldrh(RegisterID rt, RegisterID rn, ARMThumbImmediate imm) 1163 { 1164 ASSERT(rn != ARMRegisters::pc); // LDR (literal) 1165 ASSERT(imm.isUInt12()); 1166 1167 if (!((rt | rn) & 8) && imm.isUInt6()) 1168 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDRH_imm_T1, imm.getUInt6() >> 2, rn, rt); 1169 else 1170 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T2, rn, rt, imm.getUInt12()); 1171 } 1172 1173 // If index is set, this is a regular offset or a pre-indexed load; 1174 // if index is not set then is is a post-index load. 1175 // 1176 // If wback is set rn is updated - this is a pre or post index load, 1177 // if wback is not set this is a regular offset memory access. 1178 // 1179 // (-255 <= offset <= 255) 1180 // _reg = REG[rn] 1181 // _tmp = _reg + offset 1182 // MEM[index ? _tmp : _reg] = REG[rt] 1183 // if (wback) REG[rn] = _tmp ldrh(RegisterID rt,RegisterID rn,int offset,bool index,bool wback)1184 ALWAYS_INLINE void ldrh(RegisterID rt, RegisterID rn, int offset, bool index, bool wback) 1185 { 1186 ASSERT(rt != ARMRegisters::pc); 1187 ASSERT(rn != ARMRegisters::pc); 1188 ASSERT(index || wback); 1189 ASSERT(!wback | (rt != rn)); 1190 1191 bool add = true; 1192 if (offset < 0) { 1193 add = false; 1194 offset = -offset; 1195 } 1196 ASSERT((offset & ~0xff) == 0); 1197 1198 offset |= (wback << 8); 1199 offset |= (add << 9); 1200 offset |= (index << 10); 1201 offset |= (1 << 11); 1202 1203 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T3, rn, rt, offset); 1204 } 1205 1206 ALWAYS_INLINE void ldrh(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0) 1207 { 1208 ASSERT(!BadReg(rt)); // Memory hint 1209 ASSERT(rn != ARMRegisters::pc); // LDRH (literal) 1210 ASSERT(!BadReg(rm)); 1211 ASSERT(shift <= 3); 1212 1213 if (!shift && !((rt | rn | rm) & 8)) 1214 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDRH_reg_T1, rm, rn, rt); 1215 else 1216 m_formatter.twoWordOp12Reg4FourFours(OP_LDRH_reg_T2, rn, FourFours(rt, 0, shift, rm)); 1217 } 1218 ldrb(RegisterID rt,RegisterID rn,ARMThumbImmediate imm)1219 void ldrb(RegisterID rt, RegisterID rn, ARMThumbImmediate imm) 1220 { 1221 ASSERT(rn != ARMRegisters::pc); // LDR (literal) 1222 ASSERT(imm.isUInt12()); 1223 1224 if (!((rt | rn) & 8) && imm.isUInt5()) 1225 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDRB_imm_T1, imm.getUInt5(), rn, rt); 1226 else 1227 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRB_imm_T2, rn, rt, imm.getUInt12()); 1228 } 1229 ldrb(RegisterID rt,RegisterID rn,int offset,bool index,bool wback)1230 void ldrb(RegisterID rt, RegisterID rn, int offset, bool index, bool wback) 1231 { 1232 ASSERT(rt != ARMRegisters::pc); 1233 ASSERT(rn != ARMRegisters::pc); 1234 ASSERT(index || wback); 1235 ASSERT(!wback | (rt != rn)); 1236 1237 bool add = true; 1238 if (offset < 0) { 1239 add = false; 1240 offset = -offset; 1241 } 1242 1243 ASSERT(!(offset & ~0xff)); 1244 1245 offset |= (wback << 8); 1246 offset |= (add << 9); 1247 offset |= (index << 10); 1248 offset |= (1 << 11); 1249 1250 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRB_imm_T3, rn, rt, offset); 1251 } 1252 1253 ALWAYS_INLINE void ldrb(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0) 1254 { 1255 ASSERT(rn != ARMRegisters::pc); // LDR (literal) 1256 ASSERT(!BadReg(rm)); 1257 ASSERT(shift <= 3); 1258 1259 if (!shift && !((rt | rn | rm) & 8)) 1260 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDRB_reg_T1, rm, rn, rt); 1261 else 1262 m_formatter.twoWordOp12Reg4FourFours(OP_LDRB_reg_T2, rn, FourFours(rt, 0, shift, rm)); 1263 } 1264 1265 void ldrsb(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0) 1266 { 1267 ASSERT(rn != ARMRegisters::pc); 1268 ASSERT(!BadReg(rm)); 1269 ASSERT(shift <= 3); 1270 1271 if (!shift && !((rt | rn | rm) & 8)) 1272 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDRSB_reg_T1, rm, rn, rt); 1273 else 1274 m_formatter.twoWordOp12Reg4FourFours(OP_LDRSB_reg_T2, rn, FourFours(rt, 0, shift, rm)); 1275 } 1276 1277 void ldrsh(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0) 1278 { 1279 ASSERT(rn != ARMRegisters::pc); 1280 ASSERT(!BadReg(rm)); 1281 ASSERT(shift <= 3); 1282 1283 if (!shift && !((rt | rn | rm) & 8)) 1284 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDRSH_reg_T1, rm, rn, rt); 1285 else 1286 m_formatter.twoWordOp12Reg4FourFours(OP_LDRSH_reg_T2, rn, FourFours(rt, 0, shift, rm)); 1287 } 1288 lsl(RegisterID rd,RegisterID rm,int32_t shiftAmount)1289 void lsl(RegisterID rd, RegisterID rm, int32_t shiftAmount) 1290 { 1291 ASSERT(!BadReg(rd)); 1292 ASSERT(!BadReg(rm)); 1293 ShiftTypeAndAmount shift(SRType_LSL, shiftAmount); 1294 m_formatter.twoWordOp16FourFours(OP_LSL_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm)); 1295 } 1296 lsl(RegisterID rd,RegisterID rn,RegisterID rm)1297 ALWAYS_INLINE void lsl(RegisterID rd, RegisterID rn, RegisterID rm) 1298 { 1299 ASSERT(!BadReg(rd)); 1300 ASSERT(!BadReg(rn)); 1301 ASSERT(!BadReg(rm)); 1302 m_formatter.twoWordOp12Reg4FourFours(OP_LSL_reg_T2, rn, FourFours(0xf, rd, 0, rm)); 1303 } 1304 lsr(RegisterID rd,RegisterID rm,int32_t shiftAmount)1305 ALWAYS_INLINE void lsr(RegisterID rd, RegisterID rm, int32_t shiftAmount) 1306 { 1307 ASSERT(!BadReg(rd)); 1308 ASSERT(!BadReg(rm)); 1309 ShiftTypeAndAmount shift(SRType_LSR, shiftAmount); 1310 m_formatter.twoWordOp16FourFours(OP_LSR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm)); 1311 } 1312 lsr(RegisterID rd,RegisterID rn,RegisterID rm)1313 ALWAYS_INLINE void lsr(RegisterID rd, RegisterID rn, RegisterID rm) 1314 { 1315 ASSERT(!BadReg(rd)); 1316 ASSERT(!BadReg(rn)); 1317 ASSERT(!BadReg(rm)); 1318 m_formatter.twoWordOp12Reg4FourFours(OP_LSR_reg_T2, rn, FourFours(0xf, rd, 0, rm)); 1319 } 1320 movT3(RegisterID rd,ARMThumbImmediate imm)1321 ALWAYS_INLINE void movT3(RegisterID rd, ARMThumbImmediate imm) 1322 { 1323 ASSERT(imm.isValid()); 1324 ASSERT(!imm.isEncodedImm()); 1325 ASSERT(!BadReg(rd)); 1326 1327 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T3, imm.m_value.imm4, rd, imm); 1328 } 1329 1330 #if OS(LINUX) || OS(QNX) revertJumpTo_movT3movtcmpT2(void * instructionStart,RegisterID left,RegisterID right,uintptr_t imm)1331 static void revertJumpTo_movT3movtcmpT2(void* instructionStart, RegisterID left, RegisterID right, uintptr_t imm) 1332 { 1333 uint16_t* address = static_cast<uint16_t*>(instructionStart); 1334 ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(imm)); 1335 ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(imm >> 16)); 1336 address[0] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16); 1337 address[1] = twoWordOp5i6Imm4Reg4EncodedImmSecond(right, lo16); 1338 address[2] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16); 1339 address[3] = twoWordOp5i6Imm4Reg4EncodedImmSecond(right, hi16); 1340 address[4] = OP_CMP_reg_T2 | left; 1341 cacheFlush(address, sizeof(uint16_t) * 5); 1342 } 1343 #else revertJumpTo_movT3(void * instructionStart,RegisterID rd,ARMThumbImmediate imm)1344 static void revertJumpTo_movT3(void* instructionStart, RegisterID rd, ARMThumbImmediate imm) 1345 { 1346 ASSERT(imm.isValid()); 1347 ASSERT(!imm.isEncodedImm()); 1348 ASSERT(!BadReg(rd)); 1349 1350 uint16_t* address = static_cast<uint16_t*>(instructionStart); 1351 address[0] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, imm); 1352 address[1] = twoWordOp5i6Imm4Reg4EncodedImmSecond(rd, imm); 1353 cacheFlush(address, sizeof(uint16_t) * 2); 1354 } 1355 #endif 1356 mov(RegisterID rd,ARMThumbImmediate imm)1357 ALWAYS_INLINE void mov(RegisterID rd, ARMThumbImmediate imm) 1358 { 1359 ASSERT(imm.isValid()); 1360 ASSERT(!BadReg(rd)); 1361 1362 if ((rd < 8) && imm.isUInt8()) 1363 m_formatter.oneWordOp5Reg3Imm8(OP_MOV_imm_T1, rd, imm.getUInt8()); 1364 else if (imm.isEncodedImm()) 1365 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T2, 0xf, rd, imm); 1366 else 1367 movT3(rd, imm); 1368 } 1369 mov(RegisterID rd,RegisterID rm)1370 ALWAYS_INLINE void mov(RegisterID rd, RegisterID rm) 1371 { 1372 m_formatter.oneWordOp8RegReg143(OP_MOV_reg_T1, rm, rd); 1373 } 1374 movt(RegisterID rd,ARMThumbImmediate imm)1375 ALWAYS_INLINE void movt(RegisterID rd, ARMThumbImmediate imm) 1376 { 1377 ASSERT(imm.isUInt16()); 1378 ASSERT(!BadReg(rd)); 1379 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOVT, imm.m_value.imm4, rd, imm); 1380 } 1381 mvn(RegisterID rd,ARMThumbImmediate imm)1382 ALWAYS_INLINE void mvn(RegisterID rd, ARMThumbImmediate imm) 1383 { 1384 ASSERT(imm.isEncodedImm()); 1385 ASSERT(!BadReg(rd)); 1386 1387 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MVN_imm, 0xf, rd, imm); 1388 } 1389 mvn(RegisterID rd,RegisterID rm,ShiftTypeAndAmount shift)1390 ALWAYS_INLINE void mvn(RegisterID rd, RegisterID rm, ShiftTypeAndAmount shift) 1391 { 1392 ASSERT(!BadReg(rd)); 1393 ASSERT(!BadReg(rm)); 1394 m_formatter.twoWordOp16FourFours(OP_MVN_reg_T2, FourFours(shift.hi4(), rd, shift.lo4(), rm)); 1395 } 1396 mvn(RegisterID rd,RegisterID rm)1397 ALWAYS_INLINE void mvn(RegisterID rd, RegisterID rm) 1398 { 1399 if (!((rd | rm) & 8)) 1400 m_formatter.oneWordOp10Reg3Reg3(OP_MVN_reg_T1, rm, rd); 1401 else 1402 mvn(rd, rm, ShiftTypeAndAmount()); 1403 } 1404 neg(RegisterID rd,RegisterID rm)1405 ALWAYS_INLINE void neg(RegisterID rd, RegisterID rm) 1406 { 1407 ARMThumbImmediate zero = ARMThumbImmediate::makeUInt12(0); 1408 sub(rd, zero, rm); 1409 } 1410 orr(RegisterID rd,RegisterID rn,ARMThumbImmediate imm)1411 ALWAYS_INLINE void orr(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) 1412 { 1413 ASSERT(!BadReg(rd)); 1414 ASSERT(!BadReg(rn)); 1415 ASSERT(imm.isEncodedImm()); 1416 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ORR_imm_T1, rn, rd, imm); 1417 } 1418 orr(RegisterID rd,RegisterID rn,RegisterID rm,ShiftTypeAndAmount shift)1419 ALWAYS_INLINE void orr(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) 1420 { 1421 ASSERT(!BadReg(rd)); 1422 ASSERT(!BadReg(rn)); 1423 ASSERT(!BadReg(rm)); 1424 m_formatter.twoWordOp12Reg4FourFours(OP_ORR_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); 1425 } 1426 orr(RegisterID rd,RegisterID rn,RegisterID rm)1427 void orr(RegisterID rd, RegisterID rn, RegisterID rm) 1428 { 1429 if ((rd == rn) && !((rd | rm) & 8)) 1430 m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rm, rd); 1431 else if ((rd == rm) && !((rd | rn) & 8)) 1432 m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rn, rd); 1433 else 1434 orr(rd, rn, rm, ShiftTypeAndAmount()); 1435 } 1436 orr_S(RegisterID rd,RegisterID rn,RegisterID rm,ShiftTypeAndAmount shift)1437 ALWAYS_INLINE void orr_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) 1438 { 1439 ASSERT(!BadReg(rd)); 1440 ASSERT(!BadReg(rn)); 1441 ASSERT(!BadReg(rm)); 1442 m_formatter.twoWordOp12Reg4FourFours(OP_ORR_S_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); 1443 } 1444 orr_S(RegisterID rd,RegisterID rn,RegisterID rm)1445 void orr_S(RegisterID rd, RegisterID rn, RegisterID rm) 1446 { 1447 if ((rd == rn) && !((rd | rm) & 8)) 1448 m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rm, rd); 1449 else if ((rd == rm) && !((rd | rn) & 8)) 1450 m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rn, rd); 1451 else 1452 orr_S(rd, rn, rm, ShiftTypeAndAmount()); 1453 } 1454 ror(RegisterID rd,RegisterID rm,int32_t shiftAmount)1455 ALWAYS_INLINE void ror(RegisterID rd, RegisterID rm, int32_t shiftAmount) 1456 { 1457 ASSERT(!BadReg(rd)); 1458 ASSERT(!BadReg(rm)); 1459 ShiftTypeAndAmount shift(SRType_ROR, shiftAmount); 1460 m_formatter.twoWordOp16FourFours(OP_ROR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm)); 1461 } 1462 ror(RegisterID rd,RegisterID rn,RegisterID rm)1463 ALWAYS_INLINE void ror(RegisterID rd, RegisterID rn, RegisterID rm) 1464 { 1465 ASSERT(!BadReg(rd)); 1466 ASSERT(!BadReg(rn)); 1467 ASSERT(!BadReg(rm)); 1468 m_formatter.twoWordOp12Reg4FourFours(OP_ROR_reg_T2, rn, FourFours(0xf, rd, 0, rm)); 1469 } 1470 1471 #if CPU(APPLE_ARMV7S) sdiv(RegisterID rd,RegisterID rn,RegisterID rm)1472 ALWAYS_INLINE void sdiv(RegisterID rd, RegisterID rn, RegisterID rm) 1473 { 1474 ASSERT(!BadReg(rd)); 1475 ASSERT(!BadReg(rn)); 1476 ASSERT(!BadReg(rm)); 1477 m_formatter.twoWordOp12Reg4FourFours(OP_SDIV_T1, rn, FourFours(0xf, rd, 0xf, rm)); 1478 } 1479 #endif 1480 smull(RegisterID rdLo,RegisterID rdHi,RegisterID rn,RegisterID rm)1481 ALWAYS_INLINE void smull(RegisterID rdLo, RegisterID rdHi, RegisterID rn, RegisterID rm) 1482 { 1483 ASSERT(!BadReg(rdLo)); 1484 ASSERT(!BadReg(rdHi)); 1485 ASSERT(!BadReg(rn)); 1486 ASSERT(!BadReg(rm)); 1487 ASSERT(rdLo != rdHi); 1488 m_formatter.twoWordOp12Reg4FourFours(OP_SMULL_T1, rn, FourFours(rdLo, rdHi, 0, rm)); 1489 } 1490 1491 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. str(RegisterID rt,RegisterID rn,ARMThumbImmediate imm)1492 ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, ARMThumbImmediate imm) 1493 { 1494 ASSERT(rt != ARMRegisters::pc); 1495 ASSERT(rn != ARMRegisters::pc); 1496 ASSERT(imm.isUInt12()); 1497 1498 if (!((rt | rn) & 8) && imm.isUInt7()) 1499 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_STR_imm_T1, imm.getUInt7() >> 2, rn, rt); 1500 else if ((rn == ARMRegisters::sp) && !(rt & 8) && imm.isUInt10()) 1501 m_formatter.oneWordOp5Reg3Imm8(OP_STR_imm_T2, rt, static_cast<uint8_t>(imm.getUInt10() >> 2)); 1502 else 1503 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T3, rn, rt, imm.getUInt12()); 1504 } 1505 1506 // If index is set, this is a regular offset or a pre-indexed store; 1507 // if index is not set then is is a post-index store. 1508 // 1509 // If wback is set rn is updated - this is a pre or post index store, 1510 // if wback is not set this is a regular offset memory access. 1511 // 1512 // (-255 <= offset <= 255) 1513 // _reg = REG[rn] 1514 // _tmp = _reg + offset 1515 // MEM[index ? _tmp : _reg] = REG[rt] 1516 // if (wback) REG[rn] = _tmp str(RegisterID rt,RegisterID rn,int offset,bool index,bool wback)1517 ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, int offset, bool index, bool wback) 1518 { 1519 ASSERT(rt != ARMRegisters::pc); 1520 ASSERT(rn != ARMRegisters::pc); 1521 ASSERT(index || wback); 1522 ASSERT(!wback | (rt != rn)); 1523 1524 bool add = true; 1525 if (offset < 0) { 1526 add = false; 1527 offset = -offset; 1528 } 1529 ASSERT((offset & ~0xff) == 0); 1530 1531 offset |= (wback << 8); 1532 offset |= (add << 9); 1533 offset |= (index << 10); 1534 offset |= (1 << 11); 1535 1536 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T4, rn, rt, offset); 1537 } 1538 1539 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. 1540 ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0) 1541 { 1542 ASSERT(rn != ARMRegisters::pc); 1543 ASSERT(!BadReg(rm)); 1544 ASSERT(shift <= 3); 1545 1546 if (!shift && !((rt | rn | rm) & 8)) 1547 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_STR_reg_T1, rm, rn, rt); 1548 else 1549 m_formatter.twoWordOp12Reg4FourFours(OP_STR_reg_T2, rn, FourFours(rt, 0, shift, rm)); 1550 } 1551 1552 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. strb(RegisterID rt,RegisterID rn,ARMThumbImmediate imm)1553 ALWAYS_INLINE void strb(RegisterID rt, RegisterID rn, ARMThumbImmediate imm) 1554 { 1555 ASSERT(rt != ARMRegisters::pc); 1556 ASSERT(rn != ARMRegisters::pc); 1557 ASSERT(imm.isUInt12()); 1558 1559 if (!((rt | rn) & 8) && imm.isUInt7()) 1560 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_STRB_imm_T1, imm.getUInt7() >> 2, rn, rt); 1561 else 1562 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STRB_imm_T2, rn, rt, imm.getUInt12()); 1563 } 1564 1565 // If index is set, this is a regular offset or a pre-indexed store; 1566 // if index is not set then is is a post-index store. 1567 // 1568 // If wback is set rn is updated - this is a pre or post index store, 1569 // if wback is not set this is a regular offset memory access. 1570 // 1571 // (-255 <= offset <= 255) 1572 // _reg = REG[rn] 1573 // _tmp = _reg + offset 1574 // MEM[index ? _tmp : _reg] = REG[rt] 1575 // if (wback) REG[rn] = _tmp strb(RegisterID rt,RegisterID rn,int offset,bool index,bool wback)1576 ALWAYS_INLINE void strb(RegisterID rt, RegisterID rn, int offset, bool index, bool wback) 1577 { 1578 ASSERT(rt != ARMRegisters::pc); 1579 ASSERT(rn != ARMRegisters::pc); 1580 ASSERT(index || wback); 1581 ASSERT(!wback | (rt != rn)); 1582 1583 bool add = true; 1584 if (offset < 0) { 1585 add = false; 1586 offset = -offset; 1587 } 1588 ASSERT((offset & ~0xff) == 0); 1589 1590 offset |= (wback << 8); 1591 offset |= (add << 9); 1592 offset |= (index << 10); 1593 offset |= (1 << 11); 1594 1595 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STRB_imm_T3, rn, rt, offset); 1596 } 1597 1598 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. 1599 ALWAYS_INLINE void strb(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0) 1600 { 1601 ASSERT(rn != ARMRegisters::pc); 1602 ASSERT(!BadReg(rm)); 1603 ASSERT(shift <= 3); 1604 1605 if (!shift && !((rt | rn | rm) & 8)) 1606 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_STRB_reg_T1, rm, rn, rt); 1607 else 1608 m_formatter.twoWordOp12Reg4FourFours(OP_STRB_reg_T2, rn, FourFours(rt, 0, shift, rm)); 1609 } 1610 1611 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. strh(RegisterID rt,RegisterID rn,ARMThumbImmediate imm)1612 ALWAYS_INLINE void strh(RegisterID rt, RegisterID rn, ARMThumbImmediate imm) 1613 { 1614 ASSERT(rt != ARMRegisters::pc); 1615 ASSERT(rn != ARMRegisters::pc); 1616 ASSERT(imm.isUInt12()); 1617 1618 if (!((rt | rn) & 8) && imm.isUInt7()) 1619 m_formatter.oneWordOp5Imm5Reg3Reg3(OP_STRH_imm_T1, imm.getUInt7() >> 2, rn, rt); 1620 else 1621 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STRH_imm_T2, rn, rt, imm.getUInt12()); 1622 } 1623 1624 // If index is set, this is a regular offset or a pre-indexed store; 1625 // if index is not set then is is a post-index store. 1626 // 1627 // If wback is set rn is updated - this is a pre or post index store, 1628 // if wback is not set this is a regular offset memory access. 1629 // 1630 // (-255 <= offset <= 255) 1631 // _reg = REG[rn] 1632 // _tmp = _reg + offset 1633 // MEM[index ? _tmp : _reg] = REG[rt] 1634 // if (wback) REG[rn] = _tmp strh(RegisterID rt,RegisterID rn,int offset,bool index,bool wback)1635 ALWAYS_INLINE void strh(RegisterID rt, RegisterID rn, int offset, bool index, bool wback) 1636 { 1637 ASSERT(rt != ARMRegisters::pc); 1638 ASSERT(rn != ARMRegisters::pc); 1639 ASSERT(index || wback); 1640 ASSERT(!wback | (rt != rn)); 1641 1642 bool add = true; 1643 if (offset < 0) { 1644 add = false; 1645 offset = -offset; 1646 } 1647 ASSERT(!(offset & ~0xff)); 1648 1649 offset |= (wback << 8); 1650 offset |= (add << 9); 1651 offset |= (index << 10); 1652 offset |= (1 << 11); 1653 1654 m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STRH_imm_T3, rn, rt, offset); 1655 } 1656 1657 // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. 1658 ALWAYS_INLINE void strh(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0) 1659 { 1660 ASSERT(rn != ARMRegisters::pc); 1661 ASSERT(!BadReg(rm)); 1662 ASSERT(shift <= 3); 1663 1664 if (!shift && !((rt | rn | rm) & 8)) 1665 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_STRH_reg_T1, rm, rn, rt); 1666 else 1667 m_formatter.twoWordOp12Reg4FourFours(OP_STRH_reg_T2, rn, FourFours(rt, 0, shift, rm)); 1668 } 1669 sub(RegisterID rd,RegisterID rn,ARMThumbImmediate imm)1670 ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) 1671 { 1672 // Rd can only be SP if Rn is also SP. 1673 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); 1674 ASSERT(rd != ARMRegisters::pc); 1675 ASSERT(rn != ARMRegisters::pc); 1676 ASSERT(imm.isValid()); 1677 1678 if ((rn == ARMRegisters::sp) && (rd == ARMRegisters::sp) && imm.isUInt9()) { 1679 ASSERT(!(imm.getUInt16() & 3)); 1680 m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, static_cast<uint8_t>(imm.getUInt9() >> 2)); 1681 return; 1682 } else if (!((rd | rn) & 8)) { 1683 if (imm.isUInt3()) { 1684 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_imm_T1, (RegisterID)imm.getUInt3(), rn, rd); 1685 return; 1686 } else if ((rd == rn) && imm.isUInt8()) { 1687 m_formatter.oneWordOp5Reg3Imm8(OP_SUB_imm_T2, rd, imm.getUInt8()); 1688 return; 1689 } 1690 } 1691 1692 if (imm.isEncodedImm()) 1693 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T3, rn, rd, imm); 1694 else { 1695 ASSERT(imm.isUInt12()); 1696 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T4, rn, rd, imm); 1697 } 1698 } 1699 sub(RegisterID rd,ARMThumbImmediate imm,RegisterID rn)1700 ALWAYS_INLINE void sub(RegisterID rd, ARMThumbImmediate imm, RegisterID rn) 1701 { 1702 ASSERT(rd != ARMRegisters::pc); 1703 ASSERT(rn != ARMRegisters::pc); 1704 ASSERT(imm.isValid()); 1705 ASSERT(imm.isUInt12()); 1706 1707 if (!((rd | rn) & 8) && !imm.getUInt12()) 1708 m_formatter.oneWordOp10Reg3Reg3(OP_RSB_imm_T1, rn, rd); 1709 else 1710 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_RSB_imm_T2, rn, rd, imm); 1711 } 1712 sub(RegisterID rd,RegisterID rn,RegisterID rm,ShiftTypeAndAmount shift)1713 ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) 1714 { 1715 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); 1716 ASSERT(rd != ARMRegisters::pc); 1717 ASSERT(rn != ARMRegisters::pc); 1718 ASSERT(!BadReg(rm)); 1719 m_formatter.twoWordOp12Reg4FourFours(OP_SUB_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); 1720 } 1721 1722 // NOTE: In an IT block, add doesn't modify the flags register. sub(RegisterID rd,RegisterID rn,RegisterID rm)1723 ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, RegisterID rm) 1724 { 1725 if (!((rd | rn | rm) & 8)) 1726 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_reg_T1, rm, rn, rd); 1727 else 1728 sub(rd, rn, rm, ShiftTypeAndAmount()); 1729 } 1730 1731 // Not allowed in an IT (if then) block. sub_S(RegisterID rd,RegisterID rn,ARMThumbImmediate imm)1732 void sub_S(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) 1733 { 1734 // Rd can only be SP if Rn is also SP. 1735 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); 1736 ASSERT(rd != ARMRegisters::pc); 1737 ASSERT(rn != ARMRegisters::pc); 1738 ASSERT(imm.isValid()); 1739 1740 if ((rn == ARMRegisters::sp) && (rd == ARMRegisters::sp) && imm.isUInt9()) { 1741 ASSERT(!(imm.getUInt16() & 3)); 1742 m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, static_cast<uint8_t>(imm.getUInt9() >> 2)); 1743 return; 1744 } else if (!((rd | rn) & 8)) { 1745 if (imm.isUInt3()) { 1746 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_imm_T1, (RegisterID)imm.getUInt3(), rn, rd); 1747 return; 1748 } else if ((rd == rn) && imm.isUInt8()) { 1749 m_formatter.oneWordOp5Reg3Imm8(OP_SUB_imm_T2, rd, imm.getUInt8()); 1750 return; 1751 } 1752 } 1753 1754 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_S_imm_T3, rn, rd, imm); 1755 } 1756 sub_S(RegisterID rd,ARMThumbImmediate imm,RegisterID rn)1757 ALWAYS_INLINE void sub_S(RegisterID rd, ARMThumbImmediate imm, RegisterID rn) 1758 { 1759 ASSERT(rd != ARMRegisters::pc); 1760 ASSERT(rn != ARMRegisters::pc); 1761 ASSERT(imm.isValid()); 1762 ASSERT(imm.isUInt12()); 1763 1764 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_RSB_S_imm_T2, rn, rd, imm); 1765 } 1766 1767 // Not allowed in an IT (if then) block? sub_S(RegisterID rd,RegisterID rn,RegisterID rm,ShiftTypeAndAmount shift)1768 ALWAYS_INLINE void sub_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) 1769 { 1770 ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); 1771 ASSERT(rd != ARMRegisters::pc); 1772 ASSERT(rn != ARMRegisters::pc); 1773 ASSERT(!BadReg(rm)); 1774 m_formatter.twoWordOp12Reg4FourFours(OP_SUB_S_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); 1775 } 1776 1777 // Not allowed in an IT (if then) block. sub_S(RegisterID rd,RegisterID rn,RegisterID rm)1778 ALWAYS_INLINE void sub_S(RegisterID rd, RegisterID rn, RegisterID rm) 1779 { 1780 if (!((rd | rn | rm) & 8)) 1781 m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_reg_T1, rm, rn, rd); 1782 else 1783 sub_S(rd, rn, rm, ShiftTypeAndAmount()); 1784 } 1785 tst(RegisterID rn,ARMThumbImmediate imm)1786 ALWAYS_INLINE void tst(RegisterID rn, ARMThumbImmediate imm) 1787 { 1788 ASSERT(!BadReg(rn)); 1789 ASSERT(imm.isEncodedImm()); 1790 1791 m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_TST_imm, rn, (RegisterID)0xf, imm); 1792 } 1793 tst(RegisterID rn,RegisterID rm,ShiftTypeAndAmount shift)1794 ALWAYS_INLINE void tst(RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) 1795 { 1796 ASSERT(!BadReg(rn)); 1797 ASSERT(!BadReg(rm)); 1798 m_formatter.twoWordOp12Reg4FourFours(OP_TST_reg_T2, rn, FourFours(shift.hi4(), 0xf, shift.lo4(), rm)); 1799 } 1800 tst(RegisterID rn,RegisterID rm)1801 ALWAYS_INLINE void tst(RegisterID rn, RegisterID rm) 1802 { 1803 if ((rn | rm) & 8) 1804 tst(rn, rm, ShiftTypeAndAmount()); 1805 else 1806 m_formatter.oneWordOp10Reg3Reg3(OP_TST_reg_T1, rm, rn); 1807 } 1808 ubfx(RegisterID rd,RegisterID rn,unsigned lsb,unsigned width)1809 ALWAYS_INLINE void ubfx(RegisterID rd, RegisterID rn, unsigned lsb, unsigned width) 1810 { 1811 ASSERT(lsb < 32); 1812 ASSERT((width >= 1) && (width <= 32)); 1813 ASSERT((lsb + width) <= 32); 1814 m_formatter.twoWordOp12Reg40Imm3Reg4Imm20Imm5(OP_UBFX_T1, rd, rn, (lsb & 0x1c) << 10, (lsb & 0x3) << 6, (width - 1) & 0x1f); 1815 } 1816 1817 #if CPU(APPLE_ARMV7S) udiv(RegisterID rd,RegisterID rn,RegisterID rm)1818 ALWAYS_INLINE void udiv(RegisterID rd, RegisterID rn, RegisterID rm) 1819 { 1820 ASSERT(!BadReg(rd)); 1821 ASSERT(!BadReg(rn)); 1822 ASSERT(!BadReg(rm)); 1823 m_formatter.twoWordOp12Reg4FourFours(OP_UDIV_T1, rn, FourFours(0xf, rd, 0xf, rm)); 1824 } 1825 #endif 1826 vadd(FPDoubleRegisterID rd,FPDoubleRegisterID rn,FPDoubleRegisterID rm)1827 void vadd(FPDoubleRegisterID rd, FPDoubleRegisterID rn, FPDoubleRegisterID rm) 1828 { 1829 m_formatter.vfpOp(OP_VADD_T2, OP_VADD_T2b, true, rn, rd, rm); 1830 } 1831 vcmp(FPDoubleRegisterID rd,FPDoubleRegisterID rm)1832 void vcmp(FPDoubleRegisterID rd, FPDoubleRegisterID rm) 1833 { 1834 m_formatter.vfpOp(OP_VCMP, OP_VCMPb, true, VFPOperand(4), rd, rm); 1835 } 1836 vcmpz(FPDoubleRegisterID rd)1837 void vcmpz(FPDoubleRegisterID rd) 1838 { 1839 m_formatter.vfpOp(OP_VCMP, OP_VCMPb, true, VFPOperand(5), rd, VFPOperand(0)); 1840 } 1841 vcvt_signedToFloatingPoint(FPDoubleRegisterID rd,FPSingleRegisterID rm)1842 void vcvt_signedToFloatingPoint(FPDoubleRegisterID rd, FPSingleRegisterID rm) 1843 { 1844 // boolean values are 64bit (toInt, unsigned, roundZero) 1845 m_formatter.vfpOp(OP_VCVT_FPIVFP, OP_VCVT_FPIVFPb, true, vcvtOp(false, false, false), rd, rm); 1846 } 1847 vcvt_floatingPointToSigned(FPSingleRegisterID rd,FPDoubleRegisterID rm)1848 void vcvt_floatingPointToSigned(FPSingleRegisterID rd, FPDoubleRegisterID rm) 1849 { 1850 // boolean values are 64bit (toInt, unsigned, roundZero) 1851 m_formatter.vfpOp(OP_VCVT_FPIVFP, OP_VCVT_FPIVFPb, true, vcvtOp(true, false, true), rd, rm); 1852 } 1853 vcvt_unsignedToFloatingPoint(FPDoubleRegisterID rd,FPSingleRegisterID rm)1854 void vcvt_unsignedToFloatingPoint(FPDoubleRegisterID rd, FPSingleRegisterID rm) 1855 { 1856 // boolean values are 64bit (toInt, unsigned, roundZero) 1857 m_formatter.vfpOp(OP_VCVT_FPIVFP, OP_VCVT_FPIVFPb, true, vcvtOp(false, true, false), rd, rm); 1858 } 1859 vcvt_floatingPointToUnsigned(FPSingleRegisterID rd,FPDoubleRegisterID rm)1860 void vcvt_floatingPointToUnsigned(FPSingleRegisterID rd, FPDoubleRegisterID rm) 1861 { 1862 // boolean values are 64bit (toInt, unsigned, roundZero) 1863 m_formatter.vfpOp(OP_VCVT_FPIVFP, OP_VCVT_FPIVFPb, true, vcvtOp(true, true, true), rd, rm); 1864 } 1865 vdiv(FPDoubleRegisterID rd,FPDoubleRegisterID rn,FPDoubleRegisterID rm)1866 void vdiv(FPDoubleRegisterID rd, FPDoubleRegisterID rn, FPDoubleRegisterID rm) 1867 { 1868 m_formatter.vfpOp(OP_VDIV, OP_VDIVb, true, rn, rd, rm); 1869 } 1870 vldr(FPDoubleRegisterID rd,RegisterID rn,int32_t imm)1871 void vldr(FPDoubleRegisterID rd, RegisterID rn, int32_t imm) 1872 { 1873 m_formatter.vfpMemOp(OP_VLDR, OP_VLDRb, true, rn, rd, imm); 1874 } 1875 flds(FPSingleRegisterID rd,RegisterID rn,int32_t imm)1876 void flds(FPSingleRegisterID rd, RegisterID rn, int32_t imm) 1877 { 1878 m_formatter.vfpMemOp(OP_FLDS, OP_FLDSb, false, rn, rd, imm); 1879 } 1880 vmov(RegisterID rd,FPSingleRegisterID rn)1881 void vmov(RegisterID rd, FPSingleRegisterID rn) 1882 { 1883 ASSERT(!BadReg(rd)); 1884 m_formatter.vfpOp(OP_VMOV_StoC, OP_VMOV_StoCb, false, rn, rd, VFPOperand(0)); 1885 } 1886 vmov(FPSingleRegisterID rd,RegisterID rn)1887 void vmov(FPSingleRegisterID rd, RegisterID rn) 1888 { 1889 ASSERT(!BadReg(rn)); 1890 m_formatter.vfpOp(OP_VMOV_CtoS, OP_VMOV_CtoSb, false, rd, rn, VFPOperand(0)); 1891 } 1892 vmov(RegisterID rd1,RegisterID rd2,FPDoubleRegisterID rn)1893 void vmov(RegisterID rd1, RegisterID rd2, FPDoubleRegisterID rn) 1894 { 1895 ASSERT(!BadReg(rd1)); 1896 ASSERT(!BadReg(rd2)); 1897 m_formatter.vfpOp(OP_VMOV_DtoC, OP_VMOV_DtoCb, true, rd2, VFPOperand(rd1 | 16), rn); 1898 } 1899 vmov(FPDoubleRegisterID rd,RegisterID rn1,RegisterID rn2)1900 void vmov(FPDoubleRegisterID rd, RegisterID rn1, RegisterID rn2) 1901 { 1902 ASSERT(!BadReg(rn1)); 1903 ASSERT(!BadReg(rn2)); 1904 m_formatter.vfpOp(OP_VMOV_CtoD, OP_VMOV_CtoDb, true, rn2, VFPOperand(rn1 | 16), rd); 1905 } 1906 vmov(FPDoubleRegisterID rd,FPDoubleRegisterID rn)1907 void vmov(FPDoubleRegisterID rd, FPDoubleRegisterID rn) 1908 { 1909 m_formatter.vfpOp(OP_VMOV_T2, OP_VMOV_T2b, true, VFPOperand(0), rd, rn); 1910 } 1911 1912 void vmrs(RegisterID reg = ARMRegisters::pc) 1913 { 1914 ASSERT(reg != ARMRegisters::sp); 1915 m_formatter.vfpOp(OP_VMRS, OP_VMRSb, false, VFPOperand(1), VFPOperand(0x10 | reg), VFPOperand(0)); 1916 } 1917 vmul(FPDoubleRegisterID rd,FPDoubleRegisterID rn,FPDoubleRegisterID rm)1918 void vmul(FPDoubleRegisterID rd, FPDoubleRegisterID rn, FPDoubleRegisterID rm) 1919 { 1920 m_formatter.vfpOp(OP_VMUL_T2, OP_VMUL_T2b, true, rn, rd, rm); 1921 } 1922 vstr(FPDoubleRegisterID rd,RegisterID rn,int32_t imm)1923 void vstr(FPDoubleRegisterID rd, RegisterID rn, int32_t imm) 1924 { 1925 m_formatter.vfpMemOp(OP_VSTR, OP_VSTRb, true, rn, rd, imm); 1926 } 1927 fsts(FPSingleRegisterID rd,RegisterID rn,int32_t imm)1928 void fsts(FPSingleRegisterID rd, RegisterID rn, int32_t imm) 1929 { 1930 m_formatter.vfpMemOp(OP_FSTS, OP_FSTSb, false, rn, rd, imm); 1931 } 1932 vsub(FPDoubleRegisterID rd,FPDoubleRegisterID rn,FPDoubleRegisterID rm)1933 void vsub(FPDoubleRegisterID rd, FPDoubleRegisterID rn, FPDoubleRegisterID rm) 1934 { 1935 m_formatter.vfpOp(OP_VSUB_T2, OP_VSUB_T2b, true, rn, rd, rm); 1936 } 1937 vabs(FPDoubleRegisterID rd,FPDoubleRegisterID rm)1938 void vabs(FPDoubleRegisterID rd, FPDoubleRegisterID rm) 1939 { 1940 m_formatter.vfpOp(OP_VABS_T2, OP_VABS_T2b, true, VFPOperand(16), rd, rm); 1941 } 1942 vneg(FPDoubleRegisterID rd,FPDoubleRegisterID rm)1943 void vneg(FPDoubleRegisterID rd, FPDoubleRegisterID rm) 1944 { 1945 m_formatter.vfpOp(OP_VNEG_T2, OP_VNEG_T2b, true, VFPOperand(1), rd, rm); 1946 } 1947 vsqrt(FPDoubleRegisterID rd,FPDoubleRegisterID rm)1948 void vsqrt(FPDoubleRegisterID rd, FPDoubleRegisterID rm) 1949 { 1950 m_formatter.vfpOp(OP_VSQRT_T1, OP_VSQRT_T1b, true, VFPOperand(17), rd, rm); 1951 } 1952 vcvtds(FPDoubleRegisterID rd,FPSingleRegisterID rm)1953 void vcvtds(FPDoubleRegisterID rd, FPSingleRegisterID rm) 1954 { 1955 m_formatter.vfpOp(OP_VCVTDS_T1, OP_VCVTDS_T1b, false, VFPOperand(23), rd, rm); 1956 } 1957 vcvtsd(FPSingleRegisterID rd,FPDoubleRegisterID rm)1958 void vcvtsd(FPSingleRegisterID rd, FPDoubleRegisterID rm) 1959 { 1960 m_formatter.vfpOp(OP_VCVTSD_T1, OP_VCVTSD_T1b, true, VFPOperand(23), rd, rm); 1961 } 1962 nop()1963 void nop() 1964 { 1965 m_formatter.oneWordOp8Imm8(OP_NOP_T1, 0); 1966 } 1967 nopw()1968 void nopw() 1969 { 1970 m_formatter.twoWordOp16Op16(OP_NOP_T2a, OP_NOP_T2b); 1971 } 1972 labelIgnoringWatchpoints()1973 AssemblerLabel labelIgnoringWatchpoints() 1974 { 1975 return m_formatter.label(); 1976 } 1977 labelForWatchpoint()1978 AssemblerLabel labelForWatchpoint() 1979 { 1980 AssemblerLabel result = m_formatter.label(); 1981 if (static_cast<int>(result.m_offset) != m_indexOfLastWatchpoint) 1982 result = label(); 1983 m_indexOfLastWatchpoint = result.m_offset; 1984 m_indexOfTailOfLastWatchpoint = result.m_offset + maxJumpReplacementSize(); 1985 return result; 1986 } 1987 label()1988 AssemblerLabel label() 1989 { 1990 AssemblerLabel result = m_formatter.label(); 1991 while (UNLIKELY(static_cast<int>(result.m_offset) < m_indexOfTailOfLastWatchpoint)) { 1992 if (UNLIKELY(static_cast<int>(result.m_offset) + 4 <= m_indexOfTailOfLastWatchpoint)) 1993 nopw(); 1994 else 1995 nop(); 1996 result = m_formatter.label(); 1997 } 1998 return result; 1999 } 2000 align(int alignment)2001 AssemblerLabel align(int alignment) 2002 { 2003 while (!m_formatter.isAligned(alignment)) 2004 bkpt(); 2005 2006 return label(); 2007 } 2008 getRelocatedAddress(void * code,AssemblerLabel label)2009 static void* getRelocatedAddress(void* code, AssemblerLabel label) 2010 { 2011 ASSERT(label.isSet()); 2012 return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + label.m_offset); 2013 } 2014 getDifferenceBetweenLabels(AssemblerLabel a,AssemblerLabel b)2015 static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b) 2016 { 2017 return b.m_offset - a.m_offset; 2018 } 2019 executableOffsetFor(int location)2020 int executableOffsetFor(int location) 2021 { 2022 if (!location) 2023 return 0; 2024 return static_cast<int32_t*>(m_formatter.data())[location / sizeof(int32_t) - 1]; 2025 } 2026 jumpSizeDelta(JumpType jumpType,JumpLinkType jumpLinkType)2027 int jumpSizeDelta(JumpType jumpType, JumpLinkType jumpLinkType) { return JUMP_ENUM_SIZE(jumpType) - JUMP_ENUM_SIZE(jumpLinkType); } 2028 2029 // Assembler admin methods: 2030 linkRecordSourceComparator(const LinkRecord & a,const LinkRecord & b)2031 static ALWAYS_INLINE bool linkRecordSourceComparator(const LinkRecord& a, const LinkRecord& b) 2032 { 2033 return a.from() < b.from(); 2034 } 2035 canCompact(JumpType jumpType)2036 bool canCompact(JumpType jumpType) 2037 { 2038 // The following cannot be compacted: 2039 // JumpFixed: represents custom jump sequence 2040 // JumpNoConditionFixedSize: represents unconditional jump that must remain a fixed size 2041 // JumpConditionFixedSize: represents conditional jump that must remain a fixed size 2042 return (jumpType == JumpNoCondition) || (jumpType == JumpCondition); 2043 } 2044 computeJumpType(JumpType jumpType,const uint8_t * from,const uint8_t * to)2045 JumpLinkType computeJumpType(JumpType jumpType, const uint8_t* from, const uint8_t* to) 2046 { 2047 if (jumpType == JumpFixed) 2048 return LinkInvalid; 2049 2050 // for patchable jump we must leave space for the longest code sequence 2051 if (jumpType == JumpNoConditionFixedSize) 2052 return LinkBX; 2053 if (jumpType == JumpConditionFixedSize) 2054 return LinkConditionalBX; 2055 2056 const int paddingSize = JUMP_ENUM_SIZE(jumpType); 2057 2058 if (jumpType == JumpCondition) { 2059 // 2-byte conditional T1 2060 const uint16_t* jumpT1Location = reinterpret_cast_ptr<const uint16_t*>(from - (paddingSize - JUMP_ENUM_SIZE(LinkJumpT1))); 2061 if (canBeJumpT1(jumpT1Location, to)) 2062 return LinkJumpT1; 2063 // 4-byte conditional T3 2064 const uint16_t* jumpT3Location = reinterpret_cast_ptr<const uint16_t*>(from - (paddingSize - JUMP_ENUM_SIZE(LinkJumpT3))); 2065 if (canBeJumpT3(jumpT3Location, to)) 2066 return LinkJumpT3; 2067 // 4-byte conditional T4 with IT 2068 const uint16_t* conditionalJumpT4Location = 2069 reinterpret_cast_ptr<const uint16_t*>(from - (paddingSize - JUMP_ENUM_SIZE(LinkConditionalJumpT4))); 2070 if (canBeJumpT4(conditionalJumpT4Location, to)) 2071 return LinkConditionalJumpT4; 2072 } else { 2073 // 2-byte unconditional T2 2074 const uint16_t* jumpT2Location = reinterpret_cast_ptr<const uint16_t*>(from - (paddingSize - JUMP_ENUM_SIZE(LinkJumpT2))); 2075 if (canBeJumpT2(jumpT2Location, to)) 2076 return LinkJumpT2; 2077 // 4-byte unconditional T4 2078 const uint16_t* jumpT4Location = reinterpret_cast_ptr<const uint16_t*>(from - (paddingSize - JUMP_ENUM_SIZE(LinkJumpT4))); 2079 if (canBeJumpT4(jumpT4Location, to)) 2080 return LinkJumpT4; 2081 // use long jump sequence 2082 return LinkBX; 2083 } 2084 2085 ASSERT(jumpType == JumpCondition); 2086 return LinkConditionalBX; 2087 } 2088 computeJumpType(LinkRecord & record,const uint8_t * from,const uint8_t * to)2089 JumpLinkType computeJumpType(LinkRecord& record, const uint8_t* from, const uint8_t* to) 2090 { 2091 JumpLinkType linkType = computeJumpType(record.type(), from, to); 2092 record.setLinkType(linkType); 2093 return linkType; 2094 } 2095 recordLinkOffsets(int32_t regionStart,int32_t regionEnd,int32_t offset)2096 void recordLinkOffsets(int32_t regionStart, int32_t regionEnd, int32_t offset) 2097 { 2098 int32_t ptr = regionStart / sizeof(int32_t); 2099 const int32_t end = regionEnd / sizeof(int32_t); 2100 int32_t* offsets = static_cast<int32_t*>(m_formatter.data()); 2101 while (ptr < end) 2102 offsets[ptr++] = offset; 2103 } 2104 jumpsToLink()2105 Vector<LinkRecord, 0, UnsafeVectorOverflow>& jumpsToLink() 2106 { 2107 std::sort(m_jumpsToLink.begin(), m_jumpsToLink.end(), linkRecordSourceComparator); 2108 return m_jumpsToLink; 2109 } 2110 link(LinkRecord & record,uint8_t * from,uint8_t * to)2111 void ALWAYS_INLINE link(LinkRecord& record, uint8_t* from, uint8_t* to) 2112 { 2113 switch (record.linkType()) { 2114 case LinkJumpT1: 2115 linkJumpT1(record.condition(), reinterpret_cast_ptr<uint16_t*>(from), to); 2116 break; 2117 case LinkJumpT2: 2118 linkJumpT2(reinterpret_cast_ptr<uint16_t*>(from), to); 2119 break; 2120 case LinkJumpT3: 2121 linkJumpT3(record.condition(), reinterpret_cast_ptr<uint16_t*>(from), to); 2122 break; 2123 case LinkJumpT4: 2124 linkJumpT4(reinterpret_cast_ptr<uint16_t*>(from), to); 2125 break; 2126 case LinkConditionalJumpT4: 2127 linkConditionalJumpT4(record.condition(), reinterpret_cast_ptr<uint16_t*>(from), to); 2128 break; 2129 case LinkConditionalBX: 2130 linkConditionalBX(record.condition(), reinterpret_cast_ptr<uint16_t*>(from), to); 2131 break; 2132 case LinkBX: 2133 linkBX(reinterpret_cast_ptr<uint16_t*>(from), to); 2134 break; 2135 default: 2136 RELEASE_ASSERT_NOT_REACHED(); 2137 break; 2138 } 2139 } 2140 unlinkedCode()2141 void* unlinkedCode() { return m_formatter.data(); } codeSize()2142 size_t codeSize() const { return m_formatter.codeSize(); } 2143 getCallReturnOffset(AssemblerLabel call)2144 static unsigned getCallReturnOffset(AssemblerLabel call) 2145 { 2146 ASSERT(call.isSet()); 2147 return call.m_offset; 2148 } 2149 2150 // Linking & patching: 2151 // 2152 // 'link' and 'patch' methods are for use on unprotected code - such as the code 2153 // within the AssemblerBuffer, and code being patched by the patch buffer. Once 2154 // code has been finalized it is (platform support permitting) within a non- 2155 // writable region of memory; to modify the code in an execute-only execuable 2156 // pool the 'repatch' and 'relink' methods should be used. 2157 linkJump(AssemblerLabel from,AssemblerLabel to,JumpType type,Condition condition)2158 void linkJump(AssemblerLabel from, AssemblerLabel to, JumpType type, Condition condition) 2159 { 2160 ASSERT(to.isSet()); 2161 ASSERT(from.isSet()); 2162 m_jumpsToLink.append(LinkRecord(from.m_offset, to.m_offset, type, condition)); 2163 } 2164 linkJump(void * code,AssemblerLabel from,void * to)2165 static void linkJump(void* code, AssemblerLabel from, void* to) 2166 { 2167 ASSERT(from.isSet()); 2168 2169 uint16_t* location = reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code) + from.m_offset); 2170 linkJumpAbsolute(location, to); 2171 } 2172 linkCall(void * code,AssemblerLabel from,void * to)2173 static void linkCall(void* code, AssemblerLabel from, void* to) 2174 { 2175 ASSERT(!(reinterpret_cast<intptr_t>(code) & 1)); 2176 ASSERT(from.isSet()); 2177 ASSERT_VALID_CODE_POINTER(to); 2178 2179 setPointer(reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code) + from.m_offset) - 1, to, false); 2180 } 2181 linkPointer(void * code,AssemblerLabel where,void * value)2182 static void linkPointer(void* code, AssemblerLabel where, void* value) 2183 { 2184 setPointer(reinterpret_cast<char*>(code) + where.m_offset, value, false); 2185 } 2186 relinkJump(void * from,void * to)2187 static void relinkJump(void* from, void* to) 2188 { 2189 ASSERT(!(reinterpret_cast<intptr_t>(from) & 1)); 2190 ASSERT(!(reinterpret_cast<intptr_t>(to) & 1)); 2191 2192 linkJumpAbsolute(reinterpret_cast<uint16_t*>(from), to); 2193 2194 cacheFlush(reinterpret_cast<uint16_t*>(from) - 5, 5 * sizeof(uint16_t)); 2195 } 2196 relinkCall(void * from,void * to)2197 static void relinkCall(void* from, void* to) 2198 { 2199 ASSERT(!(reinterpret_cast<intptr_t>(from) & 1)); 2200 ASSERT(reinterpret_cast<intptr_t>(to) & 1); 2201 2202 setPointer(reinterpret_cast<uint16_t*>(from) - 1, to, true); 2203 } 2204 readCallTarget(void * from)2205 static void* readCallTarget(void* from) 2206 { 2207 return readPointer(reinterpret_cast<uint16_t*>(from) - 1); 2208 } 2209 repatchInt32(void * where,int32_t value)2210 static void repatchInt32(void* where, int32_t value) 2211 { 2212 ASSERT(!(reinterpret_cast<intptr_t>(where) & 1)); 2213 2214 setInt32(where, value, true); 2215 } 2216 repatchCompact(void * where,int32_t offset)2217 static void repatchCompact(void* where, int32_t offset) 2218 { 2219 ASSERT(offset >= -255 && offset <= 255); 2220 2221 bool add = true; 2222 if (offset < 0) { 2223 add = false; 2224 offset = -offset; 2225 } 2226 2227 offset |= (add << 9); 2228 offset |= (1 << 10); 2229 offset |= (1 << 11); 2230 2231 uint16_t* location = reinterpret_cast<uint16_t*>(where); 2232 location[1] &= ~((1 << 12) - 1); 2233 location[1] |= offset; 2234 cacheFlush(location, sizeof(uint16_t) * 2); 2235 } 2236 repatchPointer(void * where,void * value)2237 static void repatchPointer(void* where, void* value) 2238 { 2239 ASSERT(!(reinterpret_cast<intptr_t>(where) & 1)); 2240 2241 setPointer(where, value, true); 2242 } 2243 readPointer(void * where)2244 static void* readPointer(void* where) 2245 { 2246 return reinterpret_cast<void*>(readInt32(where)); 2247 } 2248 replaceWithJump(void * instructionStart,void * to)2249 static void replaceWithJump(void* instructionStart, void* to) 2250 { 2251 ASSERT(!(bitwise_cast<uintptr_t>(instructionStart) & 1)); 2252 ASSERT(!(bitwise_cast<uintptr_t>(to) & 1)); 2253 2254 #if OS(LINUX) || OS(QNX) 2255 if (canBeJumpT4(reinterpret_cast<uint16_t*>(instructionStart), to)) { 2256 uint16_t* ptr = reinterpret_cast<uint16_t*>(instructionStart) + 2; 2257 linkJumpT4(ptr, to); 2258 cacheFlush(ptr - 2, sizeof(uint16_t) * 2); 2259 } else { 2260 uint16_t* ptr = reinterpret_cast<uint16_t*>(instructionStart) + 5; 2261 linkBX(ptr, to); 2262 cacheFlush(ptr - 5, sizeof(uint16_t) * 5); 2263 } 2264 #else 2265 uint16_t* ptr = reinterpret_cast<uint16_t*>(instructionStart) + 2; 2266 linkJumpT4(ptr, to); 2267 cacheFlush(ptr - 2, sizeof(uint16_t) * 2); 2268 #endif 2269 } 2270 maxJumpReplacementSize()2271 static ptrdiff_t maxJumpReplacementSize() 2272 { 2273 #if OS(LINUX) || OS(QNX) 2274 return 10; 2275 #else 2276 return 4; 2277 #endif 2278 } 2279 replaceWithLoad(void * instructionStart)2280 static void replaceWithLoad(void* instructionStart) 2281 { 2282 ASSERT(!(bitwise_cast<uintptr_t>(instructionStart) & 1)); 2283 uint16_t* ptr = reinterpret_cast<uint16_t*>(instructionStart); 2284 switch (ptr[0] & 0xFFF0) { 2285 case OP_LDR_imm_T3: 2286 break; 2287 case OP_ADD_imm_T3: 2288 ASSERT(!(ptr[1] & 0xF000)); 2289 ptr[0] &= 0x000F; 2290 ptr[0] |= OP_LDR_imm_T3; 2291 ptr[1] |= (ptr[1] & 0x0F00) << 4; 2292 ptr[1] &= 0xF0FF; 2293 cacheFlush(ptr, sizeof(uint16_t) * 2); 2294 break; 2295 default: 2296 RELEASE_ASSERT_NOT_REACHED(); 2297 } 2298 } 2299 replaceWithAddressComputation(void * instructionStart)2300 static void replaceWithAddressComputation(void* instructionStart) 2301 { 2302 ASSERT(!(bitwise_cast<uintptr_t>(instructionStart) & 1)); 2303 uint16_t* ptr = reinterpret_cast<uint16_t*>(instructionStart); 2304 switch (ptr[0] & 0xFFF0) { 2305 case OP_LDR_imm_T3: 2306 ASSERT(!(ptr[1] & 0x0F00)); 2307 ptr[0] &= 0x000F; 2308 ptr[0] |= OP_ADD_imm_T3; 2309 ptr[1] |= (ptr[1] & 0xF000) >> 4; 2310 ptr[1] &= 0x0FFF; 2311 cacheFlush(ptr, sizeof(uint16_t) * 2); 2312 break; 2313 case OP_ADD_imm_T3: 2314 break; 2315 default: 2316 RELEASE_ASSERT_NOT_REACHED(); 2317 } 2318 } 2319 debugOffset()2320 unsigned debugOffset() { return m_formatter.debugOffset(); } 2321 2322 #if OS(LINUX) linuxPageFlush(uintptr_t begin,uintptr_t end)2323 static inline void linuxPageFlush(uintptr_t begin, uintptr_t end) 2324 { 2325 asm volatile( 2326 "push {r7}\n" 2327 "mov r0, %0\n" 2328 "mov r1, %1\n" 2329 "movw r7, #0x2\n" 2330 "movt r7, #0xf\n" 2331 "movs r2, #0x0\n" 2332 "svc 0x0\n" 2333 "pop {r7}\n" 2334 : 2335 : "r" (begin), "r" (end) 2336 : "r0", "r1", "r2"); 2337 } 2338 #endif 2339 cacheFlush(void * code,size_t size)2340 static void cacheFlush(void* code, size_t size) 2341 { 2342 #if OS(IOS) 2343 sys_cache_control(kCacheFunctionPrepareForExecution, code, size); 2344 #elif OS(LINUX) 2345 size_t page = pageSize(); 2346 uintptr_t current = reinterpret_cast<uintptr_t>(code); 2347 uintptr_t end = current + size; 2348 uintptr_t firstPageEnd = (current & ~(page - 1)) + page; 2349 2350 if (end <= firstPageEnd) { 2351 linuxPageFlush(current, end); 2352 return; 2353 } 2354 2355 linuxPageFlush(current, firstPageEnd); 2356 2357 for (current = firstPageEnd; current + page < end; current += page) 2358 linuxPageFlush(current, current + page); 2359 2360 linuxPageFlush(current, end); 2361 #elif OS(WINCE) 2362 CacheRangeFlush(code, size, CACHE_SYNC_ALL); 2363 #elif OS(QNX) 2364 #if !ENABLE(ASSEMBLER_WX_EXCLUSIVE) 2365 msync(code, size, MS_INVALIDATE_ICACHE); 2366 #elif OS(RTEMS) 2367 rtems_cache_flush_multiple_data_lines(code, size); 2368 #else 2369 UNUSED_PARAM(code); 2370 UNUSED_PARAM(size); 2371 #endif 2372 #elif OS(FREEBSD) && COMPILER(CLANG) 2373 __clear_cache(code, reinterpret_cast<char*>(code) + size); 2374 #else 2375 #error "The cacheFlush support is missing on this platform." 2376 #endif 2377 } 2378 2379 private: 2380 // VFP operations commonly take one or more 5-bit operands, typically representing a 2381 // floating point register number. This will commonly be encoded in the instruction 2382 // in two parts, with one single bit field, and one 4-bit field. In the case of 2383 // double precision operands the high bit of the register number will be encoded 2384 // separately, and for single precision operands the high bit of the register number 2385 // will be encoded individually. 2386 // VFPOperand encapsulates a 5-bit VFP operand, with bits 0..3 containing the 4-bit 2387 // field to be encoded together in the instruction (the low 4-bits of a double 2388 // register number, or the high 4-bits of a single register number), and bit 4 2389 // contains the bit value to be encoded individually. 2390 struct VFPOperand { VFPOperandVFPOperand2391 explicit VFPOperand(uint32_t value) 2392 : m_value(value) 2393 { 2394 ASSERT(!(m_value & ~0x1f)); 2395 } 2396 VFPOperandVFPOperand2397 VFPOperand(FPDoubleRegisterID reg) 2398 : m_value(reg) 2399 { 2400 } 2401 VFPOperandVFPOperand2402 VFPOperand(RegisterID reg) 2403 : m_value(reg) 2404 { 2405 } 2406 VFPOperandVFPOperand2407 VFPOperand(FPSingleRegisterID reg) 2408 : m_value(((reg & 1) << 4) | (reg >> 1)) // rotate the lowest bit of 'reg' to the top. 2409 { 2410 } 2411 bits1VFPOperand2412 uint32_t bits1() 2413 { 2414 return m_value >> 4; 2415 } 2416 bits4VFPOperand2417 uint32_t bits4() 2418 { 2419 return m_value & 0xf; 2420 } 2421 2422 uint32_t m_value; 2423 }; 2424 vcvtOp(bool toInteger,bool isUnsigned,bool isRoundZero)2425 VFPOperand vcvtOp(bool toInteger, bool isUnsigned, bool isRoundZero) 2426 { 2427 // Cannot specify rounding when converting to float. 2428 ASSERT(toInteger || !isRoundZero); 2429 2430 uint32_t op = 0x8; 2431 if (toInteger) { 2432 // opc2 indicates both toInteger & isUnsigned. 2433 op |= isUnsigned ? 0x4 : 0x5; 2434 // 'op' field in instruction is isRoundZero 2435 if (isRoundZero) 2436 op |= 0x10; 2437 } else { 2438 ASSERT(!isRoundZero); 2439 // 'op' field in instruction is isUnsigned 2440 if (!isUnsigned) 2441 op |= 0x10; 2442 } 2443 return VFPOperand(op); 2444 } 2445 setInt32(void * code,uint32_t value,bool flush)2446 static void setInt32(void* code, uint32_t value, bool flush) 2447 { 2448 uint16_t* location = reinterpret_cast<uint16_t*>(code); 2449 ASSERT(isMOV_imm_T3(location - 4) && isMOVT(location - 2)); 2450 2451 ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(value)); 2452 ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(value >> 16)); 2453 location[-4] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16); 2454 location[-3] = twoWordOp5i6Imm4Reg4EncodedImmSecond((location[-3] >> 8) & 0xf, lo16); 2455 location[-2] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16); 2456 location[-1] = twoWordOp5i6Imm4Reg4EncodedImmSecond((location[-1] >> 8) & 0xf, hi16); 2457 2458 if (flush) 2459 cacheFlush(location - 4, 4 * sizeof(uint16_t)); 2460 } 2461 readInt32(void * code)2462 static int32_t readInt32(void* code) 2463 { 2464 uint16_t* location = reinterpret_cast<uint16_t*>(code); 2465 ASSERT(isMOV_imm_T3(location - 4) && isMOVT(location - 2)); 2466 2467 ARMThumbImmediate lo16; 2468 ARMThumbImmediate hi16; 2469 decodeTwoWordOp5i6Imm4Reg4EncodedImmFirst(lo16, location[-4]); 2470 decodeTwoWordOp5i6Imm4Reg4EncodedImmSecond(lo16, location[-3]); 2471 decodeTwoWordOp5i6Imm4Reg4EncodedImmFirst(hi16, location[-2]); 2472 decodeTwoWordOp5i6Imm4Reg4EncodedImmSecond(hi16, location[-1]); 2473 uint32_t result = hi16.asUInt16(); 2474 result <<= 16; 2475 result |= lo16.asUInt16(); 2476 return static_cast<int32_t>(result); 2477 } 2478 setUInt7ForLoad(void * code,ARMThumbImmediate imm)2479 static void setUInt7ForLoad(void* code, ARMThumbImmediate imm) 2480 { 2481 // Requires us to have planted a LDR_imm_T1 2482 ASSERT(imm.isValid()); 2483 ASSERT(imm.isUInt7()); 2484 uint16_t* location = reinterpret_cast<uint16_t*>(code); 2485 location[0] &= ~((static_cast<uint16_t>(0x7f) >> 2) << 6); 2486 location[0] |= (imm.getUInt7() >> 2) << 6; 2487 cacheFlush(location, sizeof(uint16_t)); 2488 } 2489 setPointer(void * code,void * value,bool flush)2490 static void setPointer(void* code, void* value, bool flush) 2491 { 2492 // ### Deliberate "loss" of precision here. On 64-bit hosts void* is wider 2493 // than uint32_t, but the target is 32-bit ARM anyway. 2494 setInt32(code, static_cast<uint32_t>(reinterpret_cast<uintptr_t>(value)), flush); 2495 } 2496 isB(void * address)2497 static bool isB(void* address) 2498 { 2499 uint16_t* instruction = static_cast<uint16_t*>(address); 2500 return ((instruction[0] & 0xf800) == OP_B_T4a) && ((instruction[1] & 0xd000) == OP_B_T4b); 2501 } 2502 isBX(void * address)2503 static bool isBX(void* address) 2504 { 2505 uint16_t* instruction = static_cast<uint16_t*>(address); 2506 return (instruction[0] & 0xff87) == OP_BX; 2507 } 2508 isMOV_imm_T3(void * address)2509 static bool isMOV_imm_T3(void* address) 2510 { 2511 uint16_t* instruction = static_cast<uint16_t*>(address); 2512 return ((instruction[0] & 0xFBF0) == OP_MOV_imm_T3) && ((instruction[1] & 0x8000) == 0); 2513 } 2514 isMOVT(void * address)2515 static bool isMOVT(void* address) 2516 { 2517 uint16_t* instruction = static_cast<uint16_t*>(address); 2518 return ((instruction[0] & 0xFBF0) == OP_MOVT) && ((instruction[1] & 0x8000) == 0); 2519 } 2520 isNOP_T1(void * address)2521 static bool isNOP_T1(void* address) 2522 { 2523 uint16_t* instruction = static_cast<uint16_t*>(address); 2524 return instruction[0] == OP_NOP_T1; 2525 } 2526 isNOP_T2(void * address)2527 static bool isNOP_T2(void* address) 2528 { 2529 uint16_t* instruction = static_cast<uint16_t*>(address); 2530 return (instruction[0] == OP_NOP_T2a) && (instruction[1] == OP_NOP_T2b); 2531 } 2532 makeRelative(const void * target,const void * source)2533 static int32_t makeRelative(const void *target, const void *source) 2534 { 2535 intptr_t difference = reinterpret_cast<intptr_t>(target) - reinterpret_cast<intptr_t>(source); 2536 return static_cast<int32_t>(difference); 2537 } 2538 canBeJumpT1(const uint16_t * instruction,const void * target)2539 static bool canBeJumpT1(const uint16_t* instruction, const void* target) 2540 { 2541 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1)); 2542 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1)); 2543 2544 auto relative = makeRelative(target, instruction); 2545 // It does not appear to be documented in the ARM ARM (big surprise), but 2546 // for OP_B_T1 the branch displacement encoded in the instruction is 2 2547 // less than the actual displacement. 2548 relative -= 2; 2549 return ((relative << 23) >> 23) == relative; 2550 } 2551 canBeJumpT2(const uint16_t * instruction,const void * target)2552 static bool canBeJumpT2(const uint16_t* instruction, const void* target) 2553 { 2554 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1)); 2555 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1)); 2556 2557 auto relative = makeRelative(target, instruction); 2558 // It does not appear to be documented in the ARM ARM (big surprise), but 2559 // for OP_B_T2 the branch displacement encoded in the instruction is 2 2560 // less than the actual displacement. 2561 relative -= 2; 2562 return ((relative << 20) >> 20) == relative; 2563 } 2564 canBeJumpT3(const uint16_t * instruction,const void * target)2565 static bool canBeJumpT3(const uint16_t* instruction, const void* target) 2566 { 2567 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1)); 2568 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1)); 2569 2570 auto relative = makeRelative(target, instruction); 2571 return ((relative << 11) >> 11) == relative; 2572 } 2573 canBeJumpT4(const uint16_t * instruction,const void * target)2574 static bool canBeJumpT4(const uint16_t* instruction, const void* target) 2575 { 2576 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1)); 2577 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1)); 2578 2579 auto relative = makeRelative(target, instruction); 2580 return ((relative << 7) >> 7) == relative; 2581 } 2582 linkJumpT1(Condition cond,uint16_t * instruction,void * target)2583 void linkJumpT1(Condition cond, uint16_t* instruction, void* target) 2584 { 2585 // FIMXE: this should be up in the MacroAssembler layer. :-( 2586 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1)); 2587 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1)); 2588 ASSERT(canBeJumpT1(instruction, target)); 2589 2590 auto relative = makeRelative(target, instruction); 2591 // It does not appear to be documented in the ARM ARM (big surprise), but 2592 // for OP_B_T1 the branch displacement encoded in the instruction is 2 2593 // less than the actual displacement. 2594 relative -= 2; 2595 2596 // All branch offsets should be an even distance. 2597 ASSERT(!(relative & 1)); 2598 instruction[-1] = OP_B_T1 | ((cond & 0xf) << 8) | ((relative & 0x1fe) >> 1); 2599 } 2600 linkJumpT2(uint16_t * instruction,void * target)2601 static void linkJumpT2(uint16_t* instruction, void* target) 2602 { 2603 // FIMXE: this should be up in the MacroAssembler layer. :-( 2604 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1)); 2605 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1)); 2606 ASSERT(canBeJumpT2(instruction, target)); 2607 2608 auto relative = makeRelative(target, instruction); 2609 // It does not appear to be documented in the ARM ARM (big surprise), but 2610 // for OP_B_T2 the branch displacement encoded in the instruction is 2 2611 // less than the actual displacement. 2612 relative -= 2; 2613 2614 // All branch offsets should be an even distance. 2615 ASSERT(!(relative & 1)); 2616 instruction[-1] = OP_B_T2 | ((relative & 0xffe) >> 1); 2617 } 2618 linkJumpT3(Condition cond,uint16_t * instruction,void * target)2619 void linkJumpT3(Condition cond, uint16_t* instruction, void* target) 2620 { 2621 // FIMXE: this should be up in the MacroAssembler layer. :-( 2622 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1)); 2623 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1)); 2624 ASSERT(canBeJumpT3(instruction, target)); 2625 2626 auto relative = makeRelative(target, instruction); 2627 2628 // All branch offsets should be an even distance. 2629 ASSERT(!(relative & 1)); 2630 instruction[-2] = OP_B_T3a | ((relative & 0x100000) >> 10) | ((cond & 0xf) << 6) | ((relative & 0x3f000) >> 12); 2631 instruction[-1] = OP_B_T3b | ((relative & 0x80000) >> 8) | ((relative & 0x40000) >> 5) | ((relative & 0xffe) >> 1); 2632 } 2633 linkJumpT4(uint16_t * instruction,void * target)2634 static void linkJumpT4(uint16_t* instruction, void* target) 2635 { 2636 // FIMXE: this should be up in the MacroAssembler layer. :-( 2637 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1)); 2638 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1)); 2639 ASSERT(canBeJumpT4(instruction, target)); 2640 2641 auto relative = makeRelative(target, instruction); 2642 // ARM encoding for the top two bits below the sign bit is 'peculiar'. 2643 if (relative >= 0) 2644 relative ^= 0xC00000; 2645 2646 // All branch offsets should be an even distance. 2647 ASSERT(!(relative & 1)); 2648 instruction[-2] = OP_B_T4a | ((relative & 0x1000000) >> 14) | ((relative & 0x3ff000) >> 12); 2649 instruction[-1] = OP_B_T4b | ((relative & 0x800000) >> 10) | ((relative & 0x400000) >> 11) | ((relative & 0xffe) >> 1); 2650 } 2651 linkConditionalJumpT4(Condition cond,uint16_t * instruction,void * target)2652 void linkConditionalJumpT4(Condition cond, uint16_t* instruction, void* target) 2653 { 2654 // FIMXE: this should be up in the MacroAssembler layer. :-( 2655 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1)); 2656 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1)); 2657 2658 instruction[-3] = ifThenElse(cond) | OP_IT; 2659 linkJumpT4(instruction, target); 2660 } 2661 linkBX(uint16_t * instruction,void * target)2662 static void linkBX(uint16_t* instruction, void* target) 2663 { 2664 // FIMXE: this should be up in the MacroAssembler layer. :-( 2665 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1)); 2666 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1)); 2667 2668 const uint16_t JUMP_TEMPORARY_REGISTER = ARMRegisters::ip; 2669 ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) + 1)); 2670 ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) >> 16)); 2671 instruction[-5] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16); 2672 instruction[-4] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, lo16); 2673 instruction[-3] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16); 2674 instruction[-2] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, hi16); 2675 instruction[-1] = OP_BX | (JUMP_TEMPORARY_REGISTER << 3); 2676 } 2677 linkConditionalBX(Condition cond,uint16_t * instruction,void * target)2678 void linkConditionalBX(Condition cond, uint16_t* instruction, void* target) 2679 { 2680 // FIMXE: this should be up in the MacroAssembler layer. :-( 2681 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1)); 2682 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1)); 2683 2684 linkBX(instruction, target); 2685 instruction[-6] = ifThenElse(cond, true, true) | OP_IT; 2686 } 2687 linkJumpAbsolute(uint16_t * instruction,void * target)2688 static void linkJumpAbsolute(uint16_t* instruction, void* target) 2689 { 2690 // FIMXE: this should be up in the MacroAssembler layer. :-( 2691 ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1)); 2692 ASSERT(!(reinterpret_cast<intptr_t>(target) & 1)); 2693 2694 ASSERT((isMOV_imm_T3(instruction - 5) && isMOVT(instruction - 3) && isBX(instruction - 1)) 2695 || (isNOP_T1(instruction - 5) && isNOP_T2(instruction - 4) && isB(instruction - 2))); 2696 2697 if (canBeJumpT4(instruction, target)) { 2698 // There may be a better way to fix this, but right now put the NOPs first, since in the 2699 // case of an conditional branch this will be coming after an ITTT predicating *three* 2700 // instructions! Looking backwards to modify the ITTT to an IT is not easy, due to 2701 // variable wdith encoding - the previous instruction might *look* like an ITTT but 2702 // actually be the second half of a 2-word op. 2703 instruction[-5] = OP_NOP_T1; 2704 instruction[-4] = OP_NOP_T2a; 2705 instruction[-3] = OP_NOP_T2b; 2706 linkJumpT4(instruction, target); 2707 } else { 2708 const uint16_t JUMP_TEMPORARY_REGISTER = ARMRegisters::ip; 2709 ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) + 1)); 2710 ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) >> 16)); 2711 instruction[-5] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16); 2712 instruction[-4] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, lo16); 2713 instruction[-3] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16); 2714 instruction[-2] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, hi16); 2715 instruction[-1] = OP_BX | (JUMP_TEMPORARY_REGISTER << 3); 2716 } 2717 } 2718 twoWordOp5i6Imm4Reg4EncodedImmFirst(uint16_t op,ARMThumbImmediate imm)2719 static uint16_t twoWordOp5i6Imm4Reg4EncodedImmFirst(uint16_t op, ARMThumbImmediate imm) 2720 { 2721 return op | (imm.m_value.i << 10) | imm.m_value.imm4; 2722 } 2723 decodeTwoWordOp5i6Imm4Reg4EncodedImmFirst(ARMThumbImmediate & result,uint16_t value)2724 static void decodeTwoWordOp5i6Imm4Reg4EncodedImmFirst(ARMThumbImmediate& result, uint16_t value) 2725 { 2726 result.m_value.i = (value >> 10) & 1; 2727 result.m_value.imm4 = value & 15; 2728 } 2729 twoWordOp5i6Imm4Reg4EncodedImmSecond(uint16_t rd,ARMThumbImmediate imm)2730 static uint16_t twoWordOp5i6Imm4Reg4EncodedImmSecond(uint16_t rd, ARMThumbImmediate imm) 2731 { 2732 return (imm.m_value.imm3 << 12) | (rd << 8) | imm.m_value.imm8; 2733 } 2734 decodeTwoWordOp5i6Imm4Reg4EncodedImmSecond(ARMThumbImmediate & result,uint16_t value)2735 static void decodeTwoWordOp5i6Imm4Reg4EncodedImmSecond(ARMThumbImmediate& result, uint16_t value) 2736 { 2737 result.m_value.imm3 = (value >> 12) & 7; 2738 result.m_value.imm8 = value & 255; 2739 } 2740 2741 class ARMInstructionFormatter { 2742 public: oneWordOp5Reg3Imm8(OpcodeID op,RegisterID rd,uint8_t imm)2743 ALWAYS_INLINE void oneWordOp5Reg3Imm8(OpcodeID op, RegisterID rd, uint8_t imm) 2744 { 2745 m_buffer.putShort(op | (rd << 8) | imm); 2746 } 2747 oneWordOp5Imm5Reg3Reg3(OpcodeID op,uint8_t imm,RegisterID reg1,RegisterID reg2)2748 ALWAYS_INLINE void oneWordOp5Imm5Reg3Reg3(OpcodeID op, uint8_t imm, RegisterID reg1, RegisterID reg2) 2749 { 2750 m_buffer.putShort(op | (imm << 6) | (reg1 << 3) | reg2); 2751 } 2752 oneWordOp7Reg3Reg3Reg3(OpcodeID op,RegisterID reg1,RegisterID reg2,RegisterID reg3)2753 ALWAYS_INLINE void oneWordOp7Reg3Reg3Reg3(OpcodeID op, RegisterID reg1, RegisterID reg2, RegisterID reg3) 2754 { 2755 m_buffer.putShort(op | (reg1 << 6) | (reg2 << 3) | reg3); 2756 } 2757 oneWordOp8Imm8(OpcodeID op,uint8_t imm)2758 ALWAYS_INLINE void oneWordOp8Imm8(OpcodeID op, uint8_t imm) 2759 { 2760 m_buffer.putShort(op | imm); 2761 } 2762 oneWordOp8RegReg143(OpcodeID op,RegisterID reg1,RegisterID reg2)2763 ALWAYS_INLINE void oneWordOp8RegReg143(OpcodeID op, RegisterID reg1, RegisterID reg2) 2764 { 2765 m_buffer.putShort(op | ((reg2 & 8) << 4) | (reg1 << 3) | (reg2 & 7)); 2766 } 2767 oneWordOp9Imm7(OpcodeID op,uint8_t imm)2768 ALWAYS_INLINE void oneWordOp9Imm7(OpcodeID op, uint8_t imm) 2769 { 2770 m_buffer.putShort(op | imm); 2771 } 2772 oneWordOp10Reg3Reg3(OpcodeID op,RegisterID reg1,RegisterID reg2)2773 ALWAYS_INLINE void oneWordOp10Reg3Reg3(OpcodeID op, RegisterID reg1, RegisterID reg2) 2774 { 2775 m_buffer.putShort(op | (reg1 << 3) | reg2); 2776 } 2777 twoWordOp12Reg4FourFours(OpcodeID1 op,RegisterID reg,FourFours ff)2778 ALWAYS_INLINE void twoWordOp12Reg4FourFours(OpcodeID1 op, RegisterID reg, FourFours ff) 2779 { 2780 m_buffer.putShort(op | reg); 2781 m_buffer.putShort(ff.m_u.value); 2782 } 2783 twoWordOp16FourFours(OpcodeID1 op,FourFours ff)2784 ALWAYS_INLINE void twoWordOp16FourFours(OpcodeID1 op, FourFours ff) 2785 { 2786 m_buffer.putShort(op); 2787 m_buffer.putShort(ff.m_u.value); 2788 } 2789 twoWordOp16Op16(OpcodeID1 op1,OpcodeID2 op2)2790 ALWAYS_INLINE void twoWordOp16Op16(OpcodeID1 op1, OpcodeID2 op2) 2791 { 2792 m_buffer.putShort(op1); 2793 m_buffer.putShort(op2); 2794 } 2795 twoWordOp5i6Imm4Reg4EncodedImm(OpcodeID1 op,int imm4,RegisterID rd,ARMThumbImmediate imm)2796 ALWAYS_INLINE void twoWordOp5i6Imm4Reg4EncodedImm(OpcodeID1 op, int imm4, RegisterID rd, ARMThumbImmediate imm) 2797 { 2798 ARMThumbImmediate newImm = imm; 2799 newImm.m_value.imm4 = imm4; 2800 2801 m_buffer.putShort(ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmFirst(op, newImm)); 2802 m_buffer.putShort(ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmSecond(rd, newImm)); 2803 } 2804 twoWordOp12Reg4Reg4Imm12(OpcodeID1 op,RegisterID reg1,RegisterID reg2,uint16_t imm)2805 ALWAYS_INLINE void twoWordOp12Reg4Reg4Imm12(OpcodeID1 op, RegisterID reg1, RegisterID reg2, uint16_t imm) 2806 { 2807 m_buffer.putShort(op | reg1); 2808 m_buffer.putShort((reg2 << 12) | imm); 2809 } 2810 twoWordOp12Reg40Imm3Reg4Imm20Imm5(OpcodeID1 op,RegisterID reg1,RegisterID reg2,uint16_t imm1,uint16_t imm2,uint16_t imm3)2811 ALWAYS_INLINE void twoWordOp12Reg40Imm3Reg4Imm20Imm5(OpcodeID1 op, RegisterID reg1, RegisterID reg2, uint16_t imm1, uint16_t imm2, uint16_t imm3) 2812 { 2813 m_buffer.putShort(op | reg1); 2814 m_buffer.putShort((imm1 << 12) | (reg2 << 8) | (imm2 << 6) | imm3); 2815 } 2816 2817 // Formats up instructions of the pattern: 2818 // 111111111B11aaaa:bbbb222SA2C2cccc 2819 // Where 1s in the pattern come from op1, 2s in the pattern come from op2, S is the provided size bit. 2820 // Operands provide 5 bit values of the form Aaaaa, Bbbbb, Ccccc. vfpOp(OpcodeID1 op1,OpcodeID2 op2,bool size,VFPOperand a,VFPOperand b,VFPOperand c)2821 ALWAYS_INLINE void vfpOp(OpcodeID1 op1, OpcodeID2 op2, bool size, VFPOperand a, VFPOperand b, VFPOperand c) 2822 { 2823 ASSERT(!(op1 & 0x004f)); 2824 ASSERT(!(op2 & 0xf1af)); 2825 m_buffer.putShort(op1 | b.bits1() << 6 | a.bits4()); 2826 m_buffer.putShort(op2 | b.bits4() << 12 | size << 8 | a.bits1() << 7 | c.bits1() << 5 | c.bits4()); 2827 } 2828 2829 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2. 2830 // (i.e. +/-(0..255) 32-bit words) vfpMemOp(OpcodeID1 op1,OpcodeID2 op2,bool size,RegisterID rn,VFPOperand rd,int32_t imm)2831 ALWAYS_INLINE void vfpMemOp(OpcodeID1 op1, OpcodeID2 op2, bool size, RegisterID rn, VFPOperand rd, int32_t imm) 2832 { 2833 bool up = true; 2834 if (imm < 0) { 2835 imm = -imm; 2836 up = false; 2837 } 2838 2839 uint32_t offset = imm; 2840 ASSERT(!(offset & ~0x3fc)); 2841 offset >>= 2; 2842 2843 m_buffer.putShort(op1 | (up << 7) | rd.bits1() << 6 | rn); 2844 m_buffer.putShort(op2 | rd.bits4() << 12 | size << 8 | offset); 2845 } 2846 2847 // Administrative methods: 2848 codeSize()2849 size_t codeSize() const { return m_buffer.codeSize(); } label()2850 AssemblerLabel label() const { return m_buffer.label(); } isAligned(int alignment)2851 bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); } data()2852 void* data() const { return m_buffer.data(); } 2853 debugOffset()2854 unsigned debugOffset() { return m_buffer.debugOffset(); } 2855 2856 private: 2857 AssemblerBuffer m_buffer; 2858 } m_formatter; 2859 2860 Vector<LinkRecord, 0, UnsafeVectorOverflow> m_jumpsToLink; 2861 int m_indexOfLastWatchpoint; 2862 int m_indexOfTailOfLastWatchpoint; 2863 }; 2864 2865 #undef JUMP_ENUM_WITH_SIZE 2866 #undef JUMP_ENUM_SIZE 2867 2868 } // namespace JSC 2869 2870 #endif // ENABLE(ASSEMBLER) && CPU(ARM_THUMB2) 2871 2872 #endif // ARMAssembler_h 2873