1/*
2 * Copyright (C) 2009, 2010 University of Szeged
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY 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.
25 */
26
27#ifndef ARMAssembler_h
28#define ARMAssembler_h
29
30#if ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
31
32#include "AssemblerBufferWithConstantPool.h"
33#include "JITCompilationEffort.h"
34#include <wtf/Assertions.h>
35namespace JSC {
36
37    typedef uint32_t ARMWord;
38
39    namespace ARMRegisters {
40        typedef enum {
41            r0 = 0,
42            r1,
43            r2,
44            r3,
45            r4,
46            r5,
47            r6, S0 = r6,
48            r7,
49            r8,
50            r9,
51            r10,
52            r11, fp = r11, // frame pointer
53            r12, ip = r12, S1 = r12,
54            r13, sp = r13,
55            r14, lr = r14,
56            r15, pc = r15
57        } RegisterID;
58
59        typedef enum {
60            d0,
61            d1,
62            d2,
63            d3,
64            d4,
65            d5,
66            d6,
67            d7, SD0 = d7, /* Same as thumb assembler. */
68            d8,
69            d9,
70            d10,
71            d11,
72            d12,
73            d13,
74            d14,
75            d15,
76            d16,
77            d17,
78            d18,
79            d19,
80            d20,
81            d21,
82            d22,
83            d23,
84            d24,
85            d25,
86            d26,
87            d27,
88            d28,
89            d29,
90            d30,
91            d31
92        } FPRegisterID;
93
94#if USE(MASM_PROBE)
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)
99
100    #define FOR_EACH_CPU_GPREGISTER(V) \
101        V(void*, r0) \
102        V(void*, r1) \
103        V(void*, r2) \
104        V(void*, r3) \
105        V(void*, r4) \
106        V(void*, r5) \
107        V(void*, r6) \
108        V(void*, r7) \
109        V(void*, r8) \
110        V(void*, r9) \
111        V(void*, r10) \
112        V(void*, r11) \
113        V(void*, ip) \
114        V(void*, sp) \
115        V(void*, lr) \
116        V(void*, pc)
117
118    #define FOR_EACH_CPU_SPECIAL_REGISTER(V) \
119        V(void*, apsr) \
120        V(void*, fpscr) \
121
122    #define FOR_EACH_CPU_FPREGISTER(V) \
123        V(double, d0) \
124        V(double, d1) \
125        V(double, d2) \
126        V(double, d3) \
127        V(double, d4) \
128        V(double, d5) \
129        V(double, d6) \
130        V(double, d7) \
131        V(double, d8) \
132        V(double, d9) \
133        V(double, d10) \
134        V(double, d11) \
135        V(double, d12) \
136        V(double, d13) \
137        V(double, d14) \
138        V(double, d15)
139#endif // USE(MASM_PROBE)
140    } // namespace ARMRegisters
141
142    class ARMAssembler {
143    public:
144        typedef ARMRegisters::RegisterID RegisterID;
145        typedef ARMRegisters::FPRegisterID FPRegisterID;
146        typedef AssemblerBufferWithConstantPool<2048, 4, 4, ARMAssembler> ARMBuffer;
147        typedef SegmentedVector<AssemblerLabel, 64> Jumps;
148
149        ARMAssembler()
150            : m_indexOfTailOfLastWatchpoint(1)
151        {
152        }
153
154        ARMBuffer& buffer() { return m_buffer; }
155
156        static RegisterID firstRegister() { return ARMRegisters::r0; }
157        static RegisterID lastRegister() { return ARMRegisters::r15; }
158
159        static FPRegisterID firstFPRegister() { return ARMRegisters::d0; }
160        static FPRegisterID lastFPRegister() { return ARMRegisters::d31; }
161
162        // ARM conditional constants
163        typedef enum {
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.
179        } Condition;
180
181        // ARM instruction constants
182        enum {
183            AND = (0x0 << 21),
184            EOR = (0x1 << 21),
185            SUB = (0x2 << 21),
186            RSB = (0x3 << 21),
187            ADD = (0x4 << 21),
188            ADC = (0x5 << 21),
189            SBC = (0x6 << 21),
190            RSC = (0x7 << 21),
191            TST = (0x8 << 21),
192            TEQ = (0x9 << 21),
193            CMP = (0xa << 21),
194            CMN = (0xb << 21),
195            ORR = (0xc << 21),
196            MOV = (0xd << 21),
197            BIC = (0xe << 21),
198            MVN = (0xf << 21),
199            MUL = 0x00000090,
200            MULL = 0x00c00090,
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,
210            STMDB = 0x09200000,
211            LDMIA = 0x08b00000,
212            B = 0x0a000000,
213            BL = 0x0b000000,
214            BX = 0x012fff10,
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,
225            CLZ = 0x016f0f10,
226            BKPT = 0xe1200070,
227            BLX = 0x012fff30,
228#if WTF_ARM_ARCH_AT_LEAST(7)
229            MOVW = 0x03000000,
230            MOVT = 0x03400000,
231#endif
232            NOP = 0xe1a00000,
233            DMB_SY = 0xf57ff05f,
234        };
235
236        enum {
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),
248        };
249
250        enum DataTransferTypeA {
251            LoadUint32 = 0x05000000 | DataTransferLoad,
252            LoadUint8 = 0x05400000 | DataTransferLoad,
253            StoreUint32 = 0x05000000,
254            StoreUint8 = 0x05400000,
255        };
256
257        enum DataTransferTypeB {
258            LoadUint16 = 0x010000b0 | DataTransferLoad,
259            LoadInt16 = 0x010000f0 | DataTransferLoad,
260            LoadInt8 = 0x010000d0 | DataTransferLoad,
261            StoreUint16 = 0x010000b0,
262        };
263
264        enum DataTransferTypeFloat {
265            LoadFloat = 0x0d000a00 | DataTransferLoad,
266            LoadDouble = 0x0d000b00 | DataTransferLoad,
267            StoreFloat = 0x0d000a00,
268            StoreDouble = 0x0d000b00,
269        };
270
271        // Masks of ARM instructions
272        enum {
273            BranchOffsetMask = 0x00ffffff,
274            ConditionalFieldMask = 0xf0000000,
275            DataTransferOffsetMask = 0xfff,
276        };
277
278        enum {
279            MinimumBranchOffsetDistance = -0x00800000,
280            MaximumBranchOffsetDistance = 0x007fffff,
281        };
282
283        enum {
284            padForAlign8  = 0x00,
285            padForAlign16 = 0x0000,
286            padForAlign32 = 0xe12fff7f // 'bkpt 0xffff' instruction.
287        };
288
289        static const ARMWord InvalidImmediate = 0xf0000000;
290        static const ARMWord InvalidBranchTarget = 0xffffffff;
291        static const int DefaultPrefetchOffset = 2;
292
293        static const ARMWord BlxInstructionMask = 0x012fff30;
294        static const ARMWord LdrOrAddInstructionMask = 0x0ff00000;
295        static const ARMWord LdrPcImmediateInstructionMask = 0x0f7f0000;
296
297        static const ARMWord AddImmediateInstruction = 0x02800000;
298        static const ARMWord BlxInstruction = 0x012fff30;
299        static const ARMWord LdrImmediateInstruction = 0x05900000;
300        static const ARMWord LdrPcImmediateInstruction = 0x051f0000;
301
302        // Instruction formating
303
304        void emitInstruction(ARMWord op, int rd, int rn, ARMWord op2)
305        {
306            ASSERT(((op2 & ~Op2Immediate) <= 0xfff) || (((op2 & ~ImmediateForHalfWordTransfer) <= 0xfff)));
307            m_buffer.putInt(op | RN(rn) | RD(rd) | op2);
308        }
309
310        void emitDoublePrecisionInstruction(ARMWord op, int dd, int dn, int dm)
311        {
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)));
316        }
317
318        void emitSinglePrecisionInstruction(ARMWord op, int sd, int sn, int sm)
319        {
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));
324        }
325
326        void bitAnd(int rd, int rn, ARMWord op2, Condition cc = AL)
327        {
328            emitInstruction(toARMWord(cc) | AND, rd, rn, op2);
329        }
330
331        void bitAnds(int rd, int rn, ARMWord op2, Condition cc = AL)
332        {
333            emitInstruction(toARMWord(cc) | AND | SetConditionalCodes, rd, rn, op2);
334        }
335
336        void eor(int rd, int rn, ARMWord op2, Condition cc = AL)
337        {
338            emitInstruction(toARMWord(cc) | EOR, rd, rn, op2);
339        }
340
341        void eors(int rd, int rn, ARMWord op2, Condition cc = AL)
342        {
343            emitInstruction(toARMWord(cc) | EOR | SetConditionalCodes, rd, rn, op2);
344        }
345
346        void sub(int rd, int rn, ARMWord op2, Condition cc = AL)
347        {
348            emitInstruction(toARMWord(cc) | SUB, rd, rn, op2);
349        }
350
351        void subs(int rd, int rn, ARMWord op2, Condition cc = AL)
352        {
353            emitInstruction(toARMWord(cc) | SUB | SetConditionalCodes, rd, rn, op2);
354        }
355
356        void rsb(int rd, int rn, ARMWord op2, Condition cc = AL)
357        {
358            emitInstruction(toARMWord(cc) | RSB, rd, rn, op2);
359        }
360
361        void rsbs(int rd, int rn, ARMWord op2, Condition cc = AL)
362        {
363            emitInstruction(toARMWord(cc) | RSB | SetConditionalCodes, rd, rn, op2);
364        }
365
366        void add(int rd, int rn, ARMWord op2, Condition cc = AL)
367        {
368            emitInstruction(toARMWord(cc) | ADD, rd, rn, op2);
369        }
370
371        void adds(int rd, int rn, ARMWord op2, Condition cc = AL)
372        {
373            emitInstruction(toARMWord(cc) | ADD | SetConditionalCodes, rd, rn, op2);
374        }
375
376        void adc(int rd, int rn, ARMWord op2, Condition cc = AL)
377        {
378            emitInstruction(toARMWord(cc) | ADC, rd, rn, op2);
379        }
380
381        void adcs(int rd, int rn, ARMWord op2, Condition cc = AL)
382        {
383            emitInstruction(toARMWord(cc) | ADC | SetConditionalCodes, rd, rn, op2);
384        }
385
386        void sbc(int rd, int rn, ARMWord op2, Condition cc = AL)
387        {
388            emitInstruction(toARMWord(cc) | SBC, rd, rn, op2);
389        }
390
391        void sbcs(int rd, int rn, ARMWord op2, Condition cc = AL)
392        {
393            emitInstruction(toARMWord(cc) | SBC | SetConditionalCodes, rd, rn, op2);
394        }
395
396        void rsc(int rd, int rn, ARMWord op2, Condition cc = AL)
397        {
398            emitInstruction(toARMWord(cc) | RSC, rd, rn, op2);
399        }
400
401        void rscs(int rd, int rn, ARMWord op2, Condition cc = AL)
402        {
403            emitInstruction(toARMWord(cc) | RSC | SetConditionalCodes, rd, rn, op2);
404        }
405
406        void tst(int rn, ARMWord op2, Condition cc = AL)
407        {
408            emitInstruction(toARMWord(cc) | TST | SetConditionalCodes, 0, rn, op2);
409        }
410
411        void teq(int rn, ARMWord op2, Condition cc = AL)
412        {
413            emitInstruction(toARMWord(cc) | TEQ | SetConditionalCodes, 0, rn, op2);
414        }
415
416        void cmp(int rn, ARMWord op2, Condition cc = AL)
417        {
418            emitInstruction(toARMWord(cc) | CMP | SetConditionalCodes, 0, rn, op2);
419        }
420
421        void cmn(int rn, ARMWord op2, Condition cc = AL)
422        {
423            emitInstruction(toARMWord(cc) | CMN | SetConditionalCodes, 0, rn, op2);
424        }
425
426        void orr(int rd, int rn, ARMWord op2, Condition cc = AL)
427        {
428            emitInstruction(toARMWord(cc) | ORR, rd, rn, op2);
429        }
430
431        void orrs(int rd, int rn, ARMWord op2, Condition cc = AL)
432        {
433            emitInstruction(toARMWord(cc) | ORR | SetConditionalCodes, rd, rn, op2);
434        }
435
436        void mov(int rd, ARMWord op2, Condition cc = AL)
437        {
438            emitInstruction(toARMWord(cc) | MOV, rd, ARMRegisters::r0, op2);
439        }
440
441#if WTF_ARM_ARCH_AT_LEAST(7)
442        void movw(int rd, ARMWord op2, Condition cc = AL)
443        {
444            ASSERT((op2 | 0xf0fff) == 0xf0fff);
445            m_buffer.putInt(toARMWord(cc) | MOVW | RD(rd) | op2);
446        }
447
448        void movt(int rd, ARMWord op2, Condition cc = AL)
449        {
450            ASSERT((op2 | 0xf0fff) == 0xf0fff);
451            m_buffer.putInt(toARMWord(cc) | MOVT | RD(rd) | op2);
452        }
453#endif
454
455        void movs(int rd, ARMWord op2, Condition cc = AL)
456        {
457            emitInstruction(toARMWord(cc) | MOV | SetConditionalCodes, rd, ARMRegisters::r0, op2);
458        }
459
460        void bic(int rd, int rn, ARMWord op2, Condition cc = AL)
461        {
462            emitInstruction(toARMWord(cc) | BIC, rd, rn, op2);
463        }
464
465        void bics(int rd, int rn, ARMWord op2, Condition cc = AL)
466        {
467            emitInstruction(toARMWord(cc) | BIC | SetConditionalCodes, rd, rn, op2);
468        }
469
470        void mvn(int rd, ARMWord op2, Condition cc = AL)
471        {
472            emitInstruction(toARMWord(cc) | MVN, rd, ARMRegisters::r0, op2);
473        }
474
475        void mvns(int rd, ARMWord op2, Condition cc = AL)
476        {
477            emitInstruction(toARMWord(cc) | MVN | SetConditionalCodes, rd, ARMRegisters::r0, op2);
478        }
479
480        void mul(int rd, int rn, int rm, Condition cc = AL)
481        {
482            m_buffer.putInt(toARMWord(cc) | MUL | RN(rd) | RS(rn) | RM(rm));
483        }
484
485        void muls(int rd, int rn, int rm, Condition cc = AL)
486        {
487            m_buffer.putInt(toARMWord(cc) | MUL | SetConditionalCodes | RN(rd) | RS(rn) | RM(rm));
488        }
489
490        void mull(int rdhi, int rdlo, int rn, int rm, Condition cc = AL)
491        {
492            m_buffer.putInt(toARMWord(cc) | MULL | RN(rdhi) | RD(rdlo) | RS(rn) | RM(rm));
493        }
494
495        void vmov_f64(int dd, int dm, Condition cc = AL)
496        {
497            emitDoublePrecisionInstruction(toARMWord(cc) | VMOV_F64, dd, 0, dm);
498        }
499
500        void vadd_f64(int dd, int dn, int dm, Condition cc = AL)
501        {
502            emitDoublePrecisionInstruction(toARMWord(cc) | VADD_F64, dd, dn, dm);
503        }
504
505        void vdiv_f64(int dd, int dn, int dm, Condition cc = AL)
506        {
507            emitDoublePrecisionInstruction(toARMWord(cc) | VDIV_F64, dd, dn, dm);
508        }
509
510        void vsub_f64(int dd, int dn, int dm, Condition cc = AL)
511        {
512            emitDoublePrecisionInstruction(toARMWord(cc) | VSUB_F64, dd, dn, dm);
513        }
514
515        void vmul_f64(int dd, int dn, int dm, Condition cc = AL)
516        {
517            emitDoublePrecisionInstruction(toARMWord(cc) | VMUL_F64, dd, dn, dm);
518        }
519
520        void vcmp_f64(int dd, int dm, Condition cc = AL)
521        {
522            emitDoublePrecisionInstruction(toARMWord(cc) | VCMP_F64, dd, 0, dm);
523        }
524
525        void vsqrt_f64(int dd, int dm, Condition cc = AL)
526        {
527            emitDoublePrecisionInstruction(toARMWord(cc) | VSQRT_F64, dd, 0, dm);
528        }
529
530        void vabs_f64(int dd, int dm, Condition cc = AL)
531        {
532            emitDoublePrecisionInstruction(toARMWord(cc) | VABS_F64, dd, 0, dm);
533        }
534
535        void vneg_f64(int dd, int dm, Condition cc = AL)
536        {
537            emitDoublePrecisionInstruction(toARMWord(cc) | VNEG_F64, dd, 0, dm);
538        }
539
540        void ldrImmediate(int rd, ARMWord imm, Condition cc = AL)
541        {
542            m_buffer.putIntWithConstantInt(toARMWord(cc) | LoadUint32 | DataTransferUp | RN(ARMRegisters::pc) | RD(rd), imm, true);
543        }
544
545        void ldrUniqueImmediate(int rd, ARMWord imm, Condition cc = AL)
546        {
547            m_buffer.putIntWithConstantInt(toARMWord(cc) | LoadUint32 | DataTransferUp | RN(ARMRegisters::pc) | RD(rd), imm);
548        }
549
550        void dtrUp(DataTransferTypeA transferType, int rd, int rb, ARMWord op2, Condition cc = AL)
551        {
552            emitInstruction(toARMWord(cc) | transferType | DataTransferUp, rd, rb, op2);
553        }
554
555        void dtrUpRegister(DataTransferTypeA transferType, int rd, int rb, int rm, Condition cc = AL)
556        {
557            emitInstruction(toARMWord(cc) | transferType | DataTransferUp | Op2IsRegisterArgument, rd, rb, rm);
558        }
559
560        void dtrDown(DataTransferTypeA transferType, int rd, int rb, ARMWord op2, Condition cc = AL)
561        {
562            emitInstruction(toARMWord(cc) | transferType, rd, rb, op2);
563        }
564
565        void dtrDownRegister(DataTransferTypeA transferType, int rd, int rb, int rm, Condition cc = AL)
566        {
567            emitInstruction(toARMWord(cc) | transferType | Op2IsRegisterArgument, rd, rb, rm);
568        }
569
570        void halfDtrUp(DataTransferTypeB transferType, int rd, int rb, ARMWord op2, Condition cc = AL)
571        {
572            emitInstruction(toARMWord(cc) | transferType | DataTransferUp, rd, rb, op2);
573        }
574
575        void halfDtrUpRegister(DataTransferTypeB transferType, int rd, int rn, int rm, Condition cc = AL)
576        {
577            emitInstruction(toARMWord(cc) | transferType | DataTransferUp, rd, rn, rm);
578        }
579
580        void halfDtrDown(DataTransferTypeB transferType, int rd, int rb, ARMWord op2, Condition cc = AL)
581        {
582            emitInstruction(toARMWord(cc) | transferType, rd, rb, op2);
583        }
584
585        void halfDtrDownRegister(DataTransferTypeB transferType, int rd, int rn, int rm, Condition cc = AL)
586        {
587            emitInstruction(toARMWord(cc) | transferType, rd, rn, rm);
588        }
589
590        void doubleDtrUp(DataTransferTypeFloat type, int rd, int rb, ARMWord op2, Condition cc = AL)
591        {
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);
595        }
596
597        void doubleDtrDown(DataTransferTypeFloat type, int rd, int rb, ARMWord op2, Condition cc = AL)
598        {
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);
602        }
603
604        void push(int reg, Condition cc = AL)
605        {
606            ASSERT(ARMWord(reg) <= 0xf);
607            m_buffer.putInt(toARMWord(cc) | StoreUint32 | DataTransferWriteBack | RN(ARMRegisters::sp) | RD(reg) | 0x4);
608        }
609
610        void pop(int reg, Condition cc = AL)
611        {
612            ASSERT(ARMWord(reg) <= 0xf);
613            m_buffer.putInt(toARMWord(cc) | (LoadUint32 ^ DataTransferPostUpdate) | DataTransferUp | RN(ARMRegisters::sp) | RD(reg) | 0x4);
614        }
615
616        inline void poke(int reg, Condition cc = AL)
617        {
618            dtrDown(StoreUint32, ARMRegisters::sp, 0, reg, cc);
619        }
620
621        inline void peek(int reg, Condition cc = AL)
622        {
623            dtrUp(LoadUint32, reg, ARMRegisters::sp, 0, cc);
624        }
625
626        void vmov_vfp64(int sm, int rt, int rt2, Condition cc = AL)
627        {
628            ASSERT(rt != rt2);
629            m_buffer.putInt(toARMWord(cc) | VMOV_VFP64 | RN(rt2) | RD(rt) | (sm & 0xf) | ((sm & 0x10) << (5 - 4)));
630        }
631
632        void vmov_arm64(int rt, int rt2, int sm, Condition cc = AL)
633        {
634            ASSERT(rt != rt2);
635            m_buffer.putInt(toARMWord(cc) | VMOV_ARM64 | RN(rt2) | RD(rt) | (sm & 0xf) | ((sm & 0x10) << (5 - 4)));
636        }
637
638        void vmov_vfp32(int sn, int rt, Condition cc = AL)
639        {
640            ASSERT(rt <= 15);
641            emitSinglePrecisionInstruction(toARMWord(cc) | VMOV_VFP32, rt << 1, sn, 0);
642        }
643
644        void vmov_arm32(int rt, int sn, Condition cc = AL)
645        {
646            ASSERT(rt <= 15);
647            emitSinglePrecisionInstruction(toARMWord(cc) | VMOV_ARM32, rt << 1, sn, 0);
648        }
649
650        void vcvt_f64_s32(int dd, int sm, Condition cc = AL)
651        {
652            ASSERT(!(sm & 0x1)); // sm must be divisible by 2
653            emitDoublePrecisionInstruction(toARMWord(cc) | VCVT_F64_S32, dd, 0, (sm >> 1));
654        }
655
656        void vcvt_s32_f64(int sd, int dm, Condition cc = AL)
657        {
658            ASSERT(!(sd & 0x1)); // sd must be divisible by 2
659            emitDoublePrecisionInstruction(toARMWord(cc) | VCVT_S32_F64, (sd >> 1), 0, dm);
660        }
661
662        void vcvt_u32_f64(int sd, int dm, Condition cc = AL)
663        {
664            ASSERT(!(sd & 0x1)); // sd must be divisible by 2
665            emitDoublePrecisionInstruction(toARMWord(cc) | VCVT_U32_F64, (sd >> 1), 0, dm);
666        }
667
668        void vcvt_f64_f32(int dd, int sm, Condition cc = AL)
669        {
670            ASSERT(dd <= 15 && sm <= 15);
671            emitDoublePrecisionInstruction(toARMWord(cc) | VCVT_F64_F32, dd, 0, sm);
672        }
673
674        void vcvt_f32_f64(int dd, int sm, Condition cc = AL)
675        {
676            ASSERT(dd <= 15 && sm <= 15);
677            emitDoublePrecisionInstruction(toARMWord(cc) | VCVT_F32_F64, dd, 0, sm);
678        }
679
680        void vmrs_apsr(Condition cc = AL)
681        {
682            m_buffer.putInt(toARMWord(cc) | VMRS_APSR);
683        }
684
685        void clz(int rd, int rm, Condition cc = AL)
686        {
687            m_buffer.putInt(toARMWord(cc) | CLZ | RD(rd) | RM(rm));
688        }
689
690        void bkpt(ARMWord value)
691        {
692            m_buffer.putInt(BKPT | ((value & 0xff0) << 4) | (value & 0xf));
693        }
694
695        void nop()
696        {
697            m_buffer.putInt(NOP);
698        }
699
700        void dmbSY()
701        {
702            m_buffer.putInt(DMB_SY);
703        }
704
705        void bx(int rm, Condition cc = AL)
706        {
707            emitInstruction(toARMWord(cc) | BX, 0, 0, RM(rm));
708        }
709
710        AssemblerLabel blx(int rm, Condition cc = AL)
711        {
712            emitInstruction(toARMWord(cc) | BLX, 0, 0, RM(rm));
713            return m_buffer.label();
714        }
715
716        static ARMWord lsl(int reg, ARMWord value)
717        {
718            ASSERT(reg <= ARMRegisters::pc);
719            ASSERT(value <= 0x1f);
720            return reg | (value << 7) | 0x00;
721        }
722
723        static ARMWord lsr(int reg, ARMWord value)
724        {
725            ASSERT(reg <= ARMRegisters::pc);
726            ASSERT(value <= 0x1f);
727            return reg | (value << 7) | 0x20;
728        }
729
730        static ARMWord asr(int reg, ARMWord value)
731        {
732            ASSERT(reg <= ARMRegisters::pc);
733            ASSERT(value <= 0x1f);
734            return reg | (value << 7) | 0x40;
735        }
736
737        static ARMWord lslRegister(int reg, int shiftReg)
738        {
739            ASSERT(reg <= ARMRegisters::pc);
740            ASSERT(shiftReg <= ARMRegisters::pc);
741            return reg | (shiftReg << 8) | 0x10;
742        }
743
744        static ARMWord lsrRegister(int reg, int shiftReg)
745        {
746            ASSERT(reg <= ARMRegisters::pc);
747            ASSERT(shiftReg <= ARMRegisters::pc);
748            return reg | (shiftReg << 8) | 0x30;
749        }
750
751        static ARMWord asrRegister(int reg, int shiftReg)
752        {
753            ASSERT(reg <= ARMRegisters::pc);
754            ASSERT(shiftReg <= ARMRegisters::pc);
755            return reg | (shiftReg << 8) | 0x50;
756        }
757
758        // General helpers
759
760        size_t codeSize() const
761        {
762            return m_buffer.codeSize();
763        }
764
765        void ensureSpace(int insnSpace, int constSpace)
766        {
767            m_buffer.ensureSpace(insnSpace, constSpace);
768        }
769
770        int sizeOfConstantPool()
771        {
772            return m_buffer.sizeOfConstantPool();
773        }
774
775        AssemblerLabel labelIgnoringWatchpoints()
776        {
777            m_buffer.ensureSpaceForAnyInstruction();
778            return m_buffer.label();
779        }
780
781        AssemblerLabel labelForWatchpoint()
782        {
783            m_buffer.ensureSpaceForAnyInstruction(maxJumpReplacementSize() / sizeof(ARMWord));
784            AssemblerLabel result = m_buffer.label();
785            if (result.m_offset != (m_indexOfTailOfLastWatchpoint - maxJumpReplacementSize()))
786                result = label();
787            m_indexOfTailOfLastWatchpoint = result.m_offset + maxJumpReplacementSize();
788            return label();
789        }
790
791        AssemblerLabel label()
792        {
793            AssemblerLabel result = labelIgnoringWatchpoints();
794            while (result.m_offset + 1 < m_indexOfTailOfLastWatchpoint) {
795                nop();
796                // The available number of instructions are ensured by labelForWatchpoint.
797                result = m_buffer.label();
798            }
799            return result;
800        }
801
802        AssemblerLabel align(int alignment)
803        {
804            while (!m_buffer.isAligned(alignment))
805                mov(ARMRegisters::r0, ARMRegisters::r0);
806
807            return label();
808        }
809
810        AssemblerLabel loadBranchTarget(int rd, Condition cc = AL, int useConstantPool = 0)
811        {
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();
816        }
817
818        AssemblerLabel jmp(Condition cc = AL, int useConstantPool = 0)
819        {
820            return loadBranchTarget(ARMRegisters::pc, cc, useConstantPool);
821        }
822
823        void prepareExecutableCopy(void* to);
824
825        unsigned debugOffset() { return m_buffer.debugOffset(); }
826
827        // DFG assembly helpers for moving data between fp and registers.
828        void vmov(RegisterID rd1, RegisterID rd2, FPRegisterID rn)
829        {
830            vmov_arm64(rd1, rd2, rn);
831        }
832
833        void vmov(FPRegisterID rd, RegisterID rn1, RegisterID rn2)
834        {
835            vmov_vfp64(rd, rn1, rn2);
836        }
837
838        // Patching helpers
839
840        static ARMWord* getLdrImmAddress(ARMWord* insn)
841        {
842            // Check for call
843            if ((*insn & LdrPcImmediateInstructionMask) != LdrPcImmediateInstruction) {
844                // Must be BLX
845                ASSERT((*insn & BlxInstructionMask) == BlxInstruction);
846                insn--;
847            }
848
849            // Must be an ldr ..., [pc +/- imm]
850            ASSERT((*insn & LdrPcImmediateInstructionMask) == LdrPcImmediateInstruction);
851
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));
856        }
857
858        static ARMWord* getLdrImmAddressOnPool(ARMWord* insn, uint32_t* constPool)
859        {
860            // Must be an ldr ..., [pc +/- imm]
861            ASSERT((*insn & LdrPcImmediateInstructionMask) == LdrPcImmediateInstruction);
862
863            if (*insn & 0x1)
864                return reinterpret_cast<ARMWord*>(constPool + ((*insn & DataTransferOffsetMask) >> 1));
865            return getLdrImmAddress(insn);
866        }
867
868        static void patchPointerInternal(intptr_t from, void* to)
869        {
870            ARMWord* insn = reinterpret_cast<ARMWord*>(from);
871            ARMWord* addr = getLdrImmAddress(insn);
872            *addr = reinterpret_cast<ARMWord>(to);
873        }
874
875        static ARMWord patchConstantPoolLoad(ARMWord load, ARMWord value)
876        {
877            value = (value << 1) + 1;
878            ASSERT(!(value & ~DataTransferOffsetMask));
879            return (load & ~DataTransferOffsetMask) | value;
880        }
881
882        static void patchConstantPoolLoad(void* loadAddr, void* constPoolAddr);
883
884        // Read pointers
885        static void* readPointer(void* from)
886        {
887            ARMWord* instruction = reinterpret_cast<ARMWord*>(from);
888            ARMWord* address = getLdrImmAddress(instruction);
889            return *reinterpret_cast<void**>(address);
890        }
891
892        // Patch pointers
893
894        static void linkPointer(void* code, AssemblerLabel from, void* to)
895        {
896            patchPointerInternal(reinterpret_cast<intptr_t>(code) + from.m_offset, to);
897        }
898
899        static void repatchInt32(void* where, int32_t to)
900        {
901            patchPointerInternal(reinterpret_cast<intptr_t>(where), reinterpret_cast<void*>(to));
902        }
903
904        static void repatchCompact(void* where, int32_t value)
905        {
906            ARMWord* instruction = reinterpret_cast<ARMWord*>(where);
907            ASSERT((*instruction & 0x0f700000) == LoadUint32);
908            if (value >= 0)
909                *instruction = (*instruction & 0xff7ff000) | DataTransferUp | value;
910            else
911                *instruction = (*instruction & 0xff7ff000) | -value;
912            cacheFlush(instruction, sizeof(ARMWord));
913        }
914
915        static void repatchPointer(void* from, void* to)
916        {
917            patchPointerInternal(reinterpret_cast<intptr_t>(from), to);
918        }
919
920        // Linkers
921        static intptr_t getAbsoluteJumpAddress(void* base, int offset = 0)
922        {
923            return reinterpret_cast<intptr_t>(base) + offset - sizeof(ARMWord);
924        }
925
926        void linkJump(AssemblerLabel from, AssemblerLabel to)
927        {
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);
931        }
932
933        static void linkJump(void* code, AssemblerLabel from, void* to)
934        {
935            patchPointerInternal(getAbsoluteJumpAddress(code, from.m_offset), to);
936        }
937
938        static void relinkJump(void* from, void* to)
939        {
940            patchPointerInternal(getAbsoluteJumpAddress(from), to);
941        }
942
943        static void linkCall(void* code, AssemblerLabel from, void* to)
944        {
945            patchPointerInternal(getAbsoluteJumpAddress(code, from.m_offset), to);
946        }
947
948        static void relinkCall(void* from, void* to)
949        {
950            patchPointerInternal(getAbsoluteJumpAddress(from), to);
951        }
952
953        static void* readCallTarget(void* from)
954        {
955            return reinterpret_cast<void*>(readPointer(reinterpret_cast<void*>(getAbsoluteJumpAddress(from))));
956        }
957
958        static void replaceWithJump(void* instructionStart, void* to)
959        {
960            ARMWord* instruction = reinterpret_cast<ARMWord*>(instructionStart);
961            intptr_t difference = reinterpret_cast<intptr_t>(to) - (reinterpret_cast<intptr_t>(instruction) + DefaultPrefetchOffset * sizeof(ARMWord));
962
963            if (!(difference & 1)) {
964                difference >>= 2;
965                if ((difference <= MaximumBranchOffsetDistance && difference >= MinimumBranchOffsetDistance)) {
966                     // Direct branch.
967                     instruction[0] = B | AL | (difference & BranchOffsetMask);
968                     cacheFlush(instruction, sizeof(ARMWord));
969                     return;
970                }
971            }
972
973            // Load target.
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);
977        }
978
979        static ptrdiff_t maxJumpReplacementSize()
980        {
981            return sizeof(ARMWord) * 2;
982        }
983
984        static void replaceWithLoad(void* instructionStart)
985        {
986            ARMWord* instruction = reinterpret_cast<ARMWord*>(instructionStart);
987            cacheFlush(instruction, sizeof(ARMWord));
988
989            ASSERT((*instruction & LdrOrAddInstructionMask) == AddImmediateInstruction || (*instruction & LdrOrAddInstructionMask) == LdrImmediateInstruction);
990            if ((*instruction & LdrOrAddInstructionMask) == AddImmediateInstruction) {
991                 *instruction = (*instruction & ~LdrOrAddInstructionMask) | LdrImmediateInstruction;
992                 cacheFlush(instruction, sizeof(ARMWord));
993            }
994        }
995
996        static void replaceWithAddressComputation(void* instructionStart)
997        {
998            ARMWord* instruction = reinterpret_cast<ARMWord*>(instructionStart);
999            cacheFlush(instruction, sizeof(ARMWord));
1000
1001            ASSERT((*instruction & LdrOrAddInstructionMask) == AddImmediateInstruction || (*instruction & LdrOrAddInstructionMask) == LdrImmediateInstruction);
1002            if ((*instruction & LdrOrAddInstructionMask) == LdrImmediateInstruction) {
1003                 *instruction = (*instruction & ~LdrOrAddInstructionMask) | AddImmediateInstruction;
1004                 cacheFlush(instruction, sizeof(ARMWord));
1005            }
1006        }
1007
1008        static void revertBranchPtrWithPatch(void* instructionStart, RegisterID rn, ARMWord imm)
1009        {
1010            ARMWord* instruction = reinterpret_cast<ARMWord*>(instructionStart);
1011
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));
1017        }
1018
1019        // Address operations
1020
1021        static void* getRelocatedAddress(void* code, AssemblerLabel label)
1022        {
1023            return reinterpret_cast<void*>(reinterpret_cast<char*>(code) + label.m_offset);
1024        }
1025
1026        // Address differences
1027
1028        static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b)
1029        {
1030            return b.m_offset - a.m_offset;
1031        }
1032
1033        static unsigned getCallReturnOffset(AssemblerLabel call)
1034        {
1035            return call.m_offset;
1036        }
1037
1038        // Handle immediates
1039
1040        static ARMWord getOp2(ARMWord imm);
1041
1042        // Fast case if imm is known to be between 0 and 0xff
1043        static ARMWord getOp2Byte(ARMWord imm)
1044        {
1045            ASSERT(imm <= 0xff);
1046            return Op2Immediate | imm;
1047        }
1048
1049        static ARMWord getOp2Half(ARMWord imm)
1050        {
1051            ASSERT(imm <= 0xff);
1052            return ImmediateForHalfWordTransfer | (imm & 0x0f) | ((imm & 0xf0) << 4);
1053        }
1054
1055#if WTF_ARM_ARCH_AT_LEAST(7)
1056        static ARMWord getImm16Op2(ARMWord imm)
1057        {
1058            if (imm <= 0xffff)
1059                return (imm & 0xf000) << 4 | (imm & 0xfff);
1060            return InvalidImmediate;
1061        }
1062#endif
1063        ARMWord getImm(ARMWord imm, int tmpReg, bool invert = false);
1064        void moveImm(ARMWord imm, int dest);
1065        ARMWord encodeComplexImm(ARMWord imm, int dest);
1066
1067        // Memory load/store helpers
1068
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);
1075
1076        // Constant pool hnadlers
1077
1078        static ARMWord placeConstantPoolBarrier(int offset)
1079        {
1080            offset = (offset - sizeof(ARMWord)) >> 2;
1081            ASSERT((offset <= MaximumBranchOffsetDistance && offset >= MinimumBranchOffsetDistance));
1082            return AL | B | (offset & BranchOffsetMask);
1083        }
1084
1085#if OS(LINUX) && COMPILER(GCC)
1086        static inline void linuxPageFlush(uintptr_t begin, uintptr_t end)
1087        {
1088            asm volatile(
1089                "push    {r7}\n"
1090                "mov     r0, %0\n"
1091                "mov     r1, %1\n"
1092                "mov     r7, #0xf0000\n"
1093                "add     r7, r7, #0x2\n"
1094                "mov     r2, #0x0\n"
1095                "svc     0x0\n"
1096                "pop     {r7}\n"
1097                :
1098                : "r" (begin), "r" (end)
1099                : "r0", "r1", "r2");
1100        }
1101#endif
1102
1103        static void cacheFlush(void* code, size_t size)
1104        {
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;
1110
1111            if (end <= firstPageEnd) {
1112                linuxPageFlush(current, end);
1113                return;
1114            }
1115
1116            linuxPageFlush(current, firstPageEnd);
1117
1118            for (current = firstPageEnd; current + page < end; current += page)
1119                linuxPageFlush(current, current + page);
1120
1121            linuxPageFlush(current, end);
1122#elif OS(WINCE)
1123            CacheRangeFlush(code, size, CACHE_SYNC_ALL);
1124#else
1125#error "The cacheFlush support is missing on this platform."
1126#endif
1127        }
1128
1129    private:
1130        static ARMWord RM(int reg)
1131        {
1132            ASSERT(reg <= ARMRegisters::pc);
1133            return reg;
1134        }
1135
1136        static ARMWord RS(int reg)
1137        {
1138            ASSERT(reg <= ARMRegisters::pc);
1139            return reg << 8;
1140        }
1141
1142        static ARMWord RD(int reg)
1143        {
1144            ASSERT(reg <= ARMRegisters::pc);
1145            return reg << 12;
1146        }
1147
1148        static ARMWord RN(int reg)
1149        {
1150            ASSERT(reg <= ARMRegisters::pc);
1151            return reg << 16;
1152        }
1153
1154        static ARMWord getConditionalField(ARMWord i)
1155        {
1156            return i & ConditionalFieldMask;
1157        }
1158
1159        static ARMWord toARMWord(Condition cc)
1160        {
1161            return static_cast<ARMWord>(cc);
1162        }
1163
1164        static ARMWord toARMWord(uint32_t u)
1165        {
1166            return static_cast<ARMWord>(u);
1167        }
1168
1169        int genInt(int reg, ARMWord imm, bool positive);
1170
1171        ARMBuffer m_buffer;
1172        Jumps m_jumps;
1173        uint32_t m_indexOfTailOfLastWatchpoint;
1174    };
1175
1176} // namespace JSC
1177
1178#endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
1179
1180#endif // ARMAssembler_h
1181