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