2  * Copyright (C) 2009, 2010 University of Szeged 
   5  * Redistribution and use in source and binary forms, with or without 
   6  * modification, are permitted provided that the following conditions 
   8  * 1. Redistributions of source code must retain the above copyright 
   9  *    notice, this list of conditions and the following disclaimer. 
  10  * 2. Redistributions in binary form must reproduce the above copyright 
  11  *    notice, this list of conditions and the following disclaimer in the 
  12  *    documentation and/or other materials provided with the distribution. 
  14  * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED OR 
  18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
  19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
  20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
  21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
  22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
  23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
  24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
  27 #ifndef ARMAssembler_h 
  28 #define ARMAssembler_h 
  30 #if ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) 
  32 #include "AssemblerBufferWithConstantPool.h" 
  33 #include "JITCompilationEffort.h" 
  34 #include <wtf/Assertions.h> 
  37     typedef uint32_t ARMWord
; 
  39     #define FOR_EACH_CPU_REGISTER(V) \ 
  40         FOR_EACH_CPU_GPREGISTER(V) \ 
  41         FOR_EACH_CPU_SPECIAL_REGISTER(V) \ 
  42         FOR_EACH_CPU_FPREGISTER(V) 
  44     #define FOR_EACH_CPU_GPREGISTER(V) \ 
  62     #define FOR_EACH_CPU_SPECIAL_REGISTER(V) \ 
  66     #define FOR_EACH_CPU_FPREGISTER(V) \ 
 100     namespace ARMRegisters { 
 103             #define DECLARE_REGISTER(_type, _regName) _regName, 
 104             FOR_EACH_CPU_GPREGISTER(DECLARE_REGISTER
) 
 105             #undef DECLARE_REGISTER 
 107             // Pseudonyms for some of the registers. 
 109             r11 
= fp
, // frame pointer 
 117             #define DECLARE_REGISTER(_type, _regName) _regName, 
 118             FOR_EACH_CPU_FPREGISTER(DECLARE_REGISTER
) 
 119             #undef DECLARE_REGISTER 
 121             // Pseudonyms for some of the registers. 
 122             SD0 
= d7
, /* Same as thumb assembler. */ 
 125     } // namespace ARMRegisters 
 129         typedef ARMRegisters::RegisterID RegisterID
; 
 130         typedef ARMRegisters::FPRegisterID FPRegisterID
; 
 131         typedef AssemblerBufferWithConstantPool
<2048, 4, 4, ARMAssembler
> ARMBuffer
; 
 132         typedef SegmentedVector
<AssemblerLabel
, 64> Jumps
; 
 135             : m_indexOfTailOfLastWatchpoint(1) 
 139         ARMBuffer
& buffer() { return m_buffer
; } 
 141         static RegisterID 
firstRegister() { return ARMRegisters::r0
; } 
 142         static RegisterID 
lastRegister() { return ARMRegisters::r15
; } 
 144         static FPRegisterID 
firstFPRegister() { return ARMRegisters::d0
; } 
 145         static FPRegisterID 
lastFPRegister() { return ARMRegisters::d31
; } 
 147         // ARM conditional constants 
 149             EQ 
= 0x00000000, // Zero / Equal. 
 150             NE 
= 0x10000000, // Non-zero / Not equal. 
 151             CS 
= 0x20000000, // Unsigned higher or same. 
 152             CC 
= 0x30000000, // Unsigned lower. 
 153             MI 
= 0x40000000, // Negative. 
 154             PL 
= 0x50000000, // Positive or zero. 
 155             VS 
= 0x60000000, // Overflowed. 
 156             VC 
= 0x70000000, // Not overflowed. 
 157             HI 
= 0x80000000, // Unsigned higher. 
 158             LS 
= 0x90000000, // Unsigned lower or same. 
 159             GE 
= 0xa0000000, // Signed greater than or equal. 
 160             LT 
= 0xb0000000, // Signed less than. 
 161             GT 
= 0xc0000000, // Signed greater than. 
 162             LE 
= 0xd0000000, // Signed less than or equal. 
 163             AL 
= 0xe0000000  // Unconditional / Always execute. 
 166         // ARM instruction constants 
 186             VMOV_F64 
= 0x0eb00b40, 
 187             VADD_F64 
= 0x0e300b00, 
 188             VDIV_F64 
= 0x0e800b00, 
 189             VSUB_F64 
= 0x0e300b40, 
 190             VMUL_F64 
= 0x0e200b00, 
 191             VCMP_F64 
= 0x0eb40b40, 
 192             VSQRT_F64 
= 0x0eb10bc0, 
 193             VABS_F64 
= 0x0eb00bc0, 
 194             VNEG_F64 
= 0x0eb10b40, 
 200             VMOV_VFP64 
= 0x0c400a10, 
 201             VMOV_ARM64 
= 0x0c500a10, 
 202             VMOV_VFP32 
= 0x0e000a10, 
 203             VMOV_ARM32 
= 0x0e100a10, 
 204             VCVT_F64_S32 
= 0x0eb80bc0, 
 205             VCVT_S32_F64 
= 0x0ebd0bc0, 
 206             VCVT_U32_F64 
= 0x0ebc0bc0, 
 207             VCVT_F32_F64 
= 0x0eb70bc0, 
 208             VCVT_F64_F32 
= 0x0eb70ac0, 
 209             VMRS_APSR 
= 0x0ef1fa10, 
 213 #if WTF_ARM_ARCH_AT_LEAST(7) 
 219 #if HAVE(ARM_IDIV_INSTRUCTIONS) 
 226             Op2Immediate 
= (1 << 25), 
 227             ImmediateForHalfWordTransfer 
= (1 << 22), 
 228             Op2InvertedImmediate 
= (1 << 26), 
 229             SetConditionalCodes 
= (1 << 20), 
 230             Op2IsRegisterArgument 
= (1 << 25), 
 231             // Data transfer flags. 
 232             DataTransferUp 
= (1 << 23), 
 233             DataTransferWriteBack 
= (1 << 21), 
 234             DataTransferPostUpdate 
= (1 << 24), 
 235             DataTransferLoad 
= (1 << 20), 
 236             ByteDataTransfer 
= (1 << 22), 
 239         enum DataTransferTypeA 
{ 
 240             LoadUint32 
= 0x05000000 | DataTransferLoad
, 
 241             LoadUint8 
= 0x05400000 | DataTransferLoad
, 
 242             StoreUint32 
= 0x05000000, 
 243             StoreUint8 
= 0x05400000, 
 246         enum DataTransferTypeB 
{ 
 247             LoadUint16 
= 0x010000b0 | DataTransferLoad
, 
 248             LoadInt16 
= 0x010000f0 | DataTransferLoad
, 
 249             LoadInt8 
= 0x010000d0 | DataTransferLoad
, 
 250             StoreUint16 
= 0x010000b0, 
 253         enum DataTransferTypeFloat 
{ 
 254             LoadFloat 
= 0x0d000a00 | DataTransferLoad
, 
 255             LoadDouble 
= 0x0d000b00 | DataTransferLoad
, 
 256             StoreFloat 
= 0x0d000a00, 
 257             StoreDouble 
= 0x0d000b00, 
 260         // Masks of ARM instructions 
 262             BranchOffsetMask 
= 0x00ffffff, 
 263             ConditionalFieldMask 
= 0xf0000000, 
 264             DataTransferOffsetMask 
= 0xfff, 
 268             MinimumBranchOffsetDistance 
= -0x00800000, 
 269             MaximumBranchOffsetDistance 
= 0x007fffff, 
 274             padForAlign16 
= 0x0000, 
 275             padForAlign32 
= 0xe12fff7f // 'bkpt 0xffff' instruction. 
 278         static const ARMWord InvalidImmediate 
= 0xf0000000; 
 279         static const ARMWord InvalidBranchTarget 
= 0xffffffff; 
 280         static const int DefaultPrefetchOffset 
= 2; 
 282         static const ARMWord BlxInstructionMask 
= 0x012fff30; 
 283         static const ARMWord LdrOrAddInstructionMask 
= 0x0ff00000; 
 284         static const ARMWord LdrPcImmediateInstructionMask 
= 0x0f7f0000; 
 286         static const ARMWord AddImmediateInstruction 
= 0x02800000; 
 287         static const ARMWord BlxInstruction 
= 0x012fff30; 
 288         static const ARMWord LdrImmediateInstruction 
= 0x05900000; 
 289         static const ARMWord LdrPcImmediateInstruction 
= 0x051f0000; 
 291         // Instruction formating 
 293         void emitInstruction(ARMWord op
, int rd
, int rn
, ARMWord op2
) 
 295             ASSERT(((op2 
& ~Op2Immediate
) <= 0xfff) || (((op2 
& ~ImmediateForHalfWordTransfer
) <= 0xfff))); 
 296             m_buffer
.putInt(op 
| RN(rn
) | RD(rd
) | op2
); 
 299         void emitDoublePrecisionInstruction(ARMWord op
, int dd
, int dn
, int dm
) 
 301             ASSERT((dd 
>= 0 && dd 
<= 31) && (dn 
>= 0 && dn 
<= 31) && (dm 
>= 0 && dm 
<= 31)); 
 302             m_buffer
.putInt(op 
| ((dd 
& 0xf) << 12) | ((dd 
& 0x10) << (22 - 4)) 
 303                                | ((dn 
& 0xf) << 16) | ((dn 
& 0x10) << (7 - 4)) 
 304                                | (dm 
& 0xf) | ((dm 
& 0x10) << (5 - 4))); 
 307         void emitSinglePrecisionInstruction(ARMWord op
, int sd
, int sn
, int sm
) 
 309             ASSERT((sd 
>= 0 && sd 
<= 31) && (sn 
>= 0 && sn 
<= 31) && (sm 
>= 0 && sm 
<= 31)); 
 310             m_buffer
.putInt(op 
| ((sd 
>> 1) << 12) | ((sd 
& 0x1) << 22) 
 311                                | ((sn 
>> 1) << 16) | ((sn 
& 0x1) << 7) 
 312                                | (sm 
>> 1) | ((sm 
& 0x1) << 5)); 
 315         void bitAnd(int rd
, int rn
, ARMWord op2
, Condition cc 
= AL
) 
 317             emitInstruction(toARMWord(cc
) | AND
, rd
, rn
, op2
); 
 320         void bitAnds(int rd
, int rn
, ARMWord op2
, Condition cc 
= AL
) 
 322             emitInstruction(toARMWord(cc
) | AND 
| SetConditionalCodes
, rd
, rn
, op2
); 
 325         void eor(int rd
, int rn
, ARMWord op2
, Condition cc 
= AL
) 
 327             emitInstruction(toARMWord(cc
) | EOR
, rd
, rn
, op2
); 
 330         void eors(int rd
, int rn
, ARMWord op2
, Condition cc 
= AL
) 
 332             emitInstruction(toARMWord(cc
) | EOR 
| SetConditionalCodes
, rd
, rn
, op2
); 
 335         void sub(int rd
, int rn
, ARMWord op2
, Condition cc 
= AL
) 
 337             emitInstruction(toARMWord(cc
) | SUB
, rd
, rn
, op2
); 
 340         void subs(int rd
, int rn
, ARMWord op2
, Condition cc 
= AL
) 
 342             emitInstruction(toARMWord(cc
) | SUB 
| SetConditionalCodes
, rd
, rn
, op2
); 
 345         void rsb(int rd
, int rn
, ARMWord op2
, Condition cc 
= AL
) 
 347             emitInstruction(toARMWord(cc
) | RSB
, rd
, rn
, op2
); 
 350         void rsbs(int rd
, int rn
, ARMWord op2
, Condition cc 
= AL
) 
 352             emitInstruction(toARMWord(cc
) | RSB 
| SetConditionalCodes
, rd
, rn
, op2
); 
 355         void add(int rd
, int rn
, ARMWord op2
, Condition cc 
= AL
) 
 357             emitInstruction(toARMWord(cc
) | ADD
, rd
, rn
, op2
); 
 360         void adds(int rd
, int rn
, ARMWord op2
, Condition cc 
= AL
) 
 362             emitInstruction(toARMWord(cc
) | ADD 
| SetConditionalCodes
, rd
, rn
, op2
); 
 365         void adc(int rd
, int rn
, ARMWord op2
, Condition cc 
= AL
) 
 367             emitInstruction(toARMWord(cc
) | ADC
, rd
, rn
, op2
); 
 370         void adcs(int rd
, int rn
, ARMWord op2
, Condition cc 
= AL
) 
 372             emitInstruction(toARMWord(cc
) | ADC 
| SetConditionalCodes
, rd
, rn
, op2
); 
 375         void sbc(int rd
, int rn
, ARMWord op2
, Condition cc 
= AL
) 
 377             emitInstruction(toARMWord(cc
) | SBC
, rd
, rn
, op2
); 
 380         void sbcs(int rd
, int rn
, ARMWord op2
, Condition cc 
= AL
) 
 382             emitInstruction(toARMWord(cc
) | SBC 
| SetConditionalCodes
, rd
, rn
, op2
); 
 385         void rsc(int rd
, int rn
, ARMWord op2
, Condition cc 
= AL
) 
 387             emitInstruction(toARMWord(cc
) | RSC
, rd
, rn
, op2
); 
 390         void rscs(int rd
, int rn
, ARMWord op2
, Condition cc 
= AL
) 
 392             emitInstruction(toARMWord(cc
) | RSC 
| SetConditionalCodes
, rd
, rn
, op2
); 
 395         void tst(int rn
, ARMWord op2
, Condition cc 
= AL
) 
 397             emitInstruction(toARMWord(cc
) | TST 
| SetConditionalCodes
, 0, rn
, op2
); 
 400         void teq(int rn
, ARMWord op2
, Condition cc 
= AL
) 
 402             emitInstruction(toARMWord(cc
) | TEQ 
| SetConditionalCodes
, 0, rn
, op2
); 
 405         void cmp(int rn
, ARMWord op2
, Condition cc 
= AL
) 
 407             emitInstruction(toARMWord(cc
) | CMP 
| SetConditionalCodes
, 0, rn
, op2
); 
 410         void cmn(int rn
, ARMWord op2
, Condition cc 
= AL
) 
 412             emitInstruction(toARMWord(cc
) | CMN 
| SetConditionalCodes
, 0, rn
, op2
); 
 415         void orr(int rd
, int rn
, ARMWord op2
, Condition cc 
= AL
) 
 417             emitInstruction(toARMWord(cc
) | ORR
, rd
, rn
, op2
); 
 420         void orrs(int rd
, int rn
, ARMWord op2
, Condition cc 
= AL
) 
 422             emitInstruction(toARMWord(cc
) | ORR 
| SetConditionalCodes
, rd
, rn
, op2
); 
 425         void mov(int rd
, ARMWord op2
, Condition cc 
= AL
) 
 427             emitInstruction(toARMWord(cc
) | MOV
, rd
, ARMRegisters::r0
, op2
); 
 430 #if WTF_ARM_ARCH_AT_LEAST(7) 
 431         void movw(int rd
, ARMWord op2
, Condition cc 
= AL
) 
 433             ASSERT((op2 
| 0xf0fff) == 0xf0fff); 
 434             m_buffer
.putInt(toARMWord(cc
) | MOVW 
| RD(rd
) | op2
); 
 437         void movt(int rd
, ARMWord op2
, Condition cc 
= AL
) 
 439             ASSERT((op2 
| 0xf0fff) == 0xf0fff); 
 440             m_buffer
.putInt(toARMWord(cc
) | MOVT 
| RD(rd
) | op2
); 
 444         void movs(int rd
, ARMWord op2
, Condition cc 
= AL
) 
 446             emitInstruction(toARMWord(cc
) | MOV 
| SetConditionalCodes
, rd
, ARMRegisters::r0
, op2
); 
 449         void bic(int rd
, int rn
, ARMWord op2
, Condition cc 
= AL
) 
 451             emitInstruction(toARMWord(cc
) | BIC
, rd
, rn
, op2
); 
 454         void bics(int rd
, int rn
, ARMWord op2
, Condition cc 
= AL
) 
 456             emitInstruction(toARMWord(cc
) | BIC 
| SetConditionalCodes
, rd
, rn
, op2
); 
 459         void mvn(int rd
, ARMWord op2
, Condition cc 
= AL
) 
 461             emitInstruction(toARMWord(cc
) | MVN
, rd
, ARMRegisters::r0
, op2
); 
 464         void mvns(int rd
, ARMWord op2
, Condition cc 
= AL
) 
 466             emitInstruction(toARMWord(cc
) | MVN 
| SetConditionalCodes
, rd
, ARMRegisters::r0
, op2
); 
 469         void mul(int rd
, int rn
, int rm
, Condition cc 
= AL
) 
 471             m_buffer
.putInt(toARMWord(cc
) | MUL 
| RN(rd
) | RS(rn
) | RM(rm
)); 
 474         void muls(int rd
, int rn
, int rm
, Condition cc 
= AL
) 
 476             m_buffer
.putInt(toARMWord(cc
) | MUL 
| SetConditionalCodes 
| RN(rd
) | RS(rn
) | RM(rm
)); 
 479         void mull(int rdhi
, int rdlo
, int rn
, int rm
, Condition cc 
= AL
) 
 481             m_buffer
.putInt(toARMWord(cc
) | MULL 
| RN(rdhi
) | RD(rdlo
) | RS(rn
) | RM(rm
)); 
 484 #if HAVE(ARM_IDIV_INSTRUCTIONS) 
 485         template<int datasize
> 
 486         void sdiv(int rd
, int rn
, int rm
, Condition cc 
= AL
) 
 488             static_assert(datasize 
== 32, "sdiv datasize must be 32 for armv7s"); 
 489             ASSERT(rd 
!= ARMRegisters::pc
); 
 490             ASSERT(rn 
!= ARMRegisters::pc
); 
 491             ASSERT(rm 
!= ARMRegisters::pc
); 
 492             m_buffer
.putInt(toARMWord(cc
) | SDIV 
| RN(rd
) | RM(rn
) | RS(rm
)); 
 495         void udiv(int rd
, int rn
, int rm
, Condition cc 
= AL
) 
 497             ASSERT(rd 
!= ARMRegisters::pc
); 
 498             ASSERT(rn 
!= ARMRegisters::pc
); 
 499             ASSERT(rm 
!= ARMRegisters::pc
); 
 500             m_buffer
.putInt(toARMWord(cc
) | UDIV 
| RN(rd
) | RM(rn
) | RS(rm
)); 
 504         void vmov_f64(int dd
, int dm
, Condition cc 
= AL
) 
 506             emitDoublePrecisionInstruction(toARMWord(cc
) | VMOV_F64
, dd
, 0, dm
); 
 509         void vadd_f64(int dd
, int dn
, int dm
, Condition cc 
= AL
) 
 511             emitDoublePrecisionInstruction(toARMWord(cc
) | VADD_F64
, dd
, dn
, dm
); 
 514         void vdiv_f64(int dd
, int dn
, int dm
, Condition cc 
= AL
) 
 516             emitDoublePrecisionInstruction(toARMWord(cc
) | VDIV_F64
, dd
, dn
, dm
); 
 519         void vsub_f64(int dd
, int dn
, int dm
, Condition cc 
= AL
) 
 521             emitDoublePrecisionInstruction(toARMWord(cc
) | VSUB_F64
, dd
, dn
, dm
); 
 524         void vmul_f64(int dd
, int dn
, int dm
, Condition cc 
= AL
) 
 526             emitDoublePrecisionInstruction(toARMWord(cc
) | VMUL_F64
, dd
, dn
, dm
); 
 529         void vcmp_f64(int dd
, int dm
, Condition cc 
= AL
) 
 531             emitDoublePrecisionInstruction(toARMWord(cc
) | VCMP_F64
, dd
, 0, dm
); 
 534         void vsqrt_f64(int dd
, int dm
, Condition cc 
= AL
) 
 536             emitDoublePrecisionInstruction(toARMWord(cc
) | VSQRT_F64
, dd
, 0, dm
); 
 539         void vabs_f64(int dd
, int dm
, Condition cc 
= AL
) 
 541             emitDoublePrecisionInstruction(toARMWord(cc
) | VABS_F64
, dd
, 0, dm
); 
 544         void vneg_f64(int dd
, int dm
, Condition cc 
= AL
) 
 546             emitDoublePrecisionInstruction(toARMWord(cc
) | VNEG_F64
, dd
, 0, dm
); 
 549         void ldrImmediate(int rd
, ARMWord imm
, Condition cc 
= AL
) 
 551             m_buffer
.putIntWithConstantInt(toARMWord(cc
) | LoadUint32 
| DataTransferUp 
| RN(ARMRegisters::pc
) | RD(rd
), imm
, true); 
 554         void ldrUniqueImmediate(int rd
, ARMWord imm
, Condition cc 
= AL
) 
 556             m_buffer
.putIntWithConstantInt(toARMWord(cc
) | LoadUint32 
| DataTransferUp 
| RN(ARMRegisters::pc
) | RD(rd
), imm
); 
 559         void dtrUp(DataTransferTypeA transferType
, int rd
, int rb
, ARMWord op2
, Condition cc 
= AL
) 
 561             emitInstruction(toARMWord(cc
) | transferType 
| DataTransferUp
, rd
, rb
, op2
); 
 564         void dtrUpRegister(DataTransferTypeA transferType
, int rd
, int rb
, int rm
, Condition cc 
= AL
) 
 566             emitInstruction(toARMWord(cc
) | transferType 
| DataTransferUp 
| Op2IsRegisterArgument
, rd
, rb
, rm
); 
 569         void dtrDown(DataTransferTypeA transferType
, int rd
, int rb
, ARMWord op2
, Condition cc 
= AL
) 
 571             emitInstruction(toARMWord(cc
) | transferType
, rd
, rb
, op2
); 
 574         void dtrDownRegister(DataTransferTypeA transferType
, int rd
, int rb
, int rm
, Condition cc 
= AL
) 
 576             emitInstruction(toARMWord(cc
) | transferType 
| Op2IsRegisterArgument
, rd
, rb
, rm
); 
 579         void halfDtrUp(DataTransferTypeB transferType
, int rd
, int rb
, ARMWord op2
, Condition cc 
= AL
) 
 581             emitInstruction(toARMWord(cc
) | transferType 
| DataTransferUp
, rd
, rb
, op2
); 
 584         void halfDtrUpRegister(DataTransferTypeB transferType
, int rd
, int rn
, int rm
, Condition cc 
= AL
) 
 586             emitInstruction(toARMWord(cc
) | transferType 
| DataTransferUp
, rd
, rn
, rm
); 
 589         void halfDtrDown(DataTransferTypeB transferType
, int rd
, int rb
, ARMWord op2
, Condition cc 
= AL
) 
 591             emitInstruction(toARMWord(cc
) | transferType
, rd
, rb
, op2
); 
 594         void halfDtrDownRegister(DataTransferTypeB transferType
, int rd
, int rn
, int rm
, Condition cc 
= AL
) 
 596             emitInstruction(toARMWord(cc
) | transferType
, rd
, rn
, rm
); 
 599         void doubleDtrUp(DataTransferTypeFloat type
, int rd
, int rb
, ARMWord op2
, Condition cc 
= AL
) 
 601             ASSERT(op2 
<= 0xff && rd 
<= 15); 
 602             /* Only d0-d15 and s0, s2, s4 ... s30 are supported. */ 
 603             m_buffer
.putInt(toARMWord(cc
) | DataTransferUp 
| type 
| (rd 
<< 12) | RN(rb
) | op2
); 
 606         void doubleDtrDown(DataTransferTypeFloat type
, int rd
, int rb
, ARMWord op2
, Condition cc 
= AL
) 
 608             ASSERT(op2 
<= 0xff && rd 
<= 15); 
 609             /* Only d0-d15 and s0, s2, s4 ... s30 are supported. */ 
 610             m_buffer
.putInt(toARMWord(cc
) | type 
| (rd 
<< 12) | RN(rb
) | op2
); 
 613         void push(int reg
, Condition cc 
= AL
) 
 615             ASSERT(ARMWord(reg
) <= 0xf); 
 616             m_buffer
.putInt(toARMWord(cc
) | StoreUint32 
| DataTransferWriteBack 
| RN(ARMRegisters::sp
) | RD(reg
) | 0x4); 
 619         void pop(int reg
, Condition cc 
= AL
) 
 621             ASSERT(ARMWord(reg
) <= 0xf); 
 622             m_buffer
.putInt(toARMWord(cc
) | (LoadUint32 
^ DataTransferPostUpdate
) | DataTransferUp 
| RN(ARMRegisters::sp
) | RD(reg
) | 0x4); 
 625         inline void poke(int reg
, Condition cc 
= AL
) 
 627             dtrDown(StoreUint32
, ARMRegisters::sp
, 0, reg
, cc
); 
 630         inline void peek(int reg
, Condition cc 
= AL
) 
 632             dtrUp(LoadUint32
, reg
, ARMRegisters::sp
, 0, cc
); 
 635         void vmov_vfp64(int sm
, int rt
, int rt2
, Condition cc 
= AL
) 
 638             m_buffer
.putInt(toARMWord(cc
) | VMOV_VFP64 
| RN(rt2
) | RD(rt
) | (sm 
& 0xf) | ((sm 
& 0x10) << (5 - 4))); 
 641         void vmov_arm64(int rt
, int rt2
, int sm
, Condition cc 
= AL
) 
 644             m_buffer
.putInt(toARMWord(cc
) | VMOV_ARM64 
| RN(rt2
) | RD(rt
) | (sm 
& 0xf) | ((sm 
& 0x10) << (5 - 4))); 
 647         void vmov_vfp32(int sn
, int rt
, Condition cc 
= AL
) 
 650             emitSinglePrecisionInstruction(toARMWord(cc
) | VMOV_VFP32
, rt 
<< 1, sn
, 0); 
 653         void vmov_arm32(int rt
, int sn
, Condition cc 
= AL
) 
 656             emitSinglePrecisionInstruction(toARMWord(cc
) | VMOV_ARM32
, rt 
<< 1, sn
, 0); 
 659         void vcvt_f64_s32(int dd
, int sm
, Condition cc 
= AL
) 
 661             ASSERT(!(sm 
& 0x1)); // sm must be divisible by 2 
 662             emitDoublePrecisionInstruction(toARMWord(cc
) | VCVT_F64_S32
, dd
, 0, (sm 
>> 1)); 
 665         void vcvt_s32_f64(int sd
, int dm
, Condition cc 
= AL
) 
 667             ASSERT(!(sd 
& 0x1)); // sd must be divisible by 2 
 668             emitDoublePrecisionInstruction(toARMWord(cc
) | VCVT_S32_F64
, (sd 
>> 1), 0, dm
); 
 671         void vcvt_u32_f64(int sd
, int dm
, Condition cc 
= AL
) 
 673             ASSERT(!(sd 
& 0x1)); // sd must be divisible by 2 
 674             emitDoublePrecisionInstruction(toARMWord(cc
) | VCVT_U32_F64
, (sd 
>> 1), 0, dm
); 
 677         void vcvt_f64_f32(int dd
, int sm
, Condition cc 
= AL
) 
 679             ASSERT(dd 
<= 15 && sm 
<= 15); 
 680             emitDoublePrecisionInstruction(toARMWord(cc
) | VCVT_F64_F32
, dd
, 0, sm
); 
 683         void vcvt_f32_f64(int dd
, int sm
, Condition cc 
= AL
) 
 685             ASSERT(dd 
<= 15 && sm 
<= 15); 
 686             emitDoublePrecisionInstruction(toARMWord(cc
) | VCVT_F32_F64
, dd
, 0, sm
); 
 689         void vmrs_apsr(Condition cc 
= AL
) 
 691             m_buffer
.putInt(toARMWord(cc
) | VMRS_APSR
); 
 694         void clz(int rd
, int rm
, Condition cc 
= AL
) 
 696             m_buffer
.putInt(toARMWord(cc
) | CLZ 
| RD(rd
) | RM(rm
)); 
 699         void bkpt(ARMWord value
) 
 701             m_buffer
.putInt(BKPT 
| ((value 
& 0xff0) << 4) | (value 
& 0xf)); 
 706             m_buffer
.putInt(NOP
); 
 711             m_buffer
.putInt(DMB_SY
); 
 714         void bx(int rm
, Condition cc 
= AL
) 
 716             emitInstruction(toARMWord(cc
) | BX
, 0, 0, RM(rm
)); 
 719         AssemblerLabel 
blx(int rm
, Condition cc 
= AL
) 
 721             emitInstruction(toARMWord(cc
) | BLX
, 0, 0, RM(rm
)); 
 722             return m_buffer
.label(); 
 725         static ARMWord 
lsl(int reg
, ARMWord value
) 
 727             ASSERT(reg 
<= ARMRegisters::pc
); 
 728             ASSERT(value 
<= 0x1f); 
 729             return reg 
| (value 
<< 7) | 0x00; 
 732         static ARMWord 
lsr(int reg
, ARMWord value
) 
 734             ASSERT(reg 
<= ARMRegisters::pc
); 
 735             ASSERT(value 
<= 0x1f); 
 736             return reg 
| (value 
<< 7) | 0x20; 
 739         static ARMWord 
asr(int reg
, ARMWord value
) 
 741             ASSERT(reg 
<= ARMRegisters::pc
); 
 742             ASSERT(value 
<= 0x1f); 
 743             return reg 
| (value 
<< 7) | 0x40; 
 746         static ARMWord 
lslRegister(int reg
, int shiftReg
) 
 748             ASSERT(reg 
<= ARMRegisters::pc
); 
 749             ASSERT(shiftReg 
<= ARMRegisters::pc
); 
 750             return reg 
| (shiftReg 
<< 8) | 0x10; 
 753         static ARMWord 
lsrRegister(int reg
, int shiftReg
) 
 755             ASSERT(reg 
<= ARMRegisters::pc
); 
 756             ASSERT(shiftReg 
<= ARMRegisters::pc
); 
 757             return reg 
| (shiftReg 
<< 8) | 0x30; 
 760         static ARMWord 
asrRegister(int reg
, int shiftReg
) 
 762             ASSERT(reg 
<= ARMRegisters::pc
); 
 763             ASSERT(shiftReg 
<= ARMRegisters::pc
); 
 764             return reg 
| (shiftReg 
<< 8) | 0x50; 
 769         size_t codeSize() const 
 771             return m_buffer
.codeSize(); 
 774         void ensureSpace(int insnSpace
, int constSpace
) 
 776             m_buffer
.ensureSpace(insnSpace
, constSpace
); 
 779         int sizeOfConstantPool() 
 781             return m_buffer
.sizeOfConstantPool(); 
 784         AssemblerLabel 
labelIgnoringWatchpoints() 
 786             m_buffer
.ensureSpaceForAnyInstruction(); 
 787             return m_buffer
.label(); 
 790         AssemblerLabel 
labelForWatchpoint() 
 792             m_buffer
.ensureSpaceForAnyInstruction(maxJumpReplacementSize() / sizeof(ARMWord
)); 
 793             AssemblerLabel result 
= m_buffer
.label(); 
 794             if (result
.m_offset 
!= (m_indexOfTailOfLastWatchpoint 
- maxJumpReplacementSize())) 
 796             m_indexOfTailOfLastWatchpoint 
= result
.m_offset 
+ maxJumpReplacementSize(); 
 800         AssemblerLabel 
label() 
 802             AssemblerLabel result 
= labelIgnoringWatchpoints(); 
 803             while (result
.m_offset 
+ 1 < m_indexOfTailOfLastWatchpoint
) { 
 805                 // The available number of instructions are ensured by labelForWatchpoint. 
 806                 result 
= m_buffer
.label(); 
 811         AssemblerLabel 
align(int alignment
) 
 813             while (!m_buffer
.isAligned(alignment
)) 
 814                 mov(ARMRegisters::r0
, ARMRegisters::r0
); 
 819         AssemblerLabel 
loadBranchTarget(int rd
, Condition cc 
= AL
, int useConstantPool 
= 0) 
 821             ensureSpace(sizeof(ARMWord
), sizeof(ARMWord
)); 
 822             m_jumps
.append(m_buffer
.codeSize() | (useConstantPool 
& 0x1)); 
 823             ldrUniqueImmediate(rd
, InvalidBranchTarget
, cc
); 
 824             return m_buffer
.label(); 
 827         AssemblerLabel 
jmp(Condition cc 
= AL
, int useConstantPool 
= 0) 
 829             return loadBranchTarget(ARMRegisters::pc
, cc
, useConstantPool
); 
 832         void prepareExecutableCopy(void* to
); 
 834         unsigned debugOffset() { return m_buffer
.debugOffset(); } 
 836         // DFG assembly helpers for moving data between fp and registers. 
 837         void vmov(RegisterID rd1
, RegisterID rd2
, FPRegisterID rn
) 
 839             vmov_arm64(rd1
, rd2
, rn
); 
 842         void vmov(FPRegisterID rd
, RegisterID rn1
, RegisterID rn2
) 
 844             vmov_vfp64(rd
, rn1
, rn2
); 
 849         static ARMWord
* getLdrImmAddress(ARMWord
* insn
) 
 852             if ((*insn 
& LdrPcImmediateInstructionMask
) != LdrPcImmediateInstruction
) { 
 854                 ASSERT((*insn 
& BlxInstructionMask
) == BlxInstruction
); 
 858             // Must be an ldr ..., [pc +/- imm] 
 859             ASSERT((*insn 
& LdrPcImmediateInstructionMask
) == LdrPcImmediateInstruction
); 
 861             ARMWord addr 
= reinterpret_cast<ARMWord
>(insn
) + DefaultPrefetchOffset 
* sizeof(ARMWord
); 
 862             if (*insn 
& DataTransferUp
) 
 863                 return reinterpret_cast<ARMWord
*>(addr 
+ (*insn 
& DataTransferOffsetMask
)); 
 864             return reinterpret_cast<ARMWord
*>(addr 
- (*insn 
& DataTransferOffsetMask
)); 
 867         static ARMWord
* getLdrImmAddressOnPool(ARMWord
* insn
, uint32_t* constPool
) 
 869             // Must be an ldr ..., [pc +/- imm] 
 870             ASSERT((*insn 
& LdrPcImmediateInstructionMask
) == LdrPcImmediateInstruction
); 
 873                 return reinterpret_cast<ARMWord
*>(constPool 
+ ((*insn 
& DataTransferOffsetMask
) >> 1)); 
 874             return getLdrImmAddress(insn
); 
 877         static void patchPointerInternal(intptr_t from
, void* to
) 
 879             ARMWord
* insn 
= reinterpret_cast<ARMWord
*>(from
); 
 880             ARMWord
* addr 
= getLdrImmAddress(insn
); 
 881             *addr 
= reinterpret_cast<ARMWord
>(to
); 
 884         static ARMWord 
patchConstantPoolLoad(ARMWord load
, ARMWord value
) 
 886             value 
= (value 
<< 1) + 1; 
 887             ASSERT(!(value 
& ~DataTransferOffsetMask
)); 
 888             return (load 
& ~DataTransferOffsetMask
) | value
; 
 891         static void patchConstantPoolLoad(void* loadAddr
, void* constPoolAddr
); 
 894         static void* readPointer(void* from
) 
 896             ARMWord
* instruction 
= reinterpret_cast<ARMWord
*>(from
); 
 897             ARMWord
* address 
= getLdrImmAddress(instruction
); 
 898             return *reinterpret_cast<void**>(address
); 
 903         static void linkPointer(void* code
, AssemblerLabel from
, void* to
) 
 905             patchPointerInternal(reinterpret_cast<intptr_t>(code
) + from
.m_offset
, to
); 
 908         static void repatchInt32(void* where
, int32_t to
) 
 910             patchPointerInternal(reinterpret_cast<intptr_t>(where
), reinterpret_cast<void*>(to
)); 
 913         static void repatchCompact(void* where
, int32_t value
) 
 915             ARMWord
* instruction 
= reinterpret_cast<ARMWord
*>(where
); 
 916             ASSERT((*instruction 
& 0x0f700000) == LoadUint32
); 
 918                 *instruction 
= (*instruction 
& 0xff7ff000) | DataTransferUp 
| value
; 
 920                 *instruction 
= (*instruction 
& 0xff7ff000) | -value
; 
 921             cacheFlush(instruction
, sizeof(ARMWord
)); 
 924         static void repatchPointer(void* from
, void* to
) 
 926             patchPointerInternal(reinterpret_cast<intptr_t>(from
), to
); 
 930         static intptr_t getAbsoluteJumpAddress(void* base
, int offset 
= 0) 
 932             return reinterpret_cast<intptr_t>(base
) + offset 
- sizeof(ARMWord
); 
 935         void linkJump(AssemblerLabel from
, AssemblerLabel to
) 
 937             ARMWord
* insn 
= reinterpret_cast<ARMWord
*>(getAbsoluteJumpAddress(m_buffer
.data(), from
.m_offset
)); 
 938             ARMWord
* addr 
= getLdrImmAddressOnPool(insn
, m_buffer
.poolAddress()); 
 939             *addr 
= toARMWord(to
.m_offset
); 
 942         static void linkJump(void* code
, AssemblerLabel from
, void* to
) 
 944             patchPointerInternal(getAbsoluteJumpAddress(code
, from
.m_offset
), to
); 
 947         static void relinkJump(void* from
, void* to
) 
 949             patchPointerInternal(getAbsoluteJumpAddress(from
), to
); 
 952         static void linkCall(void* code
, AssemblerLabel from
, void* to
) 
 954             patchPointerInternal(getAbsoluteJumpAddress(code
, from
.m_offset
), to
); 
 957         static void relinkCall(void* from
, void* to
) 
 959             patchPointerInternal(getAbsoluteJumpAddress(from
), to
); 
 962         static void* readCallTarget(void* from
) 
 964             return reinterpret_cast<void*>(readPointer(reinterpret_cast<void*>(getAbsoluteJumpAddress(from
)))); 
 967         static void replaceWithJump(void* instructionStart
, void* to
) 
 969             ARMWord
* instruction 
= reinterpret_cast<ARMWord
*>(instructionStart
); 
 970             intptr_t difference 
= reinterpret_cast<intptr_t>(to
) - (reinterpret_cast<intptr_t>(instruction
) + DefaultPrefetchOffset 
* sizeof(ARMWord
)); 
 972             if (!(difference 
& 1)) { 
 974                 if ((difference 
<= MaximumBranchOffsetDistance 
&& difference 
>= MinimumBranchOffsetDistance
)) { 
 976                      instruction
[0] = B 
| AL 
| (difference 
& BranchOffsetMask
); 
 977                      cacheFlush(instruction
, sizeof(ARMWord
)); 
 983             instruction
[0] = LoadUint32 
| AL 
| RN(ARMRegisters::pc
) | RD(ARMRegisters::pc
) | 4; 
 984             instruction
[1] = reinterpret_cast<ARMWord
>(to
); 
 985             cacheFlush(instruction
, sizeof(ARMWord
) * 2); 
 988         static ptrdiff_t maxJumpReplacementSize() 
 990             return sizeof(ARMWord
) * 2; 
 993         static void replaceWithLoad(void* instructionStart
) 
 995             ARMWord
* instruction 
= reinterpret_cast<ARMWord
*>(instructionStart
); 
 996             cacheFlush(instruction
, sizeof(ARMWord
)); 
 998             ASSERT((*instruction 
& LdrOrAddInstructionMask
) == AddImmediateInstruction 
|| (*instruction 
& LdrOrAddInstructionMask
) == LdrImmediateInstruction
); 
 999             if ((*instruction 
& LdrOrAddInstructionMask
) == AddImmediateInstruction
) { 
1000                  *instruction 
= (*instruction 
& ~LdrOrAddInstructionMask
) | LdrImmediateInstruction
; 
1001                  cacheFlush(instruction
, sizeof(ARMWord
)); 
1005         static void replaceWithAddressComputation(void* instructionStart
) 
1007             ARMWord
* instruction 
= reinterpret_cast<ARMWord
*>(instructionStart
); 
1008             cacheFlush(instruction
, sizeof(ARMWord
)); 
1010             ASSERT((*instruction 
& LdrOrAddInstructionMask
) == AddImmediateInstruction 
|| (*instruction 
& LdrOrAddInstructionMask
) == LdrImmediateInstruction
); 
1011             if ((*instruction 
& LdrOrAddInstructionMask
) == LdrImmediateInstruction
) { 
1012                  *instruction 
= (*instruction 
& ~LdrOrAddInstructionMask
) | AddImmediateInstruction
; 
1013                  cacheFlush(instruction
, sizeof(ARMWord
)); 
1017         static void revertBranchPtrWithPatch(void* instructionStart
, RegisterID rn
, ARMWord imm
) 
1019             ARMWord
* instruction 
= reinterpret_cast<ARMWord
*>(instructionStart
); 
1021             ASSERT((instruction
[2] & LdrPcImmediateInstructionMask
) == LdrPcImmediateInstruction
); 
1022             instruction
[0] = toARMWord(AL
) | ((instruction
[2] & 0x0fff0fff) + sizeof(ARMWord
)) | RD(ARMRegisters::S1
); 
1023             *getLdrImmAddress(instruction
) = imm
; 
1024             instruction
[1] = toARMWord(AL
) | CMP 
| SetConditionalCodes 
| RN(rn
) | RM(ARMRegisters::S1
); 
1025             cacheFlush(instruction
, 2 * sizeof(ARMWord
)); 
1028         // Address operations 
1030         static void* getRelocatedAddress(void* code
, AssemblerLabel label
) 
1032             return reinterpret_cast<void*>(reinterpret_cast<char*>(code
) + label
.m_offset
); 
1035         // Address differences 
1037         static int getDifferenceBetweenLabels(AssemblerLabel a
, AssemblerLabel b
) 
1039             return b
.m_offset 
- a
.m_offset
; 
1042         static unsigned getCallReturnOffset(AssemblerLabel call
) 
1044             return call
.m_offset
; 
1047         // Handle immediates 
1049         static ARMWord 
getOp2(ARMWord imm
); 
1051         // Fast case if imm is known to be between 0 and 0xff 
1052         static ARMWord 
getOp2Byte(ARMWord imm
) 
1054             ASSERT(imm 
<= 0xff); 
1055             return Op2Immediate 
| imm
; 
1058         static ARMWord 
getOp2Half(ARMWord imm
) 
1060             ASSERT(imm 
<= 0xff); 
1061             return ImmediateForHalfWordTransfer 
| (imm 
& 0x0f) | ((imm 
& 0xf0) << 4); 
1064 #if WTF_ARM_ARCH_AT_LEAST(7) 
1065         static ARMWord 
getImm16Op2(ARMWord imm
) 
1068                 return (imm 
& 0xf000) << 4 | (imm 
& 0xfff); 
1069             return InvalidImmediate
; 
1072         ARMWord 
getImm(ARMWord imm
, int tmpReg
, bool invert 
= false); 
1073         void moveImm(ARMWord imm
, int dest
); 
1074         ARMWord 
encodeComplexImm(ARMWord imm
, int dest
); 
1076         // Memory load/store helpers 
1078         void dataTransfer32(DataTransferTypeA
, RegisterID srcDst
, RegisterID base
, int32_t offset
); 
1079         void baseIndexTransfer32(DataTransferTypeA
, RegisterID srcDst
, RegisterID base
, RegisterID index
, int scale
, int32_t offset
); 
1080         void dataTransfer16(DataTransferTypeB
, RegisterID srcDst
, RegisterID base
, int32_t offset
); 
1081         void baseIndexTransfer16(DataTransferTypeB
, RegisterID srcDst
, RegisterID base
, RegisterID index
, int scale
, int32_t offset
); 
1082         void dataTransferFloat(DataTransferTypeFloat
, FPRegisterID srcDst
, RegisterID base
, int32_t offset
); 
1083         void baseIndexTransferFloat(DataTransferTypeFloat
, FPRegisterID srcDst
, RegisterID base
, RegisterID index
, int scale
, int32_t offset
); 
1085         // Constant pool hnadlers 
1087         static ARMWord 
placeConstantPoolBarrier(int offset
) 
1089             offset 
= (offset 
- sizeof(ARMWord
)) >> 2; 
1090             ASSERT((offset 
<= MaximumBranchOffsetDistance 
&& offset 
>= MinimumBranchOffsetDistance
)); 
1091             return AL 
| B 
| (offset 
& BranchOffsetMask
); 
1094 #if OS(LINUX) && COMPILER(GCC) 
1095         static inline void linuxPageFlush(uintptr_t begin
, uintptr_t end
) 
1101                 "mov     r7, #0xf0000\n" 
1102                 "add     r7, r7, #0x2\n" 
1107                 : "r" (begin
), "r" (end
) 
1108                 : "r0", "r1", "r2"); 
1112         static void cacheFlush(void* code
, size_t size
) 
1114 #if OS(LINUX) && COMPILER(GCC) 
1115             size_t page 
= pageSize(); 
1116             uintptr_t current 
= reinterpret_cast<uintptr_t>(code
); 
1117             uintptr_t end 
= current 
+ size
; 
1118             uintptr_t firstPageEnd 
= (current 
& ~(page 
- 1)) + page
; 
1120             if (end 
<= firstPageEnd
) { 
1121                 linuxPageFlush(current
, end
); 
1125             linuxPageFlush(current
, firstPageEnd
); 
1127             for (current 
= firstPageEnd
; current 
+ page 
< end
; current 
+= page
) 
1128                 linuxPageFlush(current
, current 
+ page
); 
1130             linuxPageFlush(current
, end
); 
1132 #error "The cacheFlush support is missing on this platform." 
1137         static ARMWord 
RM(int reg
) 
1139             ASSERT(reg 
<= ARMRegisters::pc
); 
1143         static ARMWord 
RS(int reg
) 
1145             ASSERT(reg 
<= ARMRegisters::pc
); 
1149         static ARMWord 
RD(int reg
) 
1151             ASSERT(reg 
<= ARMRegisters::pc
); 
1155         static ARMWord 
RN(int reg
) 
1157             ASSERT(reg 
<= ARMRegisters::pc
); 
1161         static ARMWord 
getConditionalField(ARMWord i
) 
1163             return i 
& ConditionalFieldMask
; 
1166         static ARMWord 
toARMWord(Condition cc
) 
1168             return static_cast<ARMWord
>(cc
); 
1171         static ARMWord 
toARMWord(uint32_t u
) 
1173             return static_cast<ARMWord
>(u
); 
1176         int genInt(int reg
, ARMWord imm
, bool positive
); 
1180         uint32_t m_indexOfTailOfLastWatchpoint
; 
1185 #endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) 
1187 #endif // ARMAssembler_h