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