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<AssemblerLabel, 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         // Instruction formating
217 
emitInst(ARMWord op,int rd,int rn,ARMWord op2)218         void emitInst(ARMWord op, int rd, int rn, ARMWord op2)
219         {
220             ASSERT(((op2 & ~OP2_IMM) <= 0xfff) || (((op2 & ~OP2_IMMh) <= 0xfff)));
221             m_buffer.putInt(op | RN(rn) | RD(rd) | op2);
222         }
223 
emitDoublePrecisionInst(ARMWord op,int dd,int dn,int dm)224         void emitDoublePrecisionInst(ARMWord op, int dd, int dn, int dm)
225         {
226             ASSERT((dd >= 0 && dd <= 31) && (dn >= 0 && dn <= 31) && (dm >= 0 && dm <= 31));
227             m_buffer.putInt(op | ((dd & 0xf) << 12) | ((dd & 0x10) << (22 - 4))
228                                | ((dn & 0xf) << 16) | ((dn & 0x10) << (7 - 4))
229                                | (dm & 0xf) | ((dm & 0x10) << (5 - 4)));
230         }
231 
emitSinglePrecisionInst(ARMWord op,int sd,int sn,int sm)232         void emitSinglePrecisionInst(ARMWord op, int sd, int sn, int sm)
233         {
234             ASSERT((sd >= 0 && sd <= 31) && (sn >= 0 && sn <= 31) && (sm >= 0 && sm <= 31));
235             m_buffer.putInt(op | ((sd >> 1) << 12) | ((sd & 0x1) << 22)
236                                | ((sn >> 1) << 16) | ((sn & 0x1) << 7)
237                                | (sm >> 1) | ((sm & 0x1) << 5));
238         }
239 
240         void and_r(int rd, int rn, ARMWord op2, Condition cc = AL)
241         {
242             emitInst(static_cast<ARMWord>(cc) | AND, rd, rn, op2);
243         }
244 
245         void ands_r(int rd, int rn, ARMWord op2, Condition cc = AL)
246         {
247             emitInst(static_cast<ARMWord>(cc) | AND | SET_CC, rd, rn, op2);
248         }
249 
250         void eor_r(int rd, int rn, ARMWord op2, Condition cc = AL)
251         {
252             emitInst(static_cast<ARMWord>(cc) | EOR, rd, rn, op2);
253         }
254 
255         void eors_r(int rd, int rn, ARMWord op2, Condition cc = AL)
256         {
257             emitInst(static_cast<ARMWord>(cc) | EOR | SET_CC, rd, rn, op2);
258         }
259 
260         void sub_r(int rd, int rn, ARMWord op2, Condition cc = AL)
261         {
262             emitInst(static_cast<ARMWord>(cc) | SUB, rd, rn, op2);
263         }
264 
265         void subs_r(int rd, int rn, ARMWord op2, Condition cc = AL)
266         {
267             emitInst(static_cast<ARMWord>(cc) | SUB | SET_CC, rd, rn, op2);
268         }
269 
270         void rsb_r(int rd, int rn, ARMWord op2, Condition cc = AL)
271         {
272             emitInst(static_cast<ARMWord>(cc) | RSB, rd, rn, op2);
273         }
274 
275         void rsbs_r(int rd, int rn, ARMWord op2, Condition cc = AL)
276         {
277             emitInst(static_cast<ARMWord>(cc) | RSB | SET_CC, rd, rn, op2);
278         }
279 
280         void add_r(int rd, int rn, ARMWord op2, Condition cc = AL)
281         {
282             emitInst(static_cast<ARMWord>(cc) | ADD, rd, rn, op2);
283         }
284 
285         void adds_r(int rd, int rn, ARMWord op2, Condition cc = AL)
286         {
287             emitInst(static_cast<ARMWord>(cc) | ADD | SET_CC, rd, rn, op2);
288         }
289 
290         void adc_r(int rd, int rn, ARMWord op2, Condition cc = AL)
291         {
292             emitInst(static_cast<ARMWord>(cc) | ADC, rd, rn, op2);
293         }
294 
295         void adcs_r(int rd, int rn, ARMWord op2, Condition cc = AL)
296         {
297             emitInst(static_cast<ARMWord>(cc) | ADC | SET_CC, rd, rn, op2);
298         }
299 
300         void sbc_r(int rd, int rn, ARMWord op2, Condition cc = AL)
301         {
302             emitInst(static_cast<ARMWord>(cc) | SBC, rd, rn, op2);
303         }
304 
305         void sbcs_r(int rd, int rn, ARMWord op2, Condition cc = AL)
306         {
307             emitInst(static_cast<ARMWord>(cc) | SBC | SET_CC, rd, rn, op2);
308         }
309 
310         void rsc_r(int rd, int rn, ARMWord op2, Condition cc = AL)
311         {
312             emitInst(static_cast<ARMWord>(cc) | RSC, rd, rn, op2);
313         }
314 
315         void rscs_r(int rd, int rn, ARMWord op2, Condition cc = AL)
316         {
317             emitInst(static_cast<ARMWord>(cc) | RSC | SET_CC, rd, rn, op2);
318         }
319 
320         void tst_r(int rn, ARMWord op2, Condition cc = AL)
321         {
322             emitInst(static_cast<ARMWord>(cc) | TST | SET_CC, 0, rn, op2);
323         }
324 
325         void teq_r(int rn, ARMWord op2, Condition cc = AL)
326         {
327             emitInst(static_cast<ARMWord>(cc) | TEQ | SET_CC, 0, rn, op2);
328         }
329 
330         void cmp_r(int rn, ARMWord op2, Condition cc = AL)
331         {
332             emitInst(static_cast<ARMWord>(cc) | CMP | SET_CC, 0, rn, op2);
333         }
334 
335         void cmn_r(int rn, ARMWord op2, Condition cc = AL)
336         {
337             emitInst(static_cast<ARMWord>(cc) | CMN | SET_CC, 0, rn, op2);
338         }
339 
340         void orr_r(int rd, int rn, ARMWord op2, Condition cc = AL)
341         {
342             emitInst(static_cast<ARMWord>(cc) | ORR, rd, rn, op2);
343         }
344 
345         void orrs_r(int rd, int rn, ARMWord op2, Condition cc = AL)
346         {
347             emitInst(static_cast<ARMWord>(cc) | ORR | SET_CC, rd, rn, op2);
348         }
349 
350         void mov_r(int rd, ARMWord op2, Condition cc = AL)
351         {
352             emitInst(static_cast<ARMWord>(cc) | MOV, rd, ARMRegisters::r0, op2);
353         }
354 
355 #if WTF_ARM_ARCH_AT_LEAST(7)
356         void movw_r(int rd, ARMWord op2, Condition cc = AL)
357         {
358             ASSERT((op2 | 0xf0fff) == 0xf0fff);
359             m_buffer.putInt(static_cast<ARMWord>(cc) | MOVW | RD(rd) | op2);
360         }
361 
362         void movt_r(int rd, ARMWord op2, Condition cc = AL)
363         {
364             ASSERT((op2 | 0xf0fff) == 0xf0fff);
365             m_buffer.putInt(static_cast<ARMWord>(cc) | MOVT | RD(rd) | op2);
366         }
367 #endif
368 
369         void movs_r(int rd, ARMWord op2, Condition cc = AL)
370         {
371             emitInst(static_cast<ARMWord>(cc) | MOV | SET_CC, rd, ARMRegisters::r0, op2);
372         }
373 
374         void bic_r(int rd, int rn, ARMWord op2, Condition cc = AL)
375         {
376             emitInst(static_cast<ARMWord>(cc) | BIC, rd, rn, op2);
377         }
378 
379         void bics_r(int rd, int rn, ARMWord op2, Condition cc = AL)
380         {
381             emitInst(static_cast<ARMWord>(cc) | BIC | SET_CC, rd, rn, op2);
382         }
383 
384         void mvn_r(int rd, ARMWord op2, Condition cc = AL)
385         {
386             emitInst(static_cast<ARMWord>(cc) | MVN, rd, ARMRegisters::r0, op2);
387         }
388 
389         void mvns_r(int rd, ARMWord op2, Condition cc = AL)
390         {
391             emitInst(static_cast<ARMWord>(cc) | MVN | SET_CC, rd, ARMRegisters::r0, op2);
392         }
393 
394         void mul_r(int rd, int rn, int rm, Condition cc = AL)
395         {
396             m_buffer.putInt(static_cast<ARMWord>(cc) | MUL | RN(rd) | RS(rn) | RM(rm));
397         }
398 
399         void muls_r(int rd, int rn, int rm, Condition cc = AL)
400         {
401             m_buffer.putInt(static_cast<ARMWord>(cc) | MUL | SET_CC | RN(rd) | RS(rn) | RM(rm));
402         }
403 
404         void mull_r(int rdhi, int rdlo, int rn, int rm, Condition cc = AL)
405         {
406             m_buffer.putInt(static_cast<ARMWord>(cc) | MULL | RN(rdhi) | RD(rdlo) | RS(rn) | RM(rm));
407         }
408 
409         void vadd_f64_r(int dd, int dn, int dm, Condition cc = AL)
410         {
411             emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VADD_F64, dd, dn, dm);
412         }
413 
414         void vdiv_f64_r(int dd, int dn, int dm, Condition cc = AL)
415         {
416             emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VDIV_F64, dd, dn, dm);
417         }
418 
419         void vsub_f64_r(int dd, int dn, int dm, Condition cc = AL)
420         {
421             emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VSUB_F64, dd, dn, dm);
422         }
423 
424         void vmul_f64_r(int dd, int dn, int dm, Condition cc = AL)
425         {
426             emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VMUL_F64, dd, dn, dm);
427         }
428 
429         void vcmp_f64_r(int dd, int dm, Condition cc = AL)
430         {
431             emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VCMP_F64, dd, 0, dm);
432         }
433 
434         void vsqrt_f64_r(int dd, int dm, Condition cc = AL)
435         {
436             emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VSQRT_F64, dd, 0, dm);
437         }
438 
439         void ldr_imm(int rd, ARMWord imm, Condition cc = AL)
440         {
441             m_buffer.putIntWithConstantInt(static_cast<ARMWord>(cc) | DTR | DT_LOAD | DT_UP | RN(ARMRegisters::pc) | RD(rd), imm, true);
442         }
443 
444         void ldr_un_imm(int rd, ARMWord imm, Condition cc = AL)
445         {
446             m_buffer.putIntWithConstantInt(static_cast<ARMWord>(cc) | DTR | DT_LOAD | DT_UP | RN(ARMRegisters::pc) | RD(rd), imm);
447         }
448 
449         void dtr_u(bool isLoad, int rd, int rb, ARMWord op2, Condition cc = AL)
450         {
451             emitInst(static_cast<ARMWord>(cc) | DTR | (isLoad ? DT_LOAD : 0) | DT_UP, rd, rb, op2);
452         }
453 
454         void dtr_ur(bool isLoad, int rd, int rb, int rm, Condition cc = AL)
455         {
456             emitInst(static_cast<ARMWord>(cc) | DTR | (isLoad ? DT_LOAD : 0) | DT_UP | OP2_OFSREG, rd, rb, rm);
457         }
458 
459         void dtr_d(bool isLoad, int rd, int rb, ARMWord op2, Condition cc = AL)
460         {
461             emitInst(static_cast<ARMWord>(cc) | DTR | (isLoad ? DT_LOAD : 0), rd, rb, op2);
462         }
463 
464         void dtr_dr(bool isLoad, int rd, int rb, int rm, Condition cc = AL)
465         {
466             emitInst(static_cast<ARMWord>(cc) | DTR | (isLoad ? DT_LOAD : 0) | OP2_OFSREG, rd, rb, rm);
467         }
468 
469         void ldrh_r(int rd, int rn, int rm, Condition cc = AL)
470         {
471             emitInst(static_cast<ARMWord>(cc) | LDRH | HDT_UH | DT_UP | DT_PRE, rd, rn, rm);
472         }
473 
474         void ldrh_d(int rd, int rb, ARMWord op2, Condition cc = AL)
475         {
476             emitInst(static_cast<ARMWord>(cc) | LDRH | HDT_UH | DT_PRE, rd, rb, op2);
477         }
478 
479         void ldrh_u(int rd, int rb, ARMWord op2, Condition cc = AL)
480         {
481             emitInst(static_cast<ARMWord>(cc) | LDRH | HDT_UH | DT_UP | DT_PRE, rd, rb, op2);
482         }
483 
484         void strh_r(int rn, int rm, int rd, Condition cc = AL)
485         {
486             emitInst(static_cast<ARMWord>(cc) | STRH | HDT_UH | DT_UP | DT_PRE, rd, rn, rm);
487         }
488 
489         void fdtr_u(bool isLoad, int rd, int rb, ARMWord op2, Condition cc = AL)
490         {
491             ASSERT(op2 <= 0xff);
492             emitInst(static_cast<ARMWord>(cc) | FDTR | DT_UP | (isLoad ? DT_LOAD : 0), rd, rb, op2);
493         }
494 
495         void fdtr_d(bool isLoad, int rd, int rb, ARMWord op2, Condition cc = AL)
496         {
497             ASSERT(op2 <= 0xff);
498             emitInst(static_cast<ARMWord>(cc) | FDTR | (isLoad ? DT_LOAD : 0), rd, rb, op2);
499         }
500 
501         void push_r(int reg, Condition cc = AL)
502         {
503             ASSERT(ARMWord(reg) <= 0xf);
504             m_buffer.putInt(cc | DTR | DT_WB | RN(ARMRegisters::sp) | RD(reg) | 0x4);
505         }
506 
507         void pop_r(int reg, Condition cc = AL)
508         {
509             ASSERT(ARMWord(reg) <= 0xf);
510             m_buffer.putInt(cc | (DTR ^ DT_PRE) | DT_LOAD | DT_UP | RN(ARMRegisters::sp) | RD(reg) | 0x4);
511         }
512 
513         inline void poke_r(int reg, Condition cc = AL)
514         {
515             dtr_d(false, ARMRegisters::sp, 0, reg, cc);
516         }
517 
518         inline void peek_r(int reg, Condition cc = AL)
519         {
520             dtr_u(true, reg, ARMRegisters::sp, 0, cc);
521         }
522 
523         void vmov_vfp_r(int sn, int rt, Condition cc = AL)
524         {
525             ASSERT(rt <= 15);
526             emitSinglePrecisionInst(static_cast<ARMWord>(cc) | VMOV_VFP, rt << 1, sn, 0);
527         }
528 
529         void vmov_arm_r(int rt, int sn, Condition cc = AL)
530         {
531             ASSERT(rt <= 15);
532             emitSinglePrecisionInst(static_cast<ARMWord>(cc) | VMOV_ARM, rt << 1, sn, 0);
533         }
534 
535         void vcvt_f64_s32_r(int dd, int sm, Condition cc = AL)
536         {
537             ASSERT(!(sm & 0x1)); // sm must be divisible by 2
538             emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VCVT_F64_S32, dd, 0, (sm >> 1));
539         }
540 
541         void vcvt_s32_f64_r(int sd, int dm, Condition cc = AL)
542         {
543             ASSERT(!(sd & 0x1)); // sd must be divisible by 2
544             emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VCVT_S32_F64, (sd >> 1), 0, dm);
545         }
546 
547         void vcvtr_s32_f64_r(int sd, int dm, Condition cc = AL)
548         {
549             ASSERT(!(sd & 0x1)); // sd must be divisible by 2
550             emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VCVTR_S32_F64, (sd >> 1), 0, dm);
551         }
552 
553         void vmrs_apsr(Condition cc = AL)
554         {
555             m_buffer.putInt(static_cast<ARMWord>(cc) | VMRS_APSR);
556         }
557 
558 #if WTF_ARM_ARCH_AT_LEAST(5)
559         void clz_r(int rd, int rm, Condition cc = AL)
560         {
561             m_buffer.putInt(static_cast<ARMWord>(cc) | CLZ | RD(rd) | RM(rm));
562         }
563 #endif
564 
bkpt(ARMWord value)565         void bkpt(ARMWord value)
566         {
567 #if WTF_ARM_ARCH_AT_LEAST(5)
568             m_buffer.putInt(BKPT | ((value & 0xff0) << 4) | (value & 0xf));
569 #else
570             // Cannot access to Zero memory address
571             dtr_dr(true, ARMRegisters::S0, ARMRegisters::S0, ARMRegisters::S0);
572 #endif
573         }
574 
575         void bx(int rm, Condition cc = AL)
576         {
577 #if WTF_ARM_ARCH_AT_LEAST(5) || defined(__ARM_ARCH_4T__)
578             emitInst(static_cast<ARMWord>(cc) | BX, 0, 0, RM(rm));
579 #else
580             mov_r(ARMRegisters::pc, RM(rm), cc);
581 #endif
582         }
583 
584         AssemblerLabel blx(int rm, Condition cc = AL)
585         {
586 #if WTF_ARM_ARCH_AT_LEAST(5)
587             emitInst(static_cast<ARMWord>(cc) | BLX, 0, 0, RM(rm));
588 #else
589             ASSERT(rm != 14);
590             ensureSpace(2 * sizeof(ARMWord), 0);
591             mov_r(ARMRegisters::lr, ARMRegisters::pc, cc);
592             bx(rm, cc);
593 #endif
594             return m_buffer.label();
595         }
596 
lsl(int reg,ARMWord value)597         static ARMWord lsl(int reg, ARMWord value)
598         {
599             ASSERT(reg <= ARMRegisters::pc);
600             ASSERT(value <= 0x1f);
601             return reg | (value << 7) | 0x00;
602         }
603 
lsr(int reg,ARMWord value)604         static ARMWord lsr(int reg, ARMWord value)
605         {
606             ASSERT(reg <= ARMRegisters::pc);
607             ASSERT(value <= 0x1f);
608             return reg | (value << 7) | 0x20;
609         }
610 
asr(int reg,ARMWord value)611         static ARMWord asr(int reg, ARMWord value)
612         {
613             ASSERT(reg <= ARMRegisters::pc);
614             ASSERT(value <= 0x1f);
615             return reg | (value << 7) | 0x40;
616         }
617 
lsl_r(int reg,int shiftReg)618         static ARMWord lsl_r(int reg, int shiftReg)
619         {
620             ASSERT(reg <= ARMRegisters::pc);
621             ASSERT(shiftReg <= ARMRegisters::pc);
622             return reg | (shiftReg << 8) | 0x10;
623         }
624 
lsr_r(int reg,int shiftReg)625         static ARMWord lsr_r(int reg, int shiftReg)
626         {
627             ASSERT(reg <= ARMRegisters::pc);
628             ASSERT(shiftReg <= ARMRegisters::pc);
629             return reg | (shiftReg << 8) | 0x30;
630         }
631 
asr_r(int reg,int shiftReg)632         static ARMWord asr_r(int reg, int shiftReg)
633         {
634             ASSERT(reg <= ARMRegisters::pc);
635             ASSERT(shiftReg <= ARMRegisters::pc);
636             return reg | (shiftReg << 8) | 0x50;
637         }
638 
639         // General helpers
640 
codeSize()641         size_t codeSize() const
642         {
643             return m_buffer.codeSize();
644         }
645 
ensureSpace(int insnSpace,int constSpace)646         void ensureSpace(int insnSpace, int constSpace)
647         {
648             m_buffer.ensureSpace(insnSpace, constSpace);
649         }
650 
sizeOfConstantPool()651         int sizeOfConstantPool()
652         {
653             return m_buffer.sizeOfConstantPool();
654         }
655 
label()656         AssemblerLabel label()
657         {
658             m_buffer.ensureSpaceForAnyOneInstruction();
659             return m_buffer.label();
660         }
661 
align(int alignment)662         AssemblerLabel align(int alignment)
663         {
664             while (!m_buffer.isAligned(alignment))
665                 mov_r(ARMRegisters::r0, ARMRegisters::r0);
666 
667             return label();
668         }
669 
670         AssemblerLabel loadBranchTarget(int rd, Condition cc = AL, int useConstantPool = 0)
671         {
672             ensureSpace(sizeof(ARMWord), sizeof(ARMWord));
673             m_jumps.append(m_buffer.codeSize() | (useConstantPool & 0x1));
674             ldr_un_imm(rd, InvalidBranchTarget, cc);
675             return m_buffer.label();
676         }
677 
678         AssemblerLabel jmp(Condition cc = AL, int useConstantPool = 0)
679         {
680             return loadBranchTarget(ARMRegisters::pc, cc, useConstantPool);
681         }
682 
683         void* executableCopy(ExecutablePool* allocator);
684 
685 #ifndef NDEBUG
debugOffset()686         unsigned debugOffset() { return m_buffer.debugOffset(); }
687 #endif
688 
689         // Patching helpers
690 
getLdrImmAddress(ARMWord * insn)691         static ARMWord* getLdrImmAddress(ARMWord* insn)
692         {
693 #if WTF_ARM_ARCH_AT_LEAST(5)
694             // Check for call
695             if ((*insn & 0x0f7f0000) != 0x051f0000) {
696                 // Must be BLX
697                 ASSERT((*insn & 0x012fff30) == 0x012fff30);
698                 insn--;
699             }
700 #endif
701             // Must be an ldr ..., [pc +/- imm]
702             ASSERT((*insn & 0x0f7f0000) == 0x051f0000);
703 
704             ARMWord addr = reinterpret_cast<ARMWord>(insn) + DefaultPrefetching * sizeof(ARMWord);
705             if (*insn & DT_UP)
706                 return reinterpret_cast<ARMWord*>(addr + (*insn & SDT_OFFSET_MASK));
707             return reinterpret_cast<ARMWord*>(addr - (*insn & SDT_OFFSET_MASK));
708         }
709 
getLdrImmAddressOnPool(ARMWord * insn,uint32_t * constPool)710         static ARMWord* getLdrImmAddressOnPool(ARMWord* insn, uint32_t* constPool)
711         {
712             // Must be an ldr ..., [pc +/- imm]
713             ASSERT((*insn & 0x0f7f0000) == 0x051f0000);
714 
715             if (*insn & 0x1)
716                 return reinterpret_cast<ARMWord*>(constPool + ((*insn & SDT_OFFSET_MASK) >> 1));
717             return getLdrImmAddress(insn);
718         }
719 
patchPointerInternal(intptr_t from,void * to)720         static void patchPointerInternal(intptr_t from, void* to)
721         {
722             ARMWord* insn = reinterpret_cast<ARMWord*>(from);
723             ARMWord* addr = getLdrImmAddress(insn);
724             *addr = reinterpret_cast<ARMWord>(to);
725         }
726 
patchConstantPoolLoad(ARMWord load,ARMWord value)727         static ARMWord patchConstantPoolLoad(ARMWord load, ARMWord value)
728         {
729             value = (value << 1) + 1;
730             ASSERT(!(value & ~0xfff));
731             return (load & ~0xfff) | value;
732         }
733 
734         static void patchConstantPoolLoad(void* loadAddr, void* constPoolAddr);
735 
736         // Patch pointers
737 
linkPointer(void * code,AssemblerLabel from,void * to)738         static void linkPointer(void* code, AssemblerLabel from, void* to)
739         {
740             patchPointerInternal(reinterpret_cast<intptr_t>(code) + from.m_offset, to);
741         }
742 
repatchInt32(void * from,int32_t to)743         static void repatchInt32(void* from, int32_t to)
744         {
745             patchPointerInternal(reinterpret_cast<intptr_t>(from), reinterpret_cast<void*>(to));
746         }
747 
repatchPointer(void * from,void * to)748         static void repatchPointer(void* from, void* to)
749         {
750             patchPointerInternal(reinterpret_cast<intptr_t>(from), to);
751         }
752 
753         // Linkers
754         static intptr_t getAbsoluteJumpAddress(void* base, int offset = 0)
755         {
756             return reinterpret_cast<intptr_t>(base) + offset - sizeof(ARMWord);
757         }
758 
linkJump(AssemblerLabel from,AssemblerLabel to)759         void linkJump(AssemblerLabel from, AssemblerLabel to)
760         {
761             ARMWord* insn = reinterpret_cast<ARMWord*>(getAbsoluteJumpAddress(m_buffer.data(), from.m_offset));
762             ARMWord* addr = getLdrImmAddressOnPool(insn, m_buffer.poolAddress());
763             *addr = static_cast<ARMWord>(to.m_offset);
764         }
765 
linkJump(void * code,AssemblerLabel from,void * to)766         static void linkJump(void* code, AssemblerLabel from, void* to)
767         {
768             patchPointerInternal(getAbsoluteJumpAddress(code, from.m_offset), to);
769         }
770 
relinkJump(void * from,void * to)771         static void relinkJump(void* from, void* to)
772         {
773             patchPointerInternal(getAbsoluteJumpAddress(from), to);
774         }
775 
linkCall(void * code,AssemblerLabel from,void * to)776         static void linkCall(void* code, AssemblerLabel from, void* to)
777         {
778             patchPointerInternal(getAbsoluteJumpAddress(code, from.m_offset), to);
779         }
780 
relinkCall(void * from,void * to)781         static void relinkCall(void* from, void* to)
782         {
783             patchPointerInternal(getAbsoluteJumpAddress(from), to);
784         }
785 
786         // Address operations
787 
getRelocatedAddress(void * code,AssemblerLabel label)788         static void* getRelocatedAddress(void* code, AssemblerLabel label)
789         {
790             return reinterpret_cast<void*>(reinterpret_cast<char*>(code) + label.m_offset);
791         }
792 
793         // Address differences
794 
getDifferenceBetweenLabels(AssemblerLabel a,AssemblerLabel b)795         static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b)
796         {
797             return b.m_offset - a.m_offset;
798         }
799 
getCallReturnOffset(AssemblerLabel call)800         static unsigned getCallReturnOffset(AssemblerLabel call)
801         {
802             return call.m_offset;
803         }
804 
805         // Handle immediates
806 
getOp2Byte(ARMWord imm)807         static ARMWord getOp2Byte(ARMWord imm)
808         {
809             ASSERT(imm <= 0xff);
810             return OP2_IMMh | (imm & 0x0f) | ((imm & 0xf0) << 4) ;
811         }
812 
813         static ARMWord getOp2(ARMWord imm);
814 
815 #if WTF_ARM_ARCH_AT_LEAST(7)
getImm16Op2(ARMWord imm)816         static ARMWord getImm16Op2(ARMWord imm)
817         {
818             if (imm <= 0xffff)
819                 return (imm & 0xf000) << 4 | (imm & 0xfff);
820             return INVALID_IMM;
821         }
822 #endif
823         ARMWord getImm(ARMWord imm, int tmpReg, bool invert = false);
824         void moveImm(ARMWord imm, int dest);
825         ARMWord encodeComplexImm(ARMWord imm, int dest);
826 
getOffsetForHalfwordDataTransfer(ARMWord imm,int tmpReg)827         ARMWord getOffsetForHalfwordDataTransfer(ARMWord imm, int tmpReg)
828         {
829             // Encode immediate data in the instruction if it is possible
830             if (imm <= 0xff)
831                 return getOp2Byte(imm);
832             // Otherwise, store the data in a temporary register
833             return encodeComplexImm(imm, tmpReg);
834         }
835 
836         // Memory load/store helpers
837 
838         void dataTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset, bool bytes = false);
839         void baseIndexTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset);
840         void doubleTransfer(bool isLoad, FPRegisterID srcDst, RegisterID base, int32_t offset);
841 
842         // Constant pool hnadlers
843 
placeConstantPoolBarrier(int offset)844         static ARMWord placeConstantPoolBarrier(int offset)
845         {
846             offset = (offset - sizeof(ARMWord)) >> 2;
847             ASSERT((offset <= BOFFSET_MAX && offset >= BOFFSET_MIN));
848             return AL | B | (offset & BRANCH_MASK);
849         }
850 
851     private:
RM(int reg)852         ARMWord RM(int reg)
853         {
854             ASSERT(reg <= ARMRegisters::pc);
855             return reg;
856         }
857 
RS(int reg)858         ARMWord RS(int reg)
859         {
860             ASSERT(reg <= ARMRegisters::pc);
861             return reg << 8;
862         }
863 
RD(int reg)864         ARMWord RD(int reg)
865         {
866             ASSERT(reg <= ARMRegisters::pc);
867             return reg << 12;
868         }
869 
RN(int reg)870         ARMWord RN(int reg)
871         {
872             ASSERT(reg <= ARMRegisters::pc);
873             return reg << 16;
874         }
875 
getConditionalField(ARMWord i)876         static ARMWord getConditionalField(ARMWord i)
877         {
878             return i & 0xf0000000;
879         }
880 
881         int genInt(int reg, ARMWord imm, bool positive);
882 
883         ARMBuffer m_buffer;
884         Jumps m_jumps;
885     };
886 
887 } // namespace JSC
888 
889 #endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
890 
891 #endif // ARMAssembler_h
892