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
{
52 r11
, fp
= r11
, // frame pointer
53 r12
, ip
= r12
, S1
= r12
,
67 d7
, SD0
= d7
, /* Same as thumb assembler. */
95 #define FOR_EACH_CPU_REGISTER(V) \
96 FOR_EACH_CPU_GPREGISTER(V) \
97 FOR_EACH_CPU_SPECIAL_REGISTER(V) \
98 FOR_EACH_CPU_FPREGISTER(V)
100 #define FOR_EACH_CPU_GPREGISTER(V) \
118 #define FOR_EACH_CPU_SPECIAL_REGISTER(V) \
122 #define FOR_EACH_CPU_FPREGISTER(V) \
139 #endif // USE(MASM_PROBE)
140 } // namespace ARMRegisters
144 typedef ARMRegisters::RegisterID RegisterID
;
145 typedef ARMRegisters::FPRegisterID FPRegisterID
;
146 typedef AssemblerBufferWithConstantPool
<2048, 4, 4, ARMAssembler
> ARMBuffer
;
147 typedef SegmentedVector
<AssemblerLabel
, 64> Jumps
;
150 : m_indexOfTailOfLastWatchpoint(1)
154 ARMBuffer
& buffer() { return m_buffer
; }
156 static RegisterID
firstRegister() { return ARMRegisters::r0
; }
157 static RegisterID
lastRegister() { return ARMRegisters::r15
; }
159 static FPRegisterID
firstFPRegister() { return ARMRegisters::d0
; }
160 static FPRegisterID
lastFPRegister() { return ARMRegisters::d31
; }
162 // ARM conditional constants
164 EQ
= 0x00000000, // Zero / Equal.
165 NE
= 0x10000000, // Non-zero / Not equal.
166 CS
= 0x20000000, // Unsigned higher or same.
167 CC
= 0x30000000, // Unsigned lower.
168 MI
= 0x40000000, // Negative.
169 PL
= 0x50000000, // Positive or zero.
170 VS
= 0x60000000, // Overflowed.
171 VC
= 0x70000000, // Not overflowed.
172 HI
= 0x80000000, // Unsigned higher.
173 LS
= 0x90000000, // Unsigned lower or same.
174 GE
= 0xa0000000, // Signed greater than or equal.
175 LT
= 0xb0000000, // Signed less than.
176 GT
= 0xc0000000, // Signed greater than.
177 LE
= 0xd0000000, // Signed less than or equal.
178 AL
= 0xe0000000 // Unconditional / Always execute.
181 // ARM instruction constants
201 VMOV_F64
= 0x0eb00b40,
202 VADD_F64
= 0x0e300b00,
203 VDIV_F64
= 0x0e800b00,
204 VSUB_F64
= 0x0e300b40,
205 VMUL_F64
= 0x0e200b00,
206 VCMP_F64
= 0x0eb40b40,
207 VSQRT_F64
= 0x0eb10bc0,
208 VABS_F64
= 0x0eb00bc0,
209 VNEG_F64
= 0x0eb10b40,
215 VMOV_VFP64
= 0x0c400a10,
216 VMOV_ARM64
= 0x0c500a10,
217 VMOV_VFP32
= 0x0e000a10,
218 VMOV_ARM32
= 0x0e100a10,
219 VCVT_F64_S32
= 0x0eb80bc0,
220 VCVT_S32_F64
= 0x0ebd0bc0,
221 VCVT_U32_F64
= 0x0ebc0bc0,
222 VCVT_F32_F64
= 0x0eb70bc0,
223 VCVT_F64_F32
= 0x0eb70ac0,
224 VMRS_APSR
= 0x0ef1fa10,
228 #if WTF_ARM_ARCH_AT_LEAST(7)
237 Op2Immediate
= (1 << 25),
238 ImmediateForHalfWordTransfer
= (1 << 22),
239 Op2InvertedImmediate
= (1 << 26),
240 SetConditionalCodes
= (1 << 20),
241 Op2IsRegisterArgument
= (1 << 25),
242 // Data transfer flags.
243 DataTransferUp
= (1 << 23),
244 DataTransferWriteBack
= (1 << 21),
245 DataTransferPostUpdate
= (1 << 24),
246 DataTransferLoad
= (1 << 20),
247 ByteDataTransfer
= (1 << 22),
250 enum DataTransferTypeA
{
251 LoadUint32
= 0x05000000 | DataTransferLoad
,
252 LoadUint8
= 0x05400000 | DataTransferLoad
,
253 StoreUint32
= 0x05000000,
254 StoreUint8
= 0x05400000,
257 enum DataTransferTypeB
{
258 LoadUint16
= 0x010000b0 | DataTransferLoad
,
259 LoadInt16
= 0x010000f0 | DataTransferLoad
,
260 LoadInt8
= 0x010000d0 | DataTransferLoad
,
261 StoreUint16
= 0x010000b0,
264 enum DataTransferTypeFloat
{
265 LoadFloat
= 0x0d000a00 | DataTransferLoad
,
266 LoadDouble
= 0x0d000b00 | DataTransferLoad
,
267 StoreFloat
= 0x0d000a00,
268 StoreDouble
= 0x0d000b00,
271 // Masks of ARM instructions
273 BranchOffsetMask
= 0x00ffffff,
274 ConditionalFieldMask
= 0xf0000000,
275 DataTransferOffsetMask
= 0xfff,
279 MinimumBranchOffsetDistance
= -0x00800000,
280 MaximumBranchOffsetDistance
= 0x007fffff,
285 padForAlign16
= 0x0000,
286 padForAlign32
= 0xe12fff7f // 'bkpt 0xffff' instruction.
289 static const ARMWord InvalidImmediate
= 0xf0000000;
290 static const ARMWord InvalidBranchTarget
= 0xffffffff;
291 static const int DefaultPrefetchOffset
= 2;
293 static const ARMWord BlxInstructionMask
= 0x012fff30;
294 static const ARMWord LdrOrAddInstructionMask
= 0x0ff00000;
295 static const ARMWord LdrPcImmediateInstructionMask
= 0x0f7f0000;
297 static const ARMWord AddImmediateInstruction
= 0x02800000;
298 static const ARMWord BlxInstruction
= 0x012fff30;
299 static const ARMWord LdrImmediateInstruction
= 0x05900000;
300 static const ARMWord LdrPcImmediateInstruction
= 0x051f0000;
302 // Instruction formating
304 void emitInstruction(ARMWord op
, int rd
, int rn
, ARMWord op2
)
306 ASSERT(((op2
& ~Op2Immediate
) <= 0xfff) || (((op2
& ~ImmediateForHalfWordTransfer
) <= 0xfff)));
307 m_buffer
.putInt(op
| RN(rn
) | RD(rd
) | op2
);
310 void emitDoublePrecisionInstruction(ARMWord op
, int dd
, int dn
, int dm
)
312 ASSERT((dd
>= 0 && dd
<= 31) && (dn
>= 0 && dn
<= 31) && (dm
>= 0 && dm
<= 31));
313 m_buffer
.putInt(op
| ((dd
& 0xf) << 12) | ((dd
& 0x10) << (22 - 4))
314 | ((dn
& 0xf) << 16) | ((dn
& 0x10) << (7 - 4))
315 | (dm
& 0xf) | ((dm
& 0x10) << (5 - 4)));
318 void emitSinglePrecisionInstruction(ARMWord op
, int sd
, int sn
, int sm
)
320 ASSERT((sd
>= 0 && sd
<= 31) && (sn
>= 0 && sn
<= 31) && (sm
>= 0 && sm
<= 31));
321 m_buffer
.putInt(op
| ((sd
>> 1) << 12) | ((sd
& 0x1) << 22)
322 | ((sn
>> 1) << 16) | ((sn
& 0x1) << 7)
323 | (sm
>> 1) | ((sm
& 0x1) << 5));
326 void bitAnd(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
328 emitInstruction(toARMWord(cc
) | AND
, rd
, rn
, op2
);
331 void bitAnds(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
333 emitInstruction(toARMWord(cc
) | AND
| SetConditionalCodes
, rd
, rn
, op2
);
336 void eor(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
338 emitInstruction(toARMWord(cc
) | EOR
, rd
, rn
, op2
);
341 void eors(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
343 emitInstruction(toARMWord(cc
) | EOR
| SetConditionalCodes
, rd
, rn
, op2
);
346 void sub(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
348 emitInstruction(toARMWord(cc
) | SUB
, rd
, rn
, op2
);
351 void subs(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
353 emitInstruction(toARMWord(cc
) | SUB
| SetConditionalCodes
, rd
, rn
, op2
);
356 void rsb(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
358 emitInstruction(toARMWord(cc
) | RSB
, rd
, rn
, op2
);
361 void rsbs(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
363 emitInstruction(toARMWord(cc
) | RSB
| SetConditionalCodes
, rd
, rn
, op2
);
366 void add(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
368 emitInstruction(toARMWord(cc
) | ADD
, rd
, rn
, op2
);
371 void adds(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
373 emitInstruction(toARMWord(cc
) | ADD
| SetConditionalCodes
, rd
, rn
, op2
);
376 void adc(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
378 emitInstruction(toARMWord(cc
) | ADC
, rd
, rn
, op2
);
381 void adcs(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
383 emitInstruction(toARMWord(cc
) | ADC
| SetConditionalCodes
, rd
, rn
, op2
);
386 void sbc(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
388 emitInstruction(toARMWord(cc
) | SBC
, rd
, rn
, op2
);
391 void sbcs(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
393 emitInstruction(toARMWord(cc
) | SBC
| SetConditionalCodes
, rd
, rn
, op2
);
396 void rsc(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
398 emitInstruction(toARMWord(cc
) | RSC
, rd
, rn
, op2
);
401 void rscs(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
403 emitInstruction(toARMWord(cc
) | RSC
| SetConditionalCodes
, rd
, rn
, op2
);
406 void tst(int rn
, ARMWord op2
, Condition cc
= AL
)
408 emitInstruction(toARMWord(cc
) | TST
| SetConditionalCodes
, 0, rn
, op2
);
411 void teq(int rn
, ARMWord op2
, Condition cc
= AL
)
413 emitInstruction(toARMWord(cc
) | TEQ
| SetConditionalCodes
, 0, rn
, op2
);
416 void cmp(int rn
, ARMWord op2
, Condition cc
= AL
)
418 emitInstruction(toARMWord(cc
) | CMP
| SetConditionalCodes
, 0, rn
, op2
);
421 void cmn(int rn
, ARMWord op2
, Condition cc
= AL
)
423 emitInstruction(toARMWord(cc
) | CMN
| SetConditionalCodes
, 0, rn
, op2
);
426 void orr(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
428 emitInstruction(toARMWord(cc
) | ORR
, rd
, rn
, op2
);
431 void orrs(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
433 emitInstruction(toARMWord(cc
) | ORR
| SetConditionalCodes
, rd
, rn
, op2
);
436 void mov(int rd
, ARMWord op2
, Condition cc
= AL
)
438 emitInstruction(toARMWord(cc
) | MOV
, rd
, ARMRegisters::r0
, op2
);
441 #if WTF_ARM_ARCH_AT_LEAST(7)
442 void movw(int rd
, ARMWord op2
, Condition cc
= AL
)
444 ASSERT((op2
| 0xf0fff) == 0xf0fff);
445 m_buffer
.putInt(toARMWord(cc
) | MOVW
| RD(rd
) | op2
);
448 void movt(int rd
, ARMWord op2
, Condition cc
= AL
)
450 ASSERT((op2
| 0xf0fff) == 0xf0fff);
451 m_buffer
.putInt(toARMWord(cc
) | MOVT
| RD(rd
) | op2
);
455 void movs(int rd
, ARMWord op2
, Condition cc
= AL
)
457 emitInstruction(toARMWord(cc
) | MOV
| SetConditionalCodes
, rd
, ARMRegisters::r0
, op2
);
460 void bic(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
462 emitInstruction(toARMWord(cc
) | BIC
, rd
, rn
, op2
);
465 void bics(int rd
, int rn
, ARMWord op2
, Condition cc
= AL
)
467 emitInstruction(toARMWord(cc
) | BIC
| SetConditionalCodes
, rd
, rn
, op2
);
470 void mvn(int rd
, ARMWord op2
, Condition cc
= AL
)
472 emitInstruction(toARMWord(cc
) | MVN
, rd
, ARMRegisters::r0
, op2
);
475 void mvns(int rd
, ARMWord op2
, Condition cc
= AL
)
477 emitInstruction(toARMWord(cc
) | MVN
| SetConditionalCodes
, rd
, ARMRegisters::r0
, op2
);
480 void mul(int rd
, int rn
, int rm
, Condition cc
= AL
)
482 m_buffer
.putInt(toARMWord(cc
) | MUL
| RN(rd
) | RS(rn
) | RM(rm
));
485 void muls(int rd
, int rn
, int rm
, Condition cc
= AL
)
487 m_buffer
.putInt(toARMWord(cc
) | MUL
| SetConditionalCodes
| RN(rd
) | RS(rn
) | RM(rm
));
490 void mull(int rdhi
, int rdlo
, int rn
, int rm
, Condition cc
= AL
)
492 m_buffer
.putInt(toARMWord(cc
) | MULL
| RN(rdhi
) | RD(rdlo
) | RS(rn
) | RM(rm
));
495 void vmov_f64(int dd
, int dm
, Condition cc
= AL
)
497 emitDoublePrecisionInstruction(toARMWord(cc
) | VMOV_F64
, dd
, 0, dm
);
500 void vadd_f64(int dd
, int dn
, int dm
, Condition cc
= AL
)
502 emitDoublePrecisionInstruction(toARMWord(cc
) | VADD_F64
, dd
, dn
, dm
);
505 void vdiv_f64(int dd
, int dn
, int dm
, Condition cc
= AL
)
507 emitDoublePrecisionInstruction(toARMWord(cc
) | VDIV_F64
, dd
, dn
, dm
);
510 void vsub_f64(int dd
, int dn
, int dm
, Condition cc
= AL
)
512 emitDoublePrecisionInstruction(toARMWord(cc
) | VSUB_F64
, dd
, dn
, dm
);
515 void vmul_f64(int dd
, int dn
, int dm
, Condition cc
= AL
)
517 emitDoublePrecisionInstruction(toARMWord(cc
) | VMUL_F64
, dd
, dn
, dm
);
520 void vcmp_f64(int dd
, int dm
, Condition cc
= AL
)
522 emitDoublePrecisionInstruction(toARMWord(cc
) | VCMP_F64
, dd
, 0, dm
);
525 void vsqrt_f64(int dd
, int dm
, Condition cc
= AL
)
527 emitDoublePrecisionInstruction(toARMWord(cc
) | VSQRT_F64
, dd
, 0, dm
);
530 void vabs_f64(int dd
, int dm
, Condition cc
= AL
)
532 emitDoublePrecisionInstruction(toARMWord(cc
) | VABS_F64
, dd
, 0, dm
);
535 void vneg_f64(int dd
, int dm
, Condition cc
= AL
)
537 emitDoublePrecisionInstruction(toARMWord(cc
) | VNEG_F64
, dd
, 0, dm
);
540 void ldrImmediate(int rd
, ARMWord imm
, Condition cc
= AL
)
542 m_buffer
.putIntWithConstantInt(toARMWord(cc
) | LoadUint32
| DataTransferUp
| RN(ARMRegisters::pc
) | RD(rd
), imm
, true);
545 void ldrUniqueImmediate(int rd
, ARMWord imm
, Condition cc
= AL
)
547 m_buffer
.putIntWithConstantInt(toARMWord(cc
) | LoadUint32
| DataTransferUp
| RN(ARMRegisters::pc
) | RD(rd
), imm
);
550 void dtrUp(DataTransferTypeA transferType
, int rd
, int rb
, ARMWord op2
, Condition cc
= AL
)
552 emitInstruction(toARMWord(cc
) | transferType
| DataTransferUp
, rd
, rb
, op2
);
555 void dtrUpRegister(DataTransferTypeA transferType
, int rd
, int rb
, int rm
, Condition cc
= AL
)
557 emitInstruction(toARMWord(cc
) | transferType
| DataTransferUp
| Op2IsRegisterArgument
, rd
, rb
, rm
);
560 void dtrDown(DataTransferTypeA transferType
, int rd
, int rb
, ARMWord op2
, Condition cc
= AL
)
562 emitInstruction(toARMWord(cc
) | transferType
, rd
, rb
, op2
);
565 void dtrDownRegister(DataTransferTypeA transferType
, int rd
, int rb
, int rm
, Condition cc
= AL
)
567 emitInstruction(toARMWord(cc
) | transferType
| Op2IsRegisterArgument
, rd
, rb
, rm
);
570 void halfDtrUp(DataTransferTypeB transferType
, int rd
, int rb
, ARMWord op2
, Condition cc
= AL
)
572 emitInstruction(toARMWord(cc
) | transferType
| DataTransferUp
, rd
, rb
, op2
);
575 void halfDtrUpRegister(DataTransferTypeB transferType
, int rd
, int rn
, int rm
, Condition cc
= AL
)
577 emitInstruction(toARMWord(cc
) | transferType
| DataTransferUp
, rd
, rn
, rm
);
580 void halfDtrDown(DataTransferTypeB transferType
, int rd
, int rb
, ARMWord op2
, Condition cc
= AL
)
582 emitInstruction(toARMWord(cc
) | transferType
, rd
, rb
, op2
);
585 void halfDtrDownRegister(DataTransferTypeB transferType
, int rd
, int rn
, int rm
, Condition cc
= AL
)
587 emitInstruction(toARMWord(cc
) | transferType
, rd
, rn
, rm
);
590 void doubleDtrUp(DataTransferTypeFloat type
, int rd
, int rb
, ARMWord op2
, Condition cc
= AL
)
592 ASSERT(op2
<= 0xff && rd
<= 15);
593 /* Only d0-d15 and s0, s2, s4 ... s30 are supported. */
594 m_buffer
.putInt(toARMWord(cc
) | DataTransferUp
| type
| (rd
<< 12) | RN(rb
) | op2
);
597 void doubleDtrDown(DataTransferTypeFloat type
, int rd
, int rb
, ARMWord op2
, Condition cc
= AL
)
599 ASSERT(op2
<= 0xff && rd
<= 15);
600 /* Only d0-d15 and s0, s2, s4 ... s30 are supported. */
601 m_buffer
.putInt(toARMWord(cc
) | type
| (rd
<< 12) | RN(rb
) | op2
);
604 void push(int reg
, Condition cc
= AL
)
606 ASSERT(ARMWord(reg
) <= 0xf);
607 m_buffer
.putInt(toARMWord(cc
) | StoreUint32
| DataTransferWriteBack
| RN(ARMRegisters::sp
) | RD(reg
) | 0x4);
610 void pop(int reg
, Condition cc
= AL
)
612 ASSERT(ARMWord(reg
) <= 0xf);
613 m_buffer
.putInt(toARMWord(cc
) | (LoadUint32
^ DataTransferPostUpdate
) | DataTransferUp
| RN(ARMRegisters::sp
) | RD(reg
) | 0x4);
616 inline void poke(int reg
, Condition cc
= AL
)
618 dtrDown(StoreUint32
, ARMRegisters::sp
, 0, reg
, cc
);
621 inline void peek(int reg
, Condition cc
= AL
)
623 dtrUp(LoadUint32
, reg
, ARMRegisters::sp
, 0, cc
);
626 void vmov_vfp64(int sm
, int rt
, int rt2
, Condition cc
= AL
)
629 m_buffer
.putInt(toARMWord(cc
) | VMOV_VFP64
| RN(rt2
) | RD(rt
) | (sm
& 0xf) | ((sm
& 0x10) << (5 - 4)));
632 void vmov_arm64(int rt
, int rt2
, int sm
, Condition cc
= AL
)
635 m_buffer
.putInt(toARMWord(cc
) | VMOV_ARM64
| RN(rt2
) | RD(rt
) | (sm
& 0xf) | ((sm
& 0x10) << (5 - 4)));
638 void vmov_vfp32(int sn
, int rt
, Condition cc
= AL
)
641 emitSinglePrecisionInstruction(toARMWord(cc
) | VMOV_VFP32
, rt
<< 1, sn
, 0);
644 void vmov_arm32(int rt
, int sn
, Condition cc
= AL
)
647 emitSinglePrecisionInstruction(toARMWord(cc
) | VMOV_ARM32
, rt
<< 1, sn
, 0);
650 void vcvt_f64_s32(int dd
, int sm
, Condition cc
= AL
)
652 ASSERT(!(sm
& 0x1)); // sm must be divisible by 2
653 emitDoublePrecisionInstruction(toARMWord(cc
) | VCVT_F64_S32
, dd
, 0, (sm
>> 1));
656 void vcvt_s32_f64(int sd
, int dm
, Condition cc
= AL
)
658 ASSERT(!(sd
& 0x1)); // sd must be divisible by 2
659 emitDoublePrecisionInstruction(toARMWord(cc
) | VCVT_S32_F64
, (sd
>> 1), 0, dm
);
662 void vcvt_u32_f64(int sd
, int dm
, Condition cc
= AL
)
664 ASSERT(!(sd
& 0x1)); // sd must be divisible by 2
665 emitDoublePrecisionInstruction(toARMWord(cc
) | VCVT_U32_F64
, (sd
>> 1), 0, dm
);
668 void vcvt_f64_f32(int dd
, int sm
, Condition cc
= AL
)
670 ASSERT(dd
<= 15 && sm
<= 15);
671 emitDoublePrecisionInstruction(toARMWord(cc
) | VCVT_F64_F32
, dd
, 0, sm
);
674 void vcvt_f32_f64(int dd
, int sm
, Condition cc
= AL
)
676 ASSERT(dd
<= 15 && sm
<= 15);
677 emitDoublePrecisionInstruction(toARMWord(cc
) | VCVT_F32_F64
, dd
, 0, sm
);
680 void vmrs_apsr(Condition cc
= AL
)
682 m_buffer
.putInt(toARMWord(cc
) | VMRS_APSR
);
685 void clz(int rd
, int rm
, Condition cc
= AL
)
687 m_buffer
.putInt(toARMWord(cc
) | CLZ
| RD(rd
) | RM(rm
));
690 void bkpt(ARMWord value
)
692 m_buffer
.putInt(BKPT
| ((value
& 0xff0) << 4) | (value
& 0xf));
697 m_buffer
.putInt(NOP
);
702 m_buffer
.putInt(DMB_SY
);
705 void bx(int rm
, Condition cc
= AL
)
707 emitInstruction(toARMWord(cc
) | BX
, 0, 0, RM(rm
));
710 AssemblerLabel
blx(int rm
, Condition cc
= AL
)
712 emitInstruction(toARMWord(cc
) | BLX
, 0, 0, RM(rm
));
713 return m_buffer
.label();
716 static ARMWord
lsl(int reg
, ARMWord value
)
718 ASSERT(reg
<= ARMRegisters::pc
);
719 ASSERT(value
<= 0x1f);
720 return reg
| (value
<< 7) | 0x00;
723 static ARMWord
lsr(int reg
, ARMWord value
)
725 ASSERT(reg
<= ARMRegisters::pc
);
726 ASSERT(value
<= 0x1f);
727 return reg
| (value
<< 7) | 0x20;
730 static ARMWord
asr(int reg
, ARMWord value
)
732 ASSERT(reg
<= ARMRegisters::pc
);
733 ASSERT(value
<= 0x1f);
734 return reg
| (value
<< 7) | 0x40;
737 static ARMWord
lslRegister(int reg
, int shiftReg
)
739 ASSERT(reg
<= ARMRegisters::pc
);
740 ASSERT(shiftReg
<= ARMRegisters::pc
);
741 return reg
| (shiftReg
<< 8) | 0x10;
744 static ARMWord
lsrRegister(int reg
, int shiftReg
)
746 ASSERT(reg
<= ARMRegisters::pc
);
747 ASSERT(shiftReg
<= ARMRegisters::pc
);
748 return reg
| (shiftReg
<< 8) | 0x30;
751 static ARMWord
asrRegister(int reg
, int shiftReg
)
753 ASSERT(reg
<= ARMRegisters::pc
);
754 ASSERT(shiftReg
<= ARMRegisters::pc
);
755 return reg
| (shiftReg
<< 8) | 0x50;
760 size_t codeSize() const
762 return m_buffer
.codeSize();
765 void ensureSpace(int insnSpace
, int constSpace
)
767 m_buffer
.ensureSpace(insnSpace
, constSpace
);
770 int sizeOfConstantPool()
772 return m_buffer
.sizeOfConstantPool();
775 AssemblerLabel
labelIgnoringWatchpoints()
777 m_buffer
.ensureSpaceForAnyInstruction();
778 return m_buffer
.label();
781 AssemblerLabel
labelForWatchpoint()
783 m_buffer
.ensureSpaceForAnyInstruction(maxJumpReplacementSize() / sizeof(ARMWord
));
784 AssemblerLabel result
= m_buffer
.label();
785 if (result
.m_offset
!= (m_indexOfTailOfLastWatchpoint
- maxJumpReplacementSize()))
787 m_indexOfTailOfLastWatchpoint
= result
.m_offset
+ maxJumpReplacementSize();
791 AssemblerLabel
label()
793 AssemblerLabel result
= labelIgnoringWatchpoints();
794 while (result
.m_offset
+ 1 < m_indexOfTailOfLastWatchpoint
) {
796 // The available number of instructions are ensured by labelForWatchpoint.
797 result
= m_buffer
.label();
802 AssemblerLabel
align(int alignment
)
804 while (!m_buffer
.isAligned(alignment
))
805 mov(ARMRegisters::r0
, ARMRegisters::r0
);
810 AssemblerLabel
loadBranchTarget(int rd
, Condition cc
= AL
, int useConstantPool
= 0)
812 ensureSpace(sizeof(ARMWord
), sizeof(ARMWord
));
813 m_jumps
.append(m_buffer
.codeSize() | (useConstantPool
& 0x1));
814 ldrUniqueImmediate(rd
, InvalidBranchTarget
, cc
);
815 return m_buffer
.label();
818 AssemblerLabel
jmp(Condition cc
= AL
, int useConstantPool
= 0)
820 return loadBranchTarget(ARMRegisters::pc
, cc
, useConstantPool
);
823 void prepareExecutableCopy(void* to
);
825 unsigned debugOffset() { return m_buffer
.debugOffset(); }
827 // DFG assembly helpers for moving data between fp and registers.
828 void vmov(RegisterID rd1
, RegisterID rd2
, FPRegisterID rn
)
830 vmov_arm64(rd1
, rd2
, rn
);
833 void vmov(FPRegisterID rd
, RegisterID rn1
, RegisterID rn2
)
835 vmov_vfp64(rd
, rn1
, rn2
);
840 static ARMWord
* getLdrImmAddress(ARMWord
* insn
)
843 if ((*insn
& LdrPcImmediateInstructionMask
) != LdrPcImmediateInstruction
) {
845 ASSERT((*insn
& BlxInstructionMask
) == BlxInstruction
);
849 // Must be an ldr ..., [pc +/- imm]
850 ASSERT((*insn
& LdrPcImmediateInstructionMask
) == LdrPcImmediateInstruction
);
852 ARMWord addr
= reinterpret_cast<ARMWord
>(insn
) + DefaultPrefetchOffset
* sizeof(ARMWord
);
853 if (*insn
& DataTransferUp
)
854 return reinterpret_cast<ARMWord
*>(addr
+ (*insn
& DataTransferOffsetMask
));
855 return reinterpret_cast<ARMWord
*>(addr
- (*insn
& DataTransferOffsetMask
));
858 static ARMWord
* getLdrImmAddressOnPool(ARMWord
* insn
, uint32_t* constPool
)
860 // Must be an ldr ..., [pc +/- imm]
861 ASSERT((*insn
& LdrPcImmediateInstructionMask
) == LdrPcImmediateInstruction
);
864 return reinterpret_cast<ARMWord
*>(constPool
+ ((*insn
& DataTransferOffsetMask
) >> 1));
865 return getLdrImmAddress(insn
);
868 static void patchPointerInternal(intptr_t from
, void* to
)
870 ARMWord
* insn
= reinterpret_cast<ARMWord
*>(from
);
871 ARMWord
* addr
= getLdrImmAddress(insn
);
872 *addr
= reinterpret_cast<ARMWord
>(to
);
875 static ARMWord
patchConstantPoolLoad(ARMWord load
, ARMWord value
)
877 value
= (value
<< 1) + 1;
878 ASSERT(!(value
& ~DataTransferOffsetMask
));
879 return (load
& ~DataTransferOffsetMask
) | value
;
882 static void patchConstantPoolLoad(void* loadAddr
, void* constPoolAddr
);
885 static void* readPointer(void* from
)
887 ARMWord
* instruction
= reinterpret_cast<ARMWord
*>(from
);
888 ARMWord
* address
= getLdrImmAddress(instruction
);
889 return *reinterpret_cast<void**>(address
);
894 static void linkPointer(void* code
, AssemblerLabel from
, void* to
)
896 patchPointerInternal(reinterpret_cast<intptr_t>(code
) + from
.m_offset
, to
);
899 static void repatchInt32(void* where
, int32_t to
)
901 patchPointerInternal(reinterpret_cast<intptr_t>(where
), reinterpret_cast<void*>(to
));
904 static void repatchCompact(void* where
, int32_t value
)
906 ARMWord
* instruction
= reinterpret_cast<ARMWord
*>(where
);
907 ASSERT((*instruction
& 0x0f700000) == LoadUint32
);
909 *instruction
= (*instruction
& 0xff7ff000) | DataTransferUp
| value
;
911 *instruction
= (*instruction
& 0xff7ff000) | -value
;
912 cacheFlush(instruction
, sizeof(ARMWord
));
915 static void repatchPointer(void* from
, void* to
)
917 patchPointerInternal(reinterpret_cast<intptr_t>(from
), to
);
921 static intptr_t getAbsoluteJumpAddress(void* base
, int offset
= 0)
923 return reinterpret_cast<intptr_t>(base
) + offset
- sizeof(ARMWord
);
926 void linkJump(AssemblerLabel from
, AssemblerLabel to
)
928 ARMWord
* insn
= reinterpret_cast<ARMWord
*>(getAbsoluteJumpAddress(m_buffer
.data(), from
.m_offset
));
929 ARMWord
* addr
= getLdrImmAddressOnPool(insn
, m_buffer
.poolAddress());
930 *addr
= toARMWord(to
.m_offset
);
933 static void linkJump(void* code
, AssemblerLabel from
, void* to
)
935 patchPointerInternal(getAbsoluteJumpAddress(code
, from
.m_offset
), to
);
938 static void relinkJump(void* from
, void* to
)
940 patchPointerInternal(getAbsoluteJumpAddress(from
), to
);
943 static void linkCall(void* code
, AssemblerLabel from
, void* to
)
945 patchPointerInternal(getAbsoluteJumpAddress(code
, from
.m_offset
), to
);
948 static void relinkCall(void* from
, void* to
)
950 patchPointerInternal(getAbsoluteJumpAddress(from
), to
);
953 static void* readCallTarget(void* from
)
955 return reinterpret_cast<void*>(readPointer(reinterpret_cast<void*>(getAbsoluteJumpAddress(from
))));
958 static void replaceWithJump(void* instructionStart
, void* to
)
960 ARMWord
* instruction
= reinterpret_cast<ARMWord
*>(instructionStart
);
961 intptr_t difference
= reinterpret_cast<intptr_t>(to
) - (reinterpret_cast<intptr_t>(instruction
) + DefaultPrefetchOffset
* sizeof(ARMWord
));
963 if (!(difference
& 1)) {
965 if ((difference
<= MaximumBranchOffsetDistance
&& difference
>= MinimumBranchOffsetDistance
)) {
967 instruction
[0] = B
| AL
| (difference
& BranchOffsetMask
);
968 cacheFlush(instruction
, sizeof(ARMWord
));
974 instruction
[0] = LoadUint32
| AL
| RN(ARMRegisters::pc
) | RD(ARMRegisters::pc
) | 4;
975 instruction
[1] = reinterpret_cast<ARMWord
>(to
);
976 cacheFlush(instruction
, sizeof(ARMWord
) * 2);
979 static ptrdiff_t maxJumpReplacementSize()
981 return sizeof(ARMWord
) * 2;
984 static void replaceWithLoad(void* instructionStart
)
986 ARMWord
* instruction
= reinterpret_cast<ARMWord
*>(instructionStart
);
987 cacheFlush(instruction
, sizeof(ARMWord
));
989 ASSERT((*instruction
& LdrOrAddInstructionMask
) == AddImmediateInstruction
|| (*instruction
& LdrOrAddInstructionMask
) == LdrImmediateInstruction
);
990 if ((*instruction
& LdrOrAddInstructionMask
) == AddImmediateInstruction
) {
991 *instruction
= (*instruction
& ~LdrOrAddInstructionMask
) | LdrImmediateInstruction
;
992 cacheFlush(instruction
, sizeof(ARMWord
));
996 static void replaceWithAddressComputation(void* instructionStart
)
998 ARMWord
* instruction
= reinterpret_cast<ARMWord
*>(instructionStart
);
999 cacheFlush(instruction
, sizeof(ARMWord
));
1001 ASSERT((*instruction
& LdrOrAddInstructionMask
) == AddImmediateInstruction
|| (*instruction
& LdrOrAddInstructionMask
) == LdrImmediateInstruction
);
1002 if ((*instruction
& LdrOrAddInstructionMask
) == LdrImmediateInstruction
) {
1003 *instruction
= (*instruction
& ~LdrOrAddInstructionMask
) | AddImmediateInstruction
;
1004 cacheFlush(instruction
, sizeof(ARMWord
));
1008 static void revertBranchPtrWithPatch(void* instructionStart
, RegisterID rn
, ARMWord imm
)
1010 ARMWord
* instruction
= reinterpret_cast<ARMWord
*>(instructionStart
);
1012 ASSERT((instruction
[2] & LdrPcImmediateInstructionMask
) == LdrPcImmediateInstruction
);
1013 instruction
[0] = toARMWord(AL
) | ((instruction
[2] & 0x0fff0fff) + sizeof(ARMWord
)) | RD(ARMRegisters::S1
);
1014 *getLdrImmAddress(instruction
) = imm
;
1015 instruction
[1] = toARMWord(AL
) | CMP
| SetConditionalCodes
| RN(rn
) | RM(ARMRegisters::S1
);
1016 cacheFlush(instruction
, 2 * sizeof(ARMWord
));
1019 // Address operations
1021 static void* getRelocatedAddress(void* code
, AssemblerLabel label
)
1023 return reinterpret_cast<void*>(reinterpret_cast<char*>(code
) + label
.m_offset
);
1026 // Address differences
1028 static int getDifferenceBetweenLabels(AssemblerLabel a
, AssemblerLabel b
)
1030 return b
.m_offset
- a
.m_offset
;
1033 static unsigned getCallReturnOffset(AssemblerLabel call
)
1035 return call
.m_offset
;
1038 // Handle immediates
1040 static ARMWord
getOp2(ARMWord imm
);
1042 // Fast case if imm is known to be between 0 and 0xff
1043 static ARMWord
getOp2Byte(ARMWord imm
)
1045 ASSERT(imm
<= 0xff);
1046 return Op2Immediate
| imm
;
1049 static ARMWord
getOp2Half(ARMWord imm
)
1051 ASSERT(imm
<= 0xff);
1052 return ImmediateForHalfWordTransfer
| (imm
& 0x0f) | ((imm
& 0xf0) << 4);
1055 #if WTF_ARM_ARCH_AT_LEAST(7)
1056 static ARMWord
getImm16Op2(ARMWord imm
)
1059 return (imm
& 0xf000) << 4 | (imm
& 0xfff);
1060 return InvalidImmediate
;
1063 ARMWord
getImm(ARMWord imm
, int tmpReg
, bool invert
= false);
1064 void moveImm(ARMWord imm
, int dest
);
1065 ARMWord
encodeComplexImm(ARMWord imm
, int dest
);
1067 // Memory load/store helpers
1069 void dataTransfer32(DataTransferTypeA
, RegisterID srcDst
, RegisterID base
, int32_t offset
);
1070 void baseIndexTransfer32(DataTransferTypeA
, RegisterID srcDst
, RegisterID base
, RegisterID index
, int scale
, int32_t offset
);
1071 void dataTransfer16(DataTransferTypeB
, RegisterID srcDst
, RegisterID base
, int32_t offset
);
1072 void baseIndexTransfer16(DataTransferTypeB
, RegisterID srcDst
, RegisterID base
, RegisterID index
, int scale
, int32_t offset
);
1073 void dataTransferFloat(DataTransferTypeFloat
, FPRegisterID srcDst
, RegisterID base
, int32_t offset
);
1074 void baseIndexTransferFloat(DataTransferTypeFloat
, FPRegisterID srcDst
, RegisterID base
, RegisterID index
, int scale
, int32_t offset
);
1076 // Constant pool hnadlers
1078 static ARMWord
placeConstantPoolBarrier(int offset
)
1080 offset
= (offset
- sizeof(ARMWord
)) >> 2;
1081 ASSERT((offset
<= MaximumBranchOffsetDistance
&& offset
>= MinimumBranchOffsetDistance
));
1082 return AL
| B
| (offset
& BranchOffsetMask
);
1085 #if OS(LINUX) && COMPILER(GCC)
1086 static inline void linuxPageFlush(uintptr_t begin
, uintptr_t end
)
1092 "mov r7, #0xf0000\n"
1093 "add r7, r7, #0x2\n"
1098 : "r" (begin
), "r" (end
)
1099 : "r0", "r1", "r2");
1103 static void cacheFlush(void* code
, size_t size
)
1105 #if OS(LINUX) && COMPILER(GCC)
1106 size_t page
= pageSize();
1107 uintptr_t current
= reinterpret_cast<uintptr_t>(code
);
1108 uintptr_t end
= current
+ size
;
1109 uintptr_t firstPageEnd
= (current
& ~(page
- 1)) + page
;
1111 if (end
<= firstPageEnd
) {
1112 linuxPageFlush(current
, end
);
1116 linuxPageFlush(current
, firstPageEnd
);
1118 for (current
= firstPageEnd
; current
+ page
< end
; current
+= page
)
1119 linuxPageFlush(current
, current
+ page
);
1121 linuxPageFlush(current
, end
);
1123 CacheRangeFlush(code
, size
, CACHE_SYNC_ALL
);
1125 #error "The cacheFlush support is missing on this platform."
1130 static ARMWord
RM(int reg
)
1132 ASSERT(reg
<= ARMRegisters::pc
);
1136 static ARMWord
RS(int reg
)
1138 ASSERT(reg
<= ARMRegisters::pc
);
1142 static ARMWord
RD(int reg
)
1144 ASSERT(reg
<= ARMRegisters::pc
);
1148 static ARMWord
RN(int reg
)
1150 ASSERT(reg
<= ARMRegisters::pc
);
1154 static ARMWord
getConditionalField(ARMWord i
)
1156 return i
& ConditionalFieldMask
;
1159 static ARMWord
toARMWord(Condition cc
)
1161 return static_cast<ARMWord
>(cc
);
1164 static ARMWord
toARMWord(uint32_t u
)
1166 return static_cast<ARMWord
>(u
);
1169 int genInt(int reg
, ARMWord imm
, bool positive
);
1173 uint32_t m_indexOfTailOfLastWatchpoint
;
1178 #endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
1180 #endif // ARMAssembler_h