• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <wtf/Assertions.h>
34 namespace JSC {
35 
36     typedef uint32_t ARMWord;
37 
38     namespace ARMRegisters {
39         typedef enum {
40             r0 = 0,
41             r1,
42             r2,
43             r3, S0 = r3,
44             r4,
45             r5,
46             r6,
47             r7,
48             r8, S1 = r8,
49             r9,
50             r10,
51             r11,
52             r12,
53             r13, sp = r13,
54             r14, lr = r14,
55             r15, pc = r15
56         } RegisterID;
57 
58         typedef enum {
59             d0,
60             d1,
61             d2,
62             d3, SD0 = d3,
63             d4,
64             d5,
65             d6,
66             d7,
67             d8,
68             d9,
69             d10,
70             d11,
71             d12,
72             d13,
73             d14,
74             d15,
75             d16,
76             d17,
77             d18,
78             d19,
79             d20,
80             d21,
81             d22,
82             d23,
83             d24,
84             d25,
85             d26,
86             d27,
87             d28,
88             d29,
89             d30,
90             d31
91         } FPRegisterID;
92 
93     } // namespace ARMRegisters
94 
95     class ARMAssembler {
96     public:
97         typedef ARMRegisters::RegisterID RegisterID;
98         typedef ARMRegisters::FPRegisterID FPRegisterID;
99         typedef AssemblerBufferWithConstantPool<2048, 4, 4, ARMAssembler> ARMBuffer;
100         typedef SegmentedVector<int, 64> Jumps;
101 
ARMAssembler()102         ARMAssembler() { }
103 
104         // ARM conditional constants
105         typedef enum {
106             EQ = 0x00000000, // Zero
107             NE = 0x10000000, // Non-zero
108             CS = 0x20000000,
109             CC = 0x30000000,
110             MI = 0x40000000,
111             PL = 0x50000000,
112             VS = 0x60000000,
113             VC = 0x70000000,
114             HI = 0x80000000,
115             LS = 0x90000000,
116             GE = 0xa0000000,
117             LT = 0xb0000000,
118             GT = 0xc0000000,
119             LE = 0xd0000000,
120             AL = 0xe0000000
121         } Condition;
122 
123         // ARM instruction constants
124         enum {
125             AND = (0x0 << 21),
126             EOR = (0x1 << 21),
127             SUB = (0x2 << 21),
128             RSB = (0x3 << 21),
129             ADD = (0x4 << 21),
130             ADC = (0x5 << 21),
131             SBC = (0x6 << 21),
132             RSC = (0x7 << 21),
133             TST = (0x8 << 21),
134             TEQ = (0x9 << 21),
135             CMP = (0xa << 21),
136             CMN = (0xb << 21),
137             ORR = (0xc << 21),
138             MOV = (0xd << 21),
139             BIC = (0xe << 21),
140             MVN = (0xf << 21),
141             MUL = 0x00000090,
142             MULL = 0x00c00090,
143             VADD_F64 = 0x0e300b00,
144             VDIV_F64 = 0x0e800b00,
145             VSUB_F64 = 0x0e300b40,
146             VMUL_F64 = 0x0e200b00,
147             VCMP_F64 = 0x0eb40b40,
148             VSQRT_F64 = 0x0eb10bc0,
149             DTR = 0x05000000,
150             LDRH = 0x00100090,
151             STRH = 0x00000090,
152             STMDB = 0x09200000,
153             LDMIA = 0x08b00000,
154             FDTR = 0x0d000b00,
155             B = 0x0a000000,
156             BL = 0x0b000000,
157 #if WTF_ARM_ARCH_AT_LEAST(5) || defined(__ARM_ARCH_4T__)
158             BX = 0x012fff10,
159 #endif
160             VMOV_VFP = 0x0e000a10,
161             VMOV_ARM = 0x0e100a10,
162             VCVT_F64_S32 = 0x0eb80bc0,
163             VCVT_S32_F64 = 0x0ebd0b40,
164             VCVTR_S32_F64 = 0x0ebd0bc0,
165             VMRS_APSR = 0x0ef1fa10,
166 #if WTF_ARM_ARCH_AT_LEAST(5)
167             CLZ = 0x016f0f10,
168             BKPT = 0xe1200070,
169             BLX = 0x012fff30,
170 #endif
171 #if WTF_ARM_ARCH_AT_LEAST(7)
172             MOVW = 0x03000000,
173             MOVT = 0x03400000,
174 #endif
175         };
176 
177         enum {
178             OP2_IMM = (1 << 25),
179             OP2_IMMh = (1 << 22),
180             OP2_INV_IMM = (1 << 26),
181             SET_CC = (1 << 20),
182             OP2_OFSREG = (1 << 25),
183             DT_UP = (1 << 23),
184             DT_BYTE = (1 << 22),
185             DT_WB = (1 << 21),
186             // This flag is inlcuded in LDR and STR
187             DT_PRE = (1 << 24),
188             HDT_UH = (1 << 5),
189             DT_LOAD = (1 << 20),
190         };
191 
192         // Masks of ARM instructions
193         enum {
194             BRANCH_MASK = 0x00ffffff,
195             NONARM = 0xf0000000,
196             SDT_MASK = 0x0c000000,
197             SDT_OFFSET_MASK = 0xfff,
198         };
199 
200         enum {
201             BOFFSET_MIN = -0x00800000,
202             BOFFSET_MAX = 0x007fffff,
203             SDT = 0x04000000,
204         };
205 
206         enum {
207             padForAlign8  = 0x00,
208             padForAlign16 = 0x0000,
209             padForAlign32 = 0xe12fff7f // 'bkpt 0xffff' instruction.
210         };
211 
212         static const ARMWord INVALID_IMM = 0xf0000000;
213         static const ARMWord InvalidBranchTarget = 0xffffffff;
214         static const int DefaultPrefetching = 2;
215 
216         class JmpSrc {
217             friend class ARMAssembler;
218         public:
JmpSrc()219             JmpSrc()
220                 : m_offset(-1)
221             {
222             }
223 
224         private:
JmpSrc(int offset)225             JmpSrc(int offset)
226                 : m_offset(offset)
227             {
228             }
229 
230             int m_offset;
231         };
232 
233         class JmpDst {
234             friend class ARMAssembler;
235         public:
JmpDst()236             JmpDst()
237                 : m_offset(-1)
238                 , m_used(false)
239             {
240             }
241 
isUsed()242             bool isUsed() const { return m_used; }
isSet()243             bool isSet() const { return (m_offset != -1); }
used()244             void used() { m_used = true; }
245         private:
JmpDst(int offset)246             JmpDst(int offset)
247                 : m_offset(offset)
248                 , m_used(false)
249             {
250                 ASSERT(m_offset == offset);
251             }
252 
253             signed int m_offset : 31;
254             int m_used : 1;
255         };
256 
257         // Instruction formating
258 
emitInst(ARMWord op,int rd,int rn,ARMWord op2)259         void emitInst(ARMWord op, int rd, int rn, ARMWord op2)
260         {
261             ASSERT(((op2 & ~OP2_IMM) <= 0xfff) || (((op2 & ~OP2_IMMh) <= 0xfff)));
262             m_buffer.putInt(op | RN(rn) | RD(rd) | op2);
263         }
264 
emitDoublePrecisionInst(ARMWord op,int dd,int dn,int dm)265         void emitDoublePrecisionInst(ARMWord op, int dd, int dn, int dm)
266         {
267             ASSERT((dd >= 0 && dd <= 31) && (dn >= 0 && dn <= 31) && (dm >= 0 && dm <= 31));
268             m_buffer.putInt(op | ((dd & 0xf) << 12) | ((dd & 0x10) << (22 - 4))
269                                | ((dn & 0xf) << 16) | ((dn & 0x10) << (7 - 4))
270                                | (dm & 0xf) | ((dm & 0x10) << (5 - 4)));
271         }
272 
emitSinglePrecisionInst(ARMWord op,int sd,int sn,int sm)273         void emitSinglePrecisionInst(ARMWord op, int sd, int sn, int sm)
274         {
275             ASSERT((sd >= 0 && sd <= 31) && (sn >= 0 && sn <= 31) && (sm >= 0 && sm <= 31));
276             m_buffer.putInt(op | ((sd >> 1) << 12) | ((sd & 0x1) << 22)
277                                | ((sn >> 1) << 16) | ((sn & 0x1) << 7)
278                                | (sm >> 1) | ((sm & 0x1) << 5));
279         }
280 
281         void and_r(int rd, int rn, ARMWord op2, Condition cc = AL)
282         {
283             emitInst(static_cast<ARMWord>(cc) | AND, rd, rn, op2);
284         }
285 
286         void ands_r(int rd, int rn, ARMWord op2, Condition cc = AL)
287         {
288             emitInst(static_cast<ARMWord>(cc) | AND | SET_CC, rd, rn, op2);
289         }
290 
291         void eor_r(int rd, int rn, ARMWord op2, Condition cc = AL)
292         {
293             emitInst(static_cast<ARMWord>(cc) | EOR, rd, rn, op2);
294         }
295 
296         void eors_r(int rd, int rn, ARMWord op2, Condition cc = AL)
297         {
298             emitInst(static_cast<ARMWord>(cc) | EOR | SET_CC, rd, rn, op2);
299         }
300 
301         void sub_r(int rd, int rn, ARMWord op2, Condition cc = AL)
302         {
303             emitInst(static_cast<ARMWord>(cc) | SUB, rd, rn, op2);
304         }
305 
306         void subs_r(int rd, int rn, ARMWord op2, Condition cc = AL)
307         {
308             emitInst(static_cast<ARMWord>(cc) | SUB | SET_CC, rd, rn, op2);
309         }
310 
311         void rsb_r(int rd, int rn, ARMWord op2, Condition cc = AL)
312         {
313             emitInst(static_cast<ARMWord>(cc) | RSB, rd, rn, op2);
314         }
315 
316         void rsbs_r(int rd, int rn, ARMWord op2, Condition cc = AL)
317         {
318             emitInst(static_cast<ARMWord>(cc) | RSB | SET_CC, rd, rn, op2);
319         }
320 
321         void add_r(int rd, int rn, ARMWord op2, Condition cc = AL)
322         {
323             emitInst(static_cast<ARMWord>(cc) | ADD, rd, rn, op2);
324         }
325 
326         void adds_r(int rd, int rn, ARMWord op2, Condition cc = AL)
327         {
328             emitInst(static_cast<ARMWord>(cc) | ADD | SET_CC, rd, rn, op2);
329         }
330 
331         void adc_r(int rd, int rn, ARMWord op2, Condition cc = AL)
332         {
333             emitInst(static_cast<ARMWord>(cc) | ADC, rd, rn, op2);
334         }
335 
336         void adcs_r(int rd, int rn, ARMWord op2, Condition cc = AL)
337         {
338             emitInst(static_cast<ARMWord>(cc) | ADC | SET_CC, rd, rn, op2);
339         }
340 
341         void sbc_r(int rd, int rn, ARMWord op2, Condition cc = AL)
342         {
343             emitInst(static_cast<ARMWord>(cc) | SBC, rd, rn, op2);
344         }
345 
346         void sbcs_r(int rd, int rn, ARMWord op2, Condition cc = AL)
347         {
348             emitInst(static_cast<ARMWord>(cc) | SBC | SET_CC, rd, rn, op2);
349         }
350 
351         void rsc_r(int rd, int rn, ARMWord op2, Condition cc = AL)
352         {
353             emitInst(static_cast<ARMWord>(cc) | RSC, rd, rn, op2);
354         }
355 
356         void rscs_r(int rd, int rn, ARMWord op2, Condition cc = AL)
357         {
358             emitInst(static_cast<ARMWord>(cc) | RSC | SET_CC, rd, rn, op2);
359         }
360 
361         void tst_r(int rn, ARMWord op2, Condition cc = AL)
362         {
363             emitInst(static_cast<ARMWord>(cc) | TST | SET_CC, 0, rn, op2);
364         }
365 
366         void teq_r(int rn, ARMWord op2, Condition cc = AL)
367         {
368             emitInst(static_cast<ARMWord>(cc) | TEQ | SET_CC, 0, rn, op2);
369         }
370 
371         void cmp_r(int rn, ARMWord op2, Condition cc = AL)
372         {
373             emitInst(static_cast<ARMWord>(cc) | CMP | SET_CC, 0, rn, op2);
374         }
375 
376         void cmn_r(int rn, ARMWord op2, Condition cc = AL)
377         {
378             emitInst(static_cast<ARMWord>(cc) | CMN | SET_CC, 0, rn, op2);
379         }
380 
381         void orr_r(int rd, int rn, ARMWord op2, Condition cc = AL)
382         {
383             emitInst(static_cast<ARMWord>(cc) | ORR, rd, rn, op2);
384         }
385 
386         void orrs_r(int rd, int rn, ARMWord op2, Condition cc = AL)
387         {
388             emitInst(static_cast<ARMWord>(cc) | ORR | SET_CC, rd, rn, op2);
389         }
390 
391         void mov_r(int rd, ARMWord op2, Condition cc = AL)
392         {
393             emitInst(static_cast<ARMWord>(cc) | MOV, rd, ARMRegisters::r0, op2);
394         }
395 
396 #if WTF_ARM_ARCH_AT_LEAST(7)
397         void movw_r(int rd, ARMWord op2, Condition cc = AL)
398         {
399             ASSERT((op2 | 0xf0fff) == 0xf0fff);
400             m_buffer.putInt(static_cast<ARMWord>(cc) | MOVW | RD(rd) | op2);
401         }
402 
403         void movt_r(int rd, ARMWord op2, Condition cc = AL)
404         {
405             ASSERT((op2 | 0xf0fff) == 0xf0fff);
406             m_buffer.putInt(static_cast<ARMWord>(cc) | MOVT | RD(rd) | op2);
407         }
408 #endif
409 
410         void movs_r(int rd, ARMWord op2, Condition cc = AL)
411         {
412             emitInst(static_cast<ARMWord>(cc) | MOV | SET_CC, rd, ARMRegisters::r0, op2);
413         }
414 
415         void bic_r(int rd, int rn, ARMWord op2, Condition cc = AL)
416         {
417             emitInst(static_cast<ARMWord>(cc) | BIC, rd, rn, op2);
418         }
419 
420         void bics_r(int rd, int rn, ARMWord op2, Condition cc = AL)
421         {
422             emitInst(static_cast<ARMWord>(cc) | BIC | SET_CC, rd, rn, op2);
423         }
424 
425         void mvn_r(int rd, ARMWord op2, Condition cc = AL)
426         {
427             emitInst(static_cast<ARMWord>(cc) | MVN, rd, ARMRegisters::r0, op2);
428         }
429 
430         void mvns_r(int rd, ARMWord op2, Condition cc = AL)
431         {
432             emitInst(static_cast<ARMWord>(cc) | MVN | SET_CC, rd, ARMRegisters::r0, op2);
433         }
434 
435         void mul_r(int rd, int rn, int rm, Condition cc = AL)
436         {
437             m_buffer.putInt(static_cast<ARMWord>(cc) | MUL | RN(rd) | RS(rn) | RM(rm));
438         }
439 
440         void muls_r(int rd, int rn, int rm, Condition cc = AL)
441         {
442             m_buffer.putInt(static_cast<ARMWord>(cc) | MUL | SET_CC | RN(rd) | RS(rn) | RM(rm));
443         }
444 
445         void mull_r(int rdhi, int rdlo, int rn, int rm, Condition cc = AL)
446         {
447             m_buffer.putInt(static_cast<ARMWord>(cc) | MULL | RN(rdhi) | RD(rdlo) | RS(rn) | RM(rm));
448         }
449 
450         void vadd_f64_r(int dd, int dn, int dm, Condition cc = AL)
451         {
452             emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VADD_F64, dd, dn, dm);
453         }
454 
455         void vdiv_f64_r(int dd, int dn, int dm, Condition cc = AL)
456         {
457             emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VDIV_F64, dd, dn, dm);
458         }
459 
460         void vsub_f64_r(int dd, int dn, int dm, Condition cc = AL)
461         {
462             emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VSUB_F64, dd, dn, dm);
463         }
464 
465         void vmul_f64_r(int dd, int dn, int dm, Condition cc = AL)
466         {
467             emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VMUL_F64, dd, dn, dm);
468         }
469 
470         void vcmp_f64_r(int dd, int dm, Condition cc = AL)
471         {
472             emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VCMP_F64, dd, 0, dm);
473         }
474 
475         void vsqrt_f64_r(int dd, int dm, Condition cc = AL)
476         {
477             emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VSQRT_F64, dd, 0, dm);
478         }
479 
480         void ldr_imm(int rd, ARMWord imm, Condition cc = AL)
481         {
482             m_buffer.putIntWithConstantInt(static_cast<ARMWord>(cc) | DTR | DT_LOAD | DT_UP | RN(ARMRegisters::pc) | RD(rd), imm, true);
483         }
484 
485         void ldr_un_imm(int rd, ARMWord imm, Condition cc = AL)
486         {
487             m_buffer.putIntWithConstantInt(static_cast<ARMWord>(cc) | DTR | DT_LOAD | DT_UP | RN(ARMRegisters::pc) | RD(rd), imm);
488         }
489 
490         void dtr_u(bool isLoad, int rd, int rb, ARMWord op2, Condition cc = AL)
491         {
492             emitInst(static_cast<ARMWord>(cc) | DTR | (isLoad ? DT_LOAD : 0) | DT_UP, rd, rb, op2);
493         }
494 
495         void dtr_ur(bool isLoad, int rd, int rb, int rm, Condition cc = AL)
496         {
497             emitInst(static_cast<ARMWord>(cc) | DTR | (isLoad ? DT_LOAD : 0) | DT_UP | OP2_OFSREG, rd, rb, rm);
498         }
499 
500         void dtr_d(bool isLoad, int rd, int rb, ARMWord op2, Condition cc = AL)
501         {
502             emitInst(static_cast<ARMWord>(cc) | DTR | (isLoad ? DT_LOAD : 0), rd, rb, op2);
503         }
504 
505         void dtr_dr(bool isLoad, int rd, int rb, int rm, Condition cc = AL)
506         {
507             emitInst(static_cast<ARMWord>(cc) | DTR | (isLoad ? DT_LOAD : 0) | OP2_OFSREG, rd, rb, rm);
508         }
509 
510         void ldrh_r(int rd, int rn, int rm, Condition cc = AL)
511         {
512             emitInst(static_cast<ARMWord>(cc) | LDRH | HDT_UH | DT_UP | DT_PRE, rd, rn, rm);
513         }
514 
515         void ldrh_d(int rd, int rb, ARMWord op2, Condition cc = AL)
516         {
517             emitInst(static_cast<ARMWord>(cc) | LDRH | HDT_UH | DT_PRE, rd, rb, op2);
518         }
519 
520         void ldrh_u(int rd, int rb, ARMWord op2, Condition cc = AL)
521         {
522             emitInst(static_cast<ARMWord>(cc) | LDRH | HDT_UH | DT_UP | DT_PRE, rd, rb, op2);
523         }
524 
525         void strh_r(int rn, int rm, int rd, Condition cc = AL)
526         {
527             emitInst(static_cast<ARMWord>(cc) | STRH | HDT_UH | DT_UP | DT_PRE, rd, rn, rm);
528         }
529 
530         void fdtr_u(bool isLoad, int rd, int rb, ARMWord op2, Condition cc = AL)
531         {
532             ASSERT(op2 <= 0xff);
533             emitInst(static_cast<ARMWord>(cc) | FDTR | DT_UP | (isLoad ? DT_LOAD : 0), rd, rb, op2);
534         }
535 
536         void fdtr_d(bool isLoad, int rd, int rb, ARMWord op2, Condition cc = AL)
537         {
538             ASSERT(op2 <= 0xff);
539             emitInst(static_cast<ARMWord>(cc) | FDTR | (isLoad ? DT_LOAD : 0), rd, rb, op2);
540         }
541 
542         void push_r(int reg, Condition cc = AL)
543         {
544             ASSERT(ARMWord(reg) <= 0xf);
545             m_buffer.putInt(cc | DTR | DT_WB | RN(ARMRegisters::sp) | RD(reg) | 0x4);
546         }
547 
548         void pop_r(int reg, Condition cc = AL)
549         {
550             ASSERT(ARMWord(reg) <= 0xf);
551             m_buffer.putInt(cc | (DTR ^ DT_PRE) | DT_LOAD | DT_UP | RN(ARMRegisters::sp) | RD(reg) | 0x4);
552         }
553 
554         inline void poke_r(int reg, Condition cc = AL)
555         {
556             dtr_d(false, ARMRegisters::sp, 0, reg, cc);
557         }
558 
559         inline void peek_r(int reg, Condition cc = AL)
560         {
561             dtr_u(true, reg, ARMRegisters::sp, 0, cc);
562         }
563 
564         void vmov_vfp_r(int sn, int rt, Condition cc = AL)
565         {
566             ASSERT(rt <= 15);
567             emitSinglePrecisionInst(static_cast<ARMWord>(cc) | VMOV_VFP, rt << 1, sn, 0);
568         }
569 
570         void vmov_arm_r(int rt, int sn, Condition cc = AL)
571         {
572             ASSERT(rt <= 15);
573             emitSinglePrecisionInst(static_cast<ARMWord>(cc) | VMOV_ARM, rt << 1, sn, 0);
574         }
575 
576         void vcvt_f64_s32_r(int dd, int sm, Condition cc = AL)
577         {
578             ASSERT(!(sm & 0x1)); // sm must be divisible by 2
579             emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VCVT_F64_S32, dd, 0, (sm >> 1));
580         }
581 
582         void vcvt_s32_f64_r(int sd, int dm, Condition cc = AL)
583         {
584             ASSERT(!(sd & 0x1)); // sd must be divisible by 2
585             emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VCVT_S32_F64, (sd >> 1), 0, dm);
586         }
587 
588         void vcvtr_s32_f64_r(int sd, int dm, Condition cc = AL)
589         {
590             ASSERT(!(sd & 0x1)); // sd must be divisible by 2
591             emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VCVTR_S32_F64, (sd >> 1), 0, dm);
592         }
593 
594         void vmrs_apsr(Condition cc = AL)
595         {
596             m_buffer.putInt(static_cast<ARMWord>(cc) | VMRS_APSR);
597         }
598 
599 #if WTF_ARM_ARCH_AT_LEAST(5)
600         void clz_r(int rd, int rm, Condition cc = AL)
601         {
602             m_buffer.putInt(static_cast<ARMWord>(cc) | CLZ | RD(rd) | RM(rm));
603         }
604 #endif
605 
bkpt(ARMWord value)606         void bkpt(ARMWord value)
607         {
608 #if WTF_ARM_ARCH_AT_LEAST(5)
609             m_buffer.putInt(BKPT | ((value & 0xff0) << 4) | (value & 0xf));
610 #else
611             // Cannot access to Zero memory address
612             dtr_dr(true, ARMRegisters::S0, ARMRegisters::S0, ARMRegisters::S0);
613 #endif
614         }
615 
616         void bx(int rm, Condition cc = AL)
617         {
618 #if WTF_ARM_ARCH_AT_LEAST(5) || defined(__ARM_ARCH_4T__)
619             emitInst(static_cast<ARMWord>(cc) | BX, 0, 0, RM(rm));
620 #else
621             mov_r(ARMRegisters::pc, RM(rm), cc);
622 #endif
623         }
624 
625         JmpSrc blx(int rm, Condition cc = AL)
626         {
627 #if WTF_ARM_ARCH_AT_LEAST(5)
628             emitInst(static_cast<ARMWord>(cc) | BLX, 0, 0, RM(rm));
629 #else
630             ASSERT(rm != 14);
631             ensureSpace(2 * sizeof(ARMWord), 0);
632             mov_r(ARMRegisters::lr, ARMRegisters::pc, cc);
633             bx(rm, cc);
634 #endif
635             return JmpSrc(m_buffer.uncheckedSize());
636         }
637 
lsl(int reg,ARMWord value)638         static ARMWord lsl(int reg, ARMWord value)
639         {
640             ASSERT(reg <= ARMRegisters::pc);
641             ASSERT(value <= 0x1f);
642             return reg | (value << 7) | 0x00;
643         }
644 
lsr(int reg,ARMWord value)645         static ARMWord lsr(int reg, ARMWord value)
646         {
647             ASSERT(reg <= ARMRegisters::pc);
648             ASSERT(value <= 0x1f);
649             return reg | (value << 7) | 0x20;
650         }
651 
asr(int reg,ARMWord value)652         static ARMWord asr(int reg, ARMWord value)
653         {
654             ASSERT(reg <= ARMRegisters::pc);
655             ASSERT(value <= 0x1f);
656             return reg | (value << 7) | 0x40;
657         }
658 
lsl_r(int reg,int shiftReg)659         static ARMWord lsl_r(int reg, int shiftReg)
660         {
661             ASSERT(reg <= ARMRegisters::pc);
662             ASSERT(shiftReg <= ARMRegisters::pc);
663             return reg | (shiftReg << 8) | 0x10;
664         }
665 
lsr_r(int reg,int shiftReg)666         static ARMWord lsr_r(int reg, int shiftReg)
667         {
668             ASSERT(reg <= ARMRegisters::pc);
669             ASSERT(shiftReg <= ARMRegisters::pc);
670             return reg | (shiftReg << 8) | 0x30;
671         }
672 
asr_r(int reg,int shiftReg)673         static ARMWord asr_r(int reg, int shiftReg)
674         {
675             ASSERT(reg <= ARMRegisters::pc);
676             ASSERT(shiftReg <= ARMRegisters::pc);
677             return reg | (shiftReg << 8) | 0x50;
678         }
679 
680         // General helpers
681 
size()682         int size()
683         {
684             return m_buffer.size();
685         }
686 
ensureSpace(int insnSpace,int constSpace)687         void ensureSpace(int insnSpace, int constSpace)
688         {
689             m_buffer.ensureSpace(insnSpace, constSpace);
690         }
691 
sizeOfConstantPool()692         int sizeOfConstantPool()
693         {
694             return m_buffer.sizeOfConstantPool();
695         }
696 
label()697         JmpDst label()
698         {
699             return JmpDst(m_buffer.size());
700         }
701 
align(int alignment)702         JmpDst align(int alignment)
703         {
704             while (!m_buffer.isAligned(alignment))
705                 mov_r(ARMRegisters::r0, ARMRegisters::r0);
706 
707             return label();
708         }
709 
710         JmpSrc loadBranchTarget(int rd, Condition cc = AL, int useConstantPool = 0)
711         {
712             ensureSpace(sizeof(ARMWord), sizeof(ARMWord));
713             m_jumps.append(m_buffer.uncheckedSize() | (useConstantPool & 0x1));
714             ldr_un_imm(rd, InvalidBranchTarget, cc);
715             return JmpSrc(m_buffer.uncheckedSize());
716         }
717 
718         JmpSrc jmp(Condition cc = AL, int useConstantPool = 0)
719         {
720             return loadBranchTarget(ARMRegisters::pc, cc, useConstantPool);
721         }
722 
723         void* executableCopy(ExecutablePool* allocator);
724 
725 #ifndef NDEBUG
debugOffset()726         unsigned debugOffset() { return m_formatter.debugOffset(); }
727 #endif
728 
729         // Patching helpers
730 
getLdrImmAddress(ARMWord * insn)731         static ARMWord* getLdrImmAddress(ARMWord* insn)
732         {
733 #if WTF_ARM_ARCH_AT_LEAST(5)
734             // Check for call
735             if ((*insn & 0x0f7f0000) != 0x051f0000) {
736                 // Must be BLX
737                 ASSERT((*insn & 0x012fff30) == 0x012fff30);
738                 insn--;
739             }
740 #endif
741             // Must be an ldr ..., [pc +/- imm]
742             ASSERT((*insn & 0x0f7f0000) == 0x051f0000);
743 
744             ARMWord addr = reinterpret_cast<ARMWord>(insn) + DefaultPrefetching * sizeof(ARMWord);
745             if (*insn & DT_UP)
746                 return reinterpret_cast<ARMWord*>(addr + (*insn & SDT_OFFSET_MASK));
747             return reinterpret_cast<ARMWord*>(addr - (*insn & SDT_OFFSET_MASK));
748         }
749 
getLdrImmAddressOnPool(ARMWord * insn,uint32_t * constPool)750         static ARMWord* getLdrImmAddressOnPool(ARMWord* insn, uint32_t* constPool)
751         {
752             // Must be an ldr ..., [pc +/- imm]
753             ASSERT((*insn & 0x0f7f0000) == 0x051f0000);
754 
755             if (*insn & 0x1)
756                 return reinterpret_cast<ARMWord*>(constPool + ((*insn & SDT_OFFSET_MASK) >> 1));
757             return getLdrImmAddress(insn);
758         }
759 
patchPointerInternal(intptr_t from,void * to)760         static void patchPointerInternal(intptr_t from, void* to)
761         {
762             ARMWord* insn = reinterpret_cast<ARMWord*>(from);
763             ARMWord* addr = getLdrImmAddress(insn);
764             *addr = reinterpret_cast<ARMWord>(to);
765         }
766 
patchConstantPoolLoad(ARMWord load,ARMWord value)767         static ARMWord patchConstantPoolLoad(ARMWord load, ARMWord value)
768         {
769             value = (value << 1) + 1;
770             ASSERT(!(value & ~0xfff));
771             return (load & ~0xfff) | value;
772         }
773 
774         static void patchConstantPoolLoad(void* loadAddr, void* constPoolAddr);
775 
776         // Patch pointers
777 
linkPointer(void * code,JmpDst from,void * to)778         static void linkPointer(void* code, JmpDst from, void* to)
779         {
780             patchPointerInternal(reinterpret_cast<intptr_t>(code) + from.m_offset, to);
781         }
782 
repatchInt32(void * from,int32_t to)783         static void repatchInt32(void* from, int32_t to)
784         {
785             patchPointerInternal(reinterpret_cast<intptr_t>(from), reinterpret_cast<void*>(to));
786         }
787 
repatchPointer(void * from,void * to)788         static void repatchPointer(void* from, void* to)
789         {
790             patchPointerInternal(reinterpret_cast<intptr_t>(from), to);
791         }
792 
793         // Linkers
794         static intptr_t getAbsoluteJumpAddress(void* base, int offset = 0)
795         {
796             return reinterpret_cast<intptr_t>(base) + offset - sizeof(ARMWord);
797         }
798 
linkJump(JmpSrc from,JmpDst to)799         void linkJump(JmpSrc from, JmpDst to)
800         {
801             ARMWord* insn = reinterpret_cast<ARMWord*>(getAbsoluteJumpAddress(m_buffer.data(), from.m_offset));
802             ARMWord* addr = getLdrImmAddressOnPool(insn, m_buffer.poolAddress());
803             *addr = static_cast<ARMWord>(to.m_offset);
804         }
805 
linkJump(void * code,JmpSrc from,void * to)806         static void linkJump(void* code, JmpSrc from, void* to)
807         {
808             patchPointerInternal(getAbsoluteJumpAddress(code, from.m_offset), to);
809         }
810 
relinkJump(void * from,void * to)811         static void relinkJump(void* from, void* to)
812         {
813             patchPointerInternal(getAbsoluteJumpAddress(from), to);
814         }
815 
linkCall(void * code,JmpSrc from,void * to)816         static void linkCall(void* code, JmpSrc from, void* to)
817         {
818             patchPointerInternal(getAbsoluteJumpAddress(code, from.m_offset), to);
819         }
820 
relinkCall(void * from,void * to)821         static void relinkCall(void* from, void* to)
822         {
823             patchPointerInternal(getAbsoluteJumpAddress(from), to);
824         }
825 
826         // Address operations
827 
getRelocatedAddress(void * code,JmpSrc jump)828         static void* getRelocatedAddress(void* code, JmpSrc jump)
829         {
830             return reinterpret_cast<void*>(reinterpret_cast<char*>(code) + jump.m_offset);
831         }
832 
getRelocatedAddress(void * code,JmpDst label)833         static void* getRelocatedAddress(void* code, JmpDst label)
834         {
835             return reinterpret_cast<void*>(reinterpret_cast<char*>(code) + label.m_offset);
836         }
837 
838         // Address differences
839 
getDifferenceBetweenLabels(JmpDst from,JmpSrc to)840         static int getDifferenceBetweenLabels(JmpDst from, JmpSrc to)
841         {
842             return to.m_offset - from.m_offset;
843         }
844 
getDifferenceBetweenLabels(JmpDst from,JmpDst to)845         static int getDifferenceBetweenLabels(JmpDst from, JmpDst to)
846         {
847             return to.m_offset - from.m_offset;
848         }
849 
getCallReturnOffset(JmpSrc call)850         static unsigned getCallReturnOffset(JmpSrc call)
851         {
852             return call.m_offset;
853         }
854 
855         // Handle immediates
856 
getOp2Byte(ARMWord imm)857         static ARMWord getOp2Byte(ARMWord imm)
858         {
859             ASSERT(imm <= 0xff);
860             return OP2_IMMh | (imm & 0x0f) | ((imm & 0xf0) << 4) ;
861         }
862 
863         static ARMWord getOp2(ARMWord imm);
864 
865 #if WTF_ARM_ARCH_AT_LEAST(7)
getImm16Op2(ARMWord imm)866         static ARMWord getImm16Op2(ARMWord imm)
867         {
868             if (imm <= 0xffff)
869                 return (imm & 0xf000) << 4 | (imm & 0xfff);
870             return INVALID_IMM;
871         }
872 #endif
873         ARMWord getImm(ARMWord imm, int tmpReg, bool invert = false);
874         void moveImm(ARMWord imm, int dest);
875         ARMWord encodeComplexImm(ARMWord imm, int dest);
876 
getOffsetForHalfwordDataTransfer(ARMWord imm,int tmpReg)877         ARMWord getOffsetForHalfwordDataTransfer(ARMWord imm, int tmpReg)
878         {
879             // Encode immediate data in the instruction if it is possible
880             if (imm <= 0xff)
881                 return getOp2Byte(imm);
882             // Otherwise, store the data in a temporary register
883             return encodeComplexImm(imm, tmpReg);
884         }
885 
886         // Memory load/store helpers
887 
888         void dataTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset, bool bytes = false);
889         void baseIndexTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset);
890         void doubleTransfer(bool isLoad, FPRegisterID srcDst, RegisterID base, int32_t offset);
891 
892         // Constant pool hnadlers
893 
placeConstantPoolBarrier(int offset)894         static ARMWord placeConstantPoolBarrier(int offset)
895         {
896             offset = (offset - sizeof(ARMWord)) >> 2;
897             ASSERT((offset <= BOFFSET_MAX && offset >= BOFFSET_MIN));
898             return AL | B | (offset & BRANCH_MASK);
899         }
900 
901     private:
RM(int reg)902         ARMWord RM(int reg)
903         {
904             ASSERT(reg <= ARMRegisters::pc);
905             return reg;
906         }
907 
RS(int reg)908         ARMWord RS(int reg)
909         {
910             ASSERT(reg <= ARMRegisters::pc);
911             return reg << 8;
912         }
913 
RD(int reg)914         ARMWord RD(int reg)
915         {
916             ASSERT(reg <= ARMRegisters::pc);
917             return reg << 12;
918         }
919 
RN(int reg)920         ARMWord RN(int reg)
921         {
922             ASSERT(reg <= ARMRegisters::pc);
923             return reg << 16;
924         }
925 
getConditionalField(ARMWord i)926         static ARMWord getConditionalField(ARMWord i)
927         {
928             return i & 0xf0000000;
929         }
930 
931         int genInt(int reg, ARMWord imm, bool positive);
932 
933         ARMBuffer m_buffer;
934         Jumps m_jumps;
935     };
936 
937 } // namespace JSC
938 
939 #endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
940 
941 #endif // ARMAssembler_h
942