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 namespace ARMRegisters
{
44 r3
, S0
= r3
, /* Same as thumb assembler. */
67 d7
, SD0
= d7
, /* Same as thumb assembler. */
94 } // namespace ARMRegisters
98 typedef ARMRegisters::RegisterID RegisterID
;
99 typedef ARMRegisters::FPRegisterID FPRegisterID
;
100 typedef AssemblerBufferWithConstantPool
<2048, 4, 4, ARMAssembler
> ARMBuffer
;
101 typedef SegmentedVector
<AssemblerLabel
, 64> Jumps
;
104 : m_indexOfTailOfLastWatchpoint(1)
108 // ARM conditional constants
110 EQ
= 0x00000000, // Zero / Equal.
111 NE
= 0x10000000, // Non-zero / Not equal.
112 CS
= 0x20000000, // Unsigned higher or same.
113 CC
= 0x30000000, // Unsigned lower.
114 MI
= 0x40000000, // Negative.
115 PL
= 0x50000000, // Positive or zero.
116 VS
= 0x60000000, // Overflowed.
117 VC
= 0x70000000, // Not overflowed.
118 HI
= 0x80000000, // Unsigned higher.
119 LS
= 0x90000000, // Unsigned lower or same.
120 GE
= 0xa0000000, // Signed greater than or equal.
121 LT
= 0xb0000000, // Signed less than.
122 GT
= 0xc0000000, // Signed greater than.
123 LE
= 0xd0000000, // Signed less than or equal.
124 AL
= 0xe0000000 // Unconditional / Always execute.
127 // ARM instruction constants
147 VMOV_F64
= 0x0eb00b40,
148 VADD_F64
= 0x0e300b00,
149 VDIV_F64
= 0x0e800b00,
150 VSUB_F64
= 0x0e300b40,
151 VMUL_F64
= 0x0e200b00,
152 VCMP_F64
= 0x0eb40b40,
153 VSQRT_F64
= 0x0eb10bc0,
154 VABS_F64
= 0x0eb00bc0,
155 VNEG_F64
= 0x0eb10b40,
161 VMOV_VFP64
= 0x0c400a10,
162 VMOV_ARM64
= 0x0c500a10,
163 VMOV_VFP32
= 0x0e000a10,
164 VMOV_ARM32
= 0x0e100a10,
165 VCVT_F64_S32
= 0x0eb80bc0,
166 VCVT_S32_F64
= 0x0ebd0bc0,
167 VCVT_U32_F64
= 0x0ebc0bc0,
168 VCVT_F32_F64
= 0x0eb70bc0,
169 VCVT_F64_F32
= 0x0eb70ac0,
170 VMRS_APSR
= 0x0ef1fa10,
174 #if WTF_ARM_ARCH_AT_LEAST(7)
182 Op2Immediate
= (1 << 25),
183 ImmediateForHalfWordTransfer
= (1 << 22),
184 Op2InvertedImmediate
= (1 << 26),
185 SetConditionalCodes
= (1 << 20),
186 Op2IsRegisterArgument
= (1 << 25),
187 // Data transfer flags.
188 DataTransferUp
= (1 << 23),
189 DataTransferWriteBack
= (1 << 21),
190 DataTransferPostUpdate
= (1 << 24),
191 DataTransferLoad
= (1 << 20),
192 ByteDataTransfer
= (1 << 22),
195 enum DataTransferTypeA
{
196 LoadUint32
= 0x05000000 | DataTransferLoad
,
197 LoadUint8
= 0x05400000 | DataTransferLoad
,
198 StoreUint32
= 0x05000000,
199 StoreUint8
= 0x05400000,
202 enum DataTransferTypeB
{
203 LoadUint16
= 0x010000b0 | DataTransferLoad
,
204 LoadInt16
= 0x010000f0 | DataTransferLoad
,
205 LoadInt8
= 0x010000d0 | DataTransferLoad
,
206 StoreUint16
= 0x010000b0,
209 enum DataTransferTypeFloat
{
210 LoadFloat
= 0x0d000a00 | DataTransferLoad
,
211 LoadDouble
= 0x0d000b00 | DataTransferLoad
,
212 StoreFloat
= 0x0d000a00,
213 StoreDouble
= 0x0d000b00,
216 // Masks of ARM instructions
218 BranchOffsetMask
= 0x00ffffff,
219 ConditionalFieldMask
= 0xf0000000,
220 DataTransferOffsetMask
= 0xfff,
224 MinimumBranchOffsetDistance
= -0x00800000,
225 MaximumBranchOffsetDistance
= 0x007fffff,
230 padForAlign16
= 0x0000,
231 padForAlign32
= 0xe12fff7f // 'bkpt 0xffff' instruction.
234 static const ARMWord InvalidImmediate
= 0xf0000000;
235 static const ARMWord InvalidBranchTarget
= 0xffffffff;
236 static const int DefaultPrefetchOffset
= 2;
238 static const ARMWord BlxInstructionMask
= 0x012fff30;
239 static const ARMWord LdrOrAddInstructionMask
= 0x0ff00000;
240 static const ARMWord LdrPcImmediateInstructionMask
= 0x0f7f0000;
242 static const ARMWord AddImmediateInstruction
= 0x02800000;
243 static const ARMWord BlxInstruction
= 0x012fff30;
244 static const ARMWord LdrImmediateInstruction
= 0x05900000;
245 static const ARMWord LdrPcImmediateInstruction
= 0x051f0000;
247 // Instruction formating
249 void emitInstruction(ARMWord op
, int rd
, int rn
, ARMWord op2
)
251 ASSERT(((op2
& ~Op2Immediate
) <= 0xfff) || (((op2
& ~ImmediateForHalfWordTransfer
) <= 0xfff)));
252 m_buffer
.putInt(op
| RN(rn
) | RD(rd
) | op2
);
255 void emitDoublePrecisionInstruction(ARMWord op
, int dd
, int dn
, int dm
)
257 ASSERT((dd
>= 0 && dd
<= 31) && (dn
>= 0 && dn
<= 31) && (dm
>= 0 && dm
<= 31));
258 m_buffer
.putInt(op
| ((dd
& 0xf) << 12) | ((dd
& 0x10) << (22 - 4))
259 | ((dn
& 0xf) << 16) | ((dn
& 0x10) << (7 - 4))
260 | (dm
& 0xf) | ((dm
& 0x10) << (5 - 4)));
263 void emitSinglePrecisionInstruction(ARMWord op
, int sd
, int sn
, int sm
)
265 ASSERT((sd
>= 0 && sd
<= 31) && (sn
>= 0 && sn
<= 31) && (sm
>= 0 && sm
<= 31));
266 m_buffer
.putInt(op
| ((sd
>> 1) << 12) | ((sd
& 0x1) << 22)
267 | ((sn
>> 1) << 16) | ((sn
& 0x1) << 7)
268 | (sm
>> 1) | ((sm
& 0x1) << 5));
271 void bitAnd(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
273 emitInstruction(toARMWord(cc
) | AND
, rd
, rn
, op2
);
276 void bitAnds(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
278 emitInstruction(toARMWord(cc
) | AND
| SetConditionalCodes
, rd
, rn
, op2
);
281 void eor(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
283 emitInstruction(toARMWord(cc
) | EOR
, rd
, rn
, op2
);
286 void eors(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
288 emitInstruction(toARMWord(cc
) | EOR
| SetConditionalCodes
, rd
, rn
, op2
);
291 void sub(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
293 emitInstruction(toARMWord(cc
) | SUB
, rd
, rn
, op2
);
296 void subs(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
298 emitInstruction(toARMWord(cc
) | SUB
| SetConditionalCodes
, rd
, rn
, op2
);
301 void rsb(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
303 emitInstruction(toARMWord(cc
) | RSB
, rd
, rn
, op2
);
306 void rsbs(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
308 emitInstruction(toARMWord(cc
) | RSB
| SetConditionalCodes
, rd
, rn
, op2
);
311 void add(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
313 emitInstruction(toARMWord(cc
) | ADD
, rd
, rn
, op2
);
316 void adds(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
318 emitInstruction(toARMWord(cc
) | ADD
| SetConditionalCodes
, rd
, rn
, op2
);
321 void adc(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
323 emitInstruction(toARMWord(cc
) | ADC
, rd
, rn
, op2
);
326 void adcs(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
328 emitInstruction(toARMWord(cc
) | ADC
| SetConditionalCodes
, rd
, rn
, op2
);
331 void sbc(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
333 emitInstruction(toARMWord(cc
) | SBC
, rd
, rn
, op2
);
336 void sbcs(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
338 emitInstruction(toARMWord(cc
) | SBC
| SetConditionalCodes
, rd
, rn
, op2
);
341 void rsc(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
343 emitInstruction(toARMWord(cc
) | RSC
, rd
, rn
, op2
);
346 void rscs(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
348 emitInstruction(toARMWord(cc
) | RSC
| SetConditionalCodes
, rd
, rn
, op2
);
351 void tst(int rn
, ARMWord op2
, Condition cc
= AL
)
353 emitInstruction(toARMWord(cc
) | TST
| SetConditionalCodes
, 0, rn
, op2
);
356 void teq(int rn
, ARMWord op2
, Condition cc
= AL
)
358 emitInstruction(toARMWord(cc
) | TEQ
| SetConditionalCodes
, 0, rn
, op2
);
361 void cmp(int rn
, ARMWord op2
, Condition cc
= AL
)
363 emitInstruction(toARMWord(cc
) | CMP
| SetConditionalCodes
, 0, rn
, op2
);
366 void cmn(int rn
, ARMWord op2
, Condition cc
= AL
)
368 emitInstruction(toARMWord(cc
) | CMN
| SetConditionalCodes
, 0, rn
, op2
);
371 void orr(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
373 emitInstruction(toARMWord(cc
) | ORR
, rd
, rn
, op2
);
376 void orrs(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
378 emitInstruction(toARMWord(cc
) | ORR
| SetConditionalCodes
, rd
, rn
, op2
);
381 void mov(int rd
, ARMWord op2
, Condition cc
= AL
)
383 emitInstruction(toARMWord(cc
) | MOV
, rd
, ARMRegisters::r0
, op2
);
386 #if WTF_ARM_ARCH_AT_LEAST(7)
387 void movw(int rd
, ARMWord op2
, Condition cc
= AL
)
389 ASSERT((op2
| 0xf0fff) == 0xf0fff);
390 m_buffer
.putInt(toARMWord(cc
) | MOVW
| RD(rd
) | op2
);
393 void movt(int rd
, ARMWord op2
, Condition cc
= AL
)
395 ASSERT((op2
| 0xf0fff) == 0xf0fff);
396 m_buffer
.putInt(toARMWord(cc
) | MOVT
| RD(rd
) | op2
);
400 void movs(int rd
, ARMWord op2
, Condition cc
= AL
)
402 emitInstruction(toARMWord(cc
) | MOV
| SetConditionalCodes
, rd
, ARMRegisters::r0
, op2
);
405 void bic(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
407 emitInstruction(toARMWord(cc
) | BIC
, rd
, rn
, op2
);
410 void bics(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
412 emitInstruction(toARMWord(cc
) | BIC
| SetConditionalCodes
, rd
, rn
, op2
);
415 void mvn(int rd
, ARMWord op2
, Condition cc
= AL
)
417 emitInstruction(toARMWord(cc
) | MVN
, rd
, ARMRegisters::r0
, op2
);
420 void mvns(int rd
, ARMWord op2
, Condition cc
= AL
)
422 emitInstruction(toARMWord(cc
) | MVN
| SetConditionalCodes
, rd
, ARMRegisters::r0
, op2
);
425 void mul(int rd
, int rn
, int rm
, Condition cc
= AL
)
427 m_buffer
.putInt(toARMWord(cc
) | MUL
| RN(rd
) | RS(rn
) | RM(rm
));
430 void muls(int rd
, int rn
, int rm
, Condition cc
= AL
)
432 m_buffer
.putInt(toARMWord(cc
) | MUL
| SetConditionalCodes
| RN(rd
) | RS(rn
) | RM(rm
));
435 void mull(int rdhi
, int rdlo
, int rn
, int rm
, Condition cc
= AL
)
437 m_buffer
.putInt(toARMWord(cc
) | MULL
| RN(rdhi
) | RD(rdlo
) | RS(rn
) | RM(rm
));
440 void vmov_f64(int dd
, int dm
, Condition cc
= AL
)
442 emitDoublePrecisionInstruction(toARMWord(cc
) | VMOV_F64
, dd
, 0, dm
);
445 void vadd_f64(int dd
, int dn
, int dm
, Condition cc
= AL
)
447 emitDoublePrecisionInstruction(toARMWord(cc
) | VADD_F64
, dd
, dn
, dm
);
450 void vdiv_f64(int dd
, int dn
, int dm
, Condition cc
= AL
)
452 emitDoublePrecisionInstruction(toARMWord(cc
) | VDIV_F64
, dd
, dn
, dm
);
455 void vsub_f64(int dd
, int dn
, int dm
, Condition cc
= AL
)
457 emitDoublePrecisionInstruction(toARMWord(cc
) | VSUB_F64
, dd
, dn
, dm
);
460 void vmul_f64(int dd
, int dn
, int dm
, Condition cc
= AL
)
462 emitDoublePrecisionInstruction(toARMWord(cc
) | VMUL_F64
, dd
, dn
, dm
);
465 void vcmp_f64(int dd
, int dm
, Condition cc
= AL
)
467 emitDoublePrecisionInstruction(toARMWord(cc
) | VCMP_F64
, dd
, 0, dm
);
470 void vsqrt_f64(int dd
, int dm
, Condition cc
= AL
)
472 emitDoublePrecisionInstruction(toARMWord(cc
) | VSQRT_F64
, dd
, 0, dm
);
475 void vabs_f64(int dd
, int dm
, Condition cc
= AL
)
477 emitDoublePrecisionInstruction(toARMWord(cc
) | VABS_F64
, dd
, 0, dm
);
480 void vneg_f64(int dd
, int dm
, Condition cc
= AL
)
482 emitDoublePrecisionInstruction(toARMWord(cc
) | VNEG_F64
, dd
, 0, dm
);
485 void ldrImmediate(int rd
, ARMWord imm
, Condition cc
= AL
)
487 m_buffer
.putIntWithConstantInt(toARMWord(cc
) | LoadUint32
| DataTransferUp
| RN(ARMRegisters::pc
) | RD(rd
), imm
, true);
490 void ldrUniqueImmediate(int rd
, ARMWord imm
, Condition cc
= AL
)
492 m_buffer
.putIntWithConstantInt(toARMWord(cc
) | LoadUint32
| DataTransferUp
| RN(ARMRegisters::pc
) | RD(rd
), imm
);
495 void dtrUp(DataTransferTypeA transferType
, int rd
, int rb
, ARMWord op2
, Condition cc
= AL
)
497 emitInstruction(toARMWord(cc
) | transferType
| DataTransferUp
, rd
, rb
, op2
);
500 void dtrUpRegister(DataTransferTypeA transferType
, int rd
, int rb
, int rm
, Condition cc
= AL
)
502 emitInstruction(toARMWord(cc
) | transferType
| DataTransferUp
| Op2IsRegisterArgument
, rd
, rb
, rm
);
505 void dtrDown(DataTransferTypeA transferType
, int rd
, int rb
, ARMWord op2
, Condition cc
= AL
)
507 emitInstruction(toARMWord(cc
) | transferType
, rd
, rb
, op2
);
510 void dtrDownRegister(DataTransferTypeA transferType
, int rd
, int rb
, int rm
, Condition cc
= AL
)
512 emitInstruction(toARMWord(cc
) | transferType
| Op2IsRegisterArgument
, rd
, rb
, rm
);
515 void halfDtrUp(DataTransferTypeB transferType
, int rd
, int rb
, ARMWord op2
, Condition cc
= AL
)
517 emitInstruction(toARMWord(cc
) | transferType
| DataTransferUp
, rd
, rb
, op2
);
520 void halfDtrUpRegister(DataTransferTypeB transferType
, int rd
, int rn
, int rm
, Condition cc
= AL
)
522 emitInstruction(toARMWord(cc
) | transferType
| DataTransferUp
, rd
, rn
, rm
);
525 void halfDtrDown(DataTransferTypeB transferType
, int rd
, int rb
, ARMWord op2
, Condition cc
= AL
)
527 emitInstruction(toARMWord(cc
) | transferType
, rd
, rb
, op2
);
530 void halfDtrDownRegister(DataTransferTypeB transferType
, int rd
, int rn
, int rm
, Condition cc
= AL
)
532 emitInstruction(toARMWord(cc
) | transferType
, rd
, rn
, rm
);
535 void doubleDtrUp(DataTransferTypeFloat type
, int rd
, int rb
, ARMWord op2
, Condition cc
= AL
)
537 ASSERT(op2
<= 0xff && rd
<= 15);
538 /* Only d0-d15 and s0, s2, s4 ... s30 are supported. */
539 m_buffer
.putInt(toARMWord(cc
) | DataTransferUp
| type
| (rd
<< 12) | RN(rb
) | op2
);
542 void doubleDtrDown(DataTransferTypeFloat type
, int rd
, int rb
, ARMWord op2
, Condition cc
= AL
)
544 ASSERT(op2
<= 0xff && rd
<= 15);
545 /* Only d0-d15 and s0, s2, s4 ... s30 are supported. */
546 m_buffer
.putInt(toARMWord(cc
) | type
| (rd
<< 12) | RN(rb
) | op2
);
549 void push(int reg
, Condition cc
= AL
)
551 ASSERT(ARMWord(reg
) <= 0xf);
552 m_buffer
.putInt(toARMWord(cc
) | StoreUint32
| DataTransferWriteBack
| RN(ARMRegisters::sp
) | RD(reg
) | 0x4);
555 void pop(int reg
, Condition cc
= AL
)
557 ASSERT(ARMWord(reg
) <= 0xf);
558 m_buffer
.putInt(toARMWord(cc
) | (LoadUint32
^ DataTransferPostUpdate
) | DataTransferUp
| RN(ARMRegisters::sp
) | RD(reg
) | 0x4);
561 inline void poke(int reg
, Condition cc
= AL
)
563 dtrDown(StoreUint32
, ARMRegisters::sp
, 0, reg
, cc
);
566 inline void peek(int reg
, Condition cc
= AL
)
568 dtrUp(LoadUint32
, reg
, ARMRegisters::sp
, 0, cc
);
571 void vmov_vfp64(int sm
, int rt
, int rt2
, Condition cc
= AL
)
574 m_buffer
.putInt(toARMWord(cc
) | VMOV_VFP64
| RN(rt2
) | RD(rt
) | (sm
& 0xf) | ((sm
& 0x10) << (5 - 4)));
577 void vmov_arm64(int rt
, int rt2
, int sm
, Condition cc
= AL
)
580 m_buffer
.putInt(toARMWord(cc
) | VMOV_ARM64
| RN(rt2
) | RD(rt
) | (sm
& 0xf) | ((sm
& 0x10) << (5 - 4)));
583 void vmov_vfp32(int sn
, int rt
, Condition cc
= AL
)
586 emitSinglePrecisionInstruction(toARMWord(cc
) | VMOV_VFP32
, rt
<< 1, sn
, 0);
589 void vmov_arm32(int rt
, int sn
, Condition cc
= AL
)
592 emitSinglePrecisionInstruction(toARMWord(cc
) | VMOV_ARM32
, rt
<< 1, sn
, 0);
595 void vcvt_f64_s32(int dd
, int sm
, Condition cc
= AL
)
597 ASSERT(!(sm
& 0x1)); // sm must be divisible by 2
598 emitDoublePrecisionInstruction(toARMWord(cc
) | VCVT_F64_S32
, dd
, 0, (sm
>> 1));
601 void vcvt_s32_f64(int sd
, int dm
, Condition cc
= AL
)
603 ASSERT(!(sd
& 0x1)); // sd must be divisible by 2
604 emitDoublePrecisionInstruction(toARMWord(cc
) | VCVT_S32_F64
, (sd
>> 1), 0, dm
);
607 void vcvt_u32_f64(int sd
, int dm
, Condition cc
= AL
)
609 ASSERT(!(sd
& 0x1)); // sd must be divisible by 2
610 emitDoublePrecisionInstruction(toARMWord(cc
) | VCVT_U32_F64
, (sd
>> 1), 0, dm
);
613 void vcvt_f64_f32(int dd
, int sm
, Condition cc
= AL
)
615 ASSERT(dd
<= 15 && sm
<= 15);
616 emitDoublePrecisionInstruction(toARMWord(cc
) | VCVT_F64_F32
, dd
, 0, sm
);
619 void vcvt_f32_f64(int dd
, int sm
, Condition cc
= AL
)
621 ASSERT(dd
<= 15 && sm
<= 15);
622 emitDoublePrecisionInstruction(toARMWord(cc
) | VCVT_F32_F64
, dd
, 0, sm
);
625 void vmrs_apsr(Condition cc
= AL
)
627 m_buffer
.putInt(toARMWord(cc
) | VMRS_APSR
);
630 void clz(int rd
, int rm
, Condition cc
= AL
)
632 m_buffer
.putInt(toARMWord(cc
) | CLZ
| RD(rd
) | RM(rm
));
635 void bkpt(ARMWord value
)
637 m_buffer
.putInt(BKPT
| ((value
& 0xff0) << 4) | (value
& 0xf));
642 m_buffer
.putInt(NOP
);
645 void bx(int rm
, Condition cc
= AL
)
647 emitInstruction(toARMWord(cc
) | BX
, 0, 0, RM(rm
));
650 AssemblerLabel
blx(int rm
, Condition cc
= AL
)
652 emitInstruction(toARMWord(cc
) | BLX
, 0, 0, RM(rm
));
653 return m_buffer
.label();
656 static ARMWord
lsl(int reg
, ARMWord value
)
658 ASSERT(reg
<= ARMRegisters::pc
);
659 ASSERT(value
<= 0x1f);
660 return reg
| (value
<< 7) | 0x00;
663 static ARMWord
lsr(int reg
, ARMWord value
)
665 ASSERT(reg
<= ARMRegisters::pc
);
666 ASSERT(value
<= 0x1f);
667 return reg
| (value
<< 7) | 0x20;
670 static ARMWord
asr(int reg
, ARMWord value
)
672 ASSERT(reg
<= ARMRegisters::pc
);
673 ASSERT(value
<= 0x1f);
674 return reg
| (value
<< 7) | 0x40;
677 static ARMWord
lslRegister(int reg
, int shiftReg
)
679 ASSERT(reg
<= ARMRegisters::pc
);
680 ASSERT(shiftReg
<= ARMRegisters::pc
);
681 return reg
| (shiftReg
<< 8) | 0x10;
684 static ARMWord
lsrRegister(int reg
, int shiftReg
)
686 ASSERT(reg
<= ARMRegisters::pc
);
687 ASSERT(shiftReg
<= ARMRegisters::pc
);
688 return reg
| (shiftReg
<< 8) | 0x30;
691 static ARMWord
asrRegister(int reg
, int shiftReg
)
693 ASSERT(reg
<= ARMRegisters::pc
);
694 ASSERT(shiftReg
<= ARMRegisters::pc
);
695 return reg
| (shiftReg
<< 8) | 0x50;
700 size_t codeSize() const
702 return m_buffer
.codeSize();
705 void ensureSpace(int insnSpace
, int constSpace
)
707 m_buffer
.ensureSpace(insnSpace
, constSpace
);
710 int sizeOfConstantPool()
712 return m_buffer
.sizeOfConstantPool();
715 AssemblerLabel
labelIgnoringWatchpoints()
717 m_buffer
.ensureSpaceForAnyInstruction();
718 return m_buffer
.label();
721 AssemblerLabel
labelForWatchpoint()
723 m_buffer
.ensureSpaceForAnyInstruction(maxJumpReplacementSize() / sizeof(ARMWord
));
724 AssemblerLabel result
= m_buffer
.label();
725 if (result
.m_offset
!= (m_indexOfTailOfLastWatchpoint
- maxJumpReplacementSize()))
727 m_indexOfTailOfLastWatchpoint
= result
.m_offset
+ maxJumpReplacementSize();
731 AssemblerLabel
label()
733 AssemblerLabel result
= labelIgnoringWatchpoints();
734 while (result
.m_offset
+ 1 < m_indexOfTailOfLastWatchpoint
) {
736 // The available number of instructions are ensured by labelForWatchpoint.
737 result
= m_buffer
.label();
742 AssemblerLabel
align(int alignment
)
744 while (!m_buffer
.isAligned(alignment
))
745 mov(ARMRegisters::r0
, ARMRegisters::r0
);
750 AssemblerLabel
loadBranchTarget(int rd
, Condition cc
= AL
, int useConstantPool
= 0)
752 ensureSpace(sizeof(ARMWord
), sizeof(ARMWord
));
753 m_jumps
.append(m_buffer
.codeSize() | (useConstantPool
& 0x1));
754 ldrUniqueImmediate(rd
, InvalidBranchTarget
, cc
);
755 return m_buffer
.label();
758 AssemblerLabel
jmp(Condition cc
= AL
, int useConstantPool
= 0)
760 return loadBranchTarget(ARMRegisters::pc
, cc
, useConstantPool
);
763 PassRefPtr
<ExecutableMemoryHandle
> executableCopy(VM
&, void* ownerUID
, JITCompilationEffort
);
765 unsigned debugOffset() { return m_buffer
.debugOffset(); }
767 // DFG assembly helpers for moving data between fp and registers.
768 void vmov(RegisterID rd1
, RegisterID rd2
, FPRegisterID rn
)
770 vmov_arm64(rd1
, rd2
, rn
);
773 void vmov(FPRegisterID rd
, RegisterID rn1
, RegisterID rn2
)
775 vmov_vfp64(rd
, rn1
, rn2
);
780 static ARMWord
* getLdrImmAddress(ARMWord
* insn
)
783 if ((*insn
& LdrPcImmediateInstructionMask
) != LdrPcImmediateInstruction
) {
785 ASSERT((*insn
& BlxInstructionMask
) == BlxInstruction
);
789 // Must be an ldr ..., [pc +/- imm]
790 ASSERT((*insn
& LdrPcImmediateInstructionMask
) == LdrPcImmediateInstruction
);
792 ARMWord addr
= reinterpret_cast<ARMWord
>(insn
) + DefaultPrefetchOffset
* sizeof(ARMWord
);
793 if (*insn
& DataTransferUp
)
794 return reinterpret_cast<ARMWord
*>(addr
+ (*insn
& DataTransferOffsetMask
));
795 return reinterpret_cast<ARMWord
*>(addr
- (*insn
& DataTransferOffsetMask
));
798 static ARMWord
* getLdrImmAddressOnPool(ARMWord
* insn
, uint32_t* constPool
)
800 // Must be an ldr ..., [pc +/- imm]
801 ASSERT((*insn
& LdrPcImmediateInstructionMask
) == LdrPcImmediateInstruction
);
804 return reinterpret_cast<ARMWord
*>(constPool
+ ((*insn
& DataTransferOffsetMask
) >> 1));
805 return getLdrImmAddress(insn
);
808 static void patchPointerInternal(intptr_t from
, void* to
)
810 ARMWord
* insn
= reinterpret_cast<ARMWord
*>(from
);
811 ARMWord
* addr
= getLdrImmAddress(insn
);
812 *addr
= reinterpret_cast<ARMWord
>(to
);
815 static ARMWord
patchConstantPoolLoad(ARMWord load
, ARMWord value
)
817 value
= (value
<< 1) + 1;
818 ASSERT(!(value
& ~DataTransferOffsetMask
));
819 return (load
& ~DataTransferOffsetMask
) | value
;
822 static void patchConstantPoolLoad(void* loadAddr
, void* constPoolAddr
);
825 static void* readPointer(void* from
)
827 ARMWord
* instruction
= reinterpret_cast<ARMWord
*>(from
);
828 ARMWord
* address
= getLdrImmAddress(instruction
);
829 return *reinterpret_cast<void**>(address
);
834 static void linkPointer(void* code
, AssemblerLabel from
, void* to
)
836 patchPointerInternal(reinterpret_cast<intptr_t>(code
) + from
.m_offset
, to
);
839 static void repatchInt32(void* where
, int32_t to
)
841 patchPointerInternal(reinterpret_cast<intptr_t>(where
), reinterpret_cast<void*>(to
));
844 static void repatchCompact(void* where
, int32_t value
)
846 ARMWord
* instruction
= reinterpret_cast<ARMWord
*>(where
);
847 ASSERT((*instruction
& 0x0f700000) == LoadUint32
);
849 *instruction
= (*instruction
& 0xff7ff000) | DataTransferUp
| value
;
851 *instruction
= (*instruction
& 0xff7ff000) | -value
;
852 cacheFlush(instruction
, sizeof(ARMWord
));
855 static void repatchPointer(void* from
, void* to
)
857 patchPointerInternal(reinterpret_cast<intptr_t>(from
), to
);
861 static intptr_t getAbsoluteJumpAddress(void* base
, int offset
= 0)
863 return reinterpret_cast<intptr_t>(base
) + offset
- sizeof(ARMWord
);
866 void linkJump(AssemblerLabel from
, AssemblerLabel to
)
868 ARMWord
* insn
= reinterpret_cast<ARMWord
*>(getAbsoluteJumpAddress(m_buffer
.data(), from
.m_offset
));
869 ARMWord
* addr
= getLdrImmAddressOnPool(insn
, m_buffer
.poolAddress());
870 *addr
= toARMWord(to
.m_offset
);
873 static void linkJump(void* code
, AssemblerLabel from
, void* to
)
875 patchPointerInternal(getAbsoluteJumpAddress(code
, from
.m_offset
), to
);
878 static void relinkJump(void* from
, void* to
)
880 patchPointerInternal(getAbsoluteJumpAddress(from
), to
);
883 static void linkCall(void* code
, AssemblerLabel from
, void* to
)
885 patchPointerInternal(getAbsoluteJumpAddress(code
, from
.m_offset
), to
);
888 static void relinkCall(void* from
, void* to
)
890 patchPointerInternal(getAbsoluteJumpAddress(from
), to
);
893 static void* readCallTarget(void* from
)
895 return reinterpret_cast<void*>(readPointer(reinterpret_cast<void*>(getAbsoluteJumpAddress(from
))));
898 static void replaceWithJump(void* instructionStart
, void* to
)
900 ARMWord
* instruction
= reinterpret_cast<ARMWord
*>(instructionStart
);
901 intptr_t difference
= reinterpret_cast<intptr_t>(to
) - (reinterpret_cast<intptr_t>(instruction
) + DefaultPrefetchOffset
* sizeof(ARMWord
));
903 if (!(difference
& 1)) {
905 if ((difference
<= MaximumBranchOffsetDistance
&& difference
>= MinimumBranchOffsetDistance
)) {
907 instruction
[0] = B
| AL
| (difference
& BranchOffsetMask
);
908 cacheFlush(instruction
, sizeof(ARMWord
));
914 instruction
[0] = LoadUint32
| AL
| RN(ARMRegisters::pc
) | RD(ARMRegisters::pc
) | 4;
915 instruction
[1] = reinterpret_cast<ARMWord
>(to
);
916 cacheFlush(instruction
, sizeof(ARMWord
) * 2);
919 static ptrdiff_t maxJumpReplacementSize()
921 return sizeof(ARMWord
) * 2;
924 static void replaceWithLoad(void* instructionStart
)
926 ARMWord
* instruction
= reinterpret_cast<ARMWord
*>(instructionStart
);
927 cacheFlush(instruction
, sizeof(ARMWord
));
929 ASSERT((*instruction
& LdrOrAddInstructionMask
) == AddImmediateInstruction
|| (*instruction
& LdrOrAddInstructionMask
) == LdrImmediateInstruction
);
930 if ((*instruction
& LdrOrAddInstructionMask
) == AddImmediateInstruction
) {
931 *instruction
= (*instruction
& ~LdrOrAddInstructionMask
) | LdrImmediateInstruction
;
932 cacheFlush(instruction
, sizeof(ARMWord
));
936 static void replaceWithAddressComputation(void* instructionStart
)
938 ARMWord
* instruction
= reinterpret_cast<ARMWord
*>(instructionStart
);
939 cacheFlush(instruction
, sizeof(ARMWord
));
941 ASSERT((*instruction
& LdrOrAddInstructionMask
) == AddImmediateInstruction
|| (*instruction
& LdrOrAddInstructionMask
) == LdrImmediateInstruction
);
942 if ((*instruction
& LdrOrAddInstructionMask
) == LdrImmediateInstruction
) {
943 *instruction
= (*instruction
& ~LdrOrAddInstructionMask
) | AddImmediateInstruction
;
944 cacheFlush(instruction
, sizeof(ARMWord
));
948 static void revertBranchPtrWithPatch(void* instructionStart
, RegisterID rn
, ARMWord imm
)
950 ARMWord
* instruction
= reinterpret_cast<ARMWord
*>(instructionStart
);
952 ASSERT((instruction
[2] & LdrPcImmediateInstructionMask
) == LdrPcImmediateInstruction
);
953 instruction
[0] = toARMWord(AL
) | ((instruction
[2] & 0x0fff0fff) + sizeof(ARMWord
)) | RD(ARMRegisters::S1
);
954 *getLdrImmAddress(instruction
) = imm
;
955 instruction
[1] = toARMWord(AL
) | CMP
| SetConditionalCodes
| RN(rn
) | RM(ARMRegisters::S1
);
956 cacheFlush(instruction
, 2 * sizeof(ARMWord
));
959 // Address operations
961 static void* getRelocatedAddress(void* code
, AssemblerLabel label
)
963 return reinterpret_cast<void*>(reinterpret_cast<char*>(code
) + label
.m_offset
);
966 // Address differences
968 static int getDifferenceBetweenLabels(AssemblerLabel a
, AssemblerLabel b
)
970 return b
.m_offset
- a
.m_offset
;
973 static unsigned getCallReturnOffset(AssemblerLabel call
)
975 return call
.m_offset
;
980 static ARMWord
getOp2(ARMWord imm
);
982 // Fast case if imm is known to be between 0 and 0xff
983 static ARMWord
getOp2Byte(ARMWord imm
)
986 return Op2Immediate
| imm
;
989 static ARMWord
getOp2Half(ARMWord imm
)
992 return ImmediateForHalfWordTransfer
| (imm
& 0x0f) | ((imm
& 0xf0) << 4);
995 #if WTF_ARM_ARCH_AT_LEAST(7)
996 static ARMWord
getImm16Op2(ARMWord imm
)
999 return (imm
& 0xf000) << 4 | (imm
& 0xfff);
1000 return InvalidImmediate
;
1003 ARMWord
getImm(ARMWord imm
, int tmpReg
, bool invert
= false);
1004 void moveImm(ARMWord imm
, int dest
);
1005 ARMWord
encodeComplexImm(ARMWord imm
, int dest
);
1007 // Memory load/store helpers
1009 void dataTransfer32(DataTransferTypeA
, RegisterID srcDst
, RegisterID base
, int32_t offset
);
1010 void baseIndexTransfer32(DataTransferTypeA
, RegisterID srcDst
, RegisterID base
, RegisterID index
, int scale
, int32_t offset
);
1011 void dataTransfer16(DataTransferTypeB
, RegisterID srcDst
, RegisterID base
, int32_t offset
);
1012 void baseIndexTransfer16(DataTransferTypeB
, RegisterID srcDst
, RegisterID base
, RegisterID index
, int scale
, int32_t offset
);
1013 void dataTransferFloat(DataTransferTypeFloat
, FPRegisterID srcDst
, RegisterID base
, int32_t offset
);
1014 void baseIndexTransferFloat(DataTransferTypeFloat
, FPRegisterID srcDst
, RegisterID base
, RegisterID index
, int scale
, int32_t offset
);
1016 // Constant pool hnadlers
1018 static ARMWord
placeConstantPoolBarrier(int offset
)
1020 offset
= (offset
- sizeof(ARMWord
)) >> 2;
1021 ASSERT((offset
<= MaximumBranchOffsetDistance
&& offset
>= MinimumBranchOffsetDistance
));
1022 return AL
| B
| (offset
& BranchOffsetMask
);
1025 #if OS(LINUX) && COMPILER(GCC)
1026 static inline void linuxPageFlush(uintptr_t begin
, uintptr_t end
)
1032 "mov r7, #0xf0000\n"
1033 "add r7, r7, #0x2\n"
1038 : "r" (begin
), "r" (end
)
1039 : "r0", "r1", "r2");
1043 #if OS(LINUX) && COMPILER(RVCT)
1044 static __asm
void cacheFlush(void* code
, size_t);
1046 static void cacheFlush(void* code
, size_t size
)
1048 #if OS(LINUX) && COMPILER(GCC)
1049 size_t page
= pageSize();
1050 uintptr_t current
= reinterpret_cast<uintptr_t>(code
);
1051 uintptr_t end
= current
+ size
;
1052 uintptr_t firstPageEnd
= (current
& ~(page
- 1)) + page
;
1054 if (end
<= firstPageEnd
) {
1055 linuxPageFlush(current
, end
);
1059 linuxPageFlush(current
, firstPageEnd
);
1061 for (current
= firstPageEnd
; current
+ page
< end
; current
+= page
)
1062 linuxPageFlush(current
, current
+ page
);
1064 linuxPageFlush(current
, end
);
1066 CacheRangeFlush(code
, size
, CACHE_SYNC_ALL
);
1067 #elif OS(QNX) && ENABLE(ASSEMBLER_WX_EXCLUSIVE)
1071 msync(code
, size
, MS_INVALIDATE_ICACHE
);
1073 #error "The cacheFlush support is missing on this platform."
1079 static ARMWord
RM(int reg
)
1081 ASSERT(reg
<= ARMRegisters::pc
);
1085 static ARMWord
RS(int reg
)
1087 ASSERT(reg
<= ARMRegisters::pc
);
1091 static ARMWord
RD(int reg
)
1093 ASSERT(reg
<= ARMRegisters::pc
);
1097 static ARMWord
RN(int reg
)
1099 ASSERT(reg
<= ARMRegisters::pc
);
1103 static ARMWord
getConditionalField(ARMWord i
)
1105 return i
& ConditionalFieldMask
;
1108 static ARMWord
toARMWord(Condition cc
)
1110 return static_cast<ARMWord
>(cc
);
1113 static ARMWord
toARMWord(uint32_t u
)
1115 return static_cast<ARMWord
>(u
);
1118 int genInt(int reg
, ARMWord imm
, bool positive
);
1122 uint32_t m_indexOfTailOfLastWatchpoint
;
1127 #endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
1129 #endif // ARMAssembler_h