|
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, |
|
44 S0 = r3, |
|
45 r4, |
|
46 r5, |
|
47 r6, |
|
48 r7, |
|
49 r8, |
|
50 S1 = r8, |
|
51 r9, |
|
52 r10, |
|
53 r11, |
|
54 r12, |
|
55 r13, |
|
56 sp = r13, |
|
57 r14, |
|
58 lr = r14, |
|
59 r15, |
|
60 pc = r15 |
|
61 } RegisterID; |
|
62 |
|
63 typedef enum { |
|
64 d0, |
|
65 d1, |
|
66 d2, |
|
67 d3, |
|
68 SD0 = d3 |
|
69 } FPRegisterID; |
|
70 |
|
71 } // namespace ARMRegisters |
|
72 |
|
73 class ARMAssembler { |
|
74 public: |
|
75 typedef ARMRegisters::RegisterID RegisterID; |
|
76 typedef ARMRegisters::FPRegisterID FPRegisterID; |
|
77 typedef AssemblerBufferWithConstantPool<2048, 4, 4, ARMAssembler> ARMBuffer; |
|
78 typedef SegmentedVector<int, 64> Jumps; |
|
79 |
|
80 ARMAssembler() { } |
|
81 |
|
82 // ARM conditional constants |
|
83 typedef enum { |
|
84 EQ = 0x00000000, // Zero |
|
85 NE = 0x10000000, // Non-zero |
|
86 CS = 0x20000000, |
|
87 CC = 0x30000000, |
|
88 MI = 0x40000000, |
|
89 PL = 0x50000000, |
|
90 VS = 0x60000000, |
|
91 VC = 0x70000000, |
|
92 HI = 0x80000000, |
|
93 LS = 0x90000000, |
|
94 GE = 0xa0000000, |
|
95 LT = 0xb0000000, |
|
96 GT = 0xc0000000, |
|
97 LE = 0xd0000000, |
|
98 AL = 0xe0000000 |
|
99 } Condition; |
|
100 |
|
101 // ARM instruction constants |
|
102 enum { |
|
103 AND = (0x0 << 21), |
|
104 EOR = (0x1 << 21), |
|
105 SUB = (0x2 << 21), |
|
106 RSB = (0x3 << 21), |
|
107 ADD = (0x4 << 21), |
|
108 ADC = (0x5 << 21), |
|
109 SBC = (0x6 << 21), |
|
110 RSC = (0x7 << 21), |
|
111 TST = (0x8 << 21), |
|
112 TEQ = (0x9 << 21), |
|
113 CMP = (0xa << 21), |
|
114 CMN = (0xb << 21), |
|
115 ORR = (0xc << 21), |
|
116 MOV = (0xd << 21), |
|
117 BIC = (0xe << 21), |
|
118 MVN = (0xf << 21), |
|
119 MUL = 0x00000090, |
|
120 MULL = 0x00c00090, |
|
121 FADDD = 0x0e300b00, |
|
122 FDIVD = 0x0e800b00, |
|
123 FSUBD = 0x0e300b40, |
|
124 FMULD = 0x0e200b00, |
|
125 FCMPD = 0x0eb40b40, |
|
126 FSQRTD = 0x0eb10bc0, |
|
127 DTR = 0x05000000, |
|
128 LDRH = 0x00100090, |
|
129 STRH = 0x00000090, |
|
130 STMDB = 0x09200000, |
|
131 LDMIA = 0x08b00000, |
|
132 FDTR = 0x0d000b00, |
|
133 B = 0x0a000000, |
|
134 BL = 0x0b000000, |
|
135 #if WTF_ARM_ARCH_AT_LEAST(5) || defined(__ARM_ARCH_4T__) |
|
136 BX = 0x012fff10, |
|
137 #endif |
|
138 FMSR = 0x0e000a10, |
|
139 FMRS = 0x0e100a10, |
|
140 FSITOD = 0x0eb80bc0, |
|
141 FTOSID = 0x0ebd0b40, |
|
142 FMSTAT = 0x0ef1fa10, |
|
143 #if WTF_ARM_ARCH_AT_LEAST(5) |
|
144 CLZ = 0x016f0f10, |
|
145 BKPT = 0xe120070, |
|
146 BLX = 0x012fff30, |
|
147 #endif |
|
148 #if WTF_ARM_ARCH_AT_LEAST(7) |
|
149 MOVW = 0x03000000, |
|
150 MOVT = 0x03400000, |
|
151 #endif |
|
152 }; |
|
153 |
|
154 enum { |
|
155 OP2_IMM = (1 << 25), |
|
156 OP2_IMMh = (1 << 22), |
|
157 OP2_INV_IMM = (1 << 26), |
|
158 SET_CC = (1 << 20), |
|
159 OP2_OFSREG = (1 << 25), |
|
160 DT_UP = (1 << 23), |
|
161 DT_BYTE = (1 << 22), |
|
162 DT_WB = (1 << 21), |
|
163 // This flag is inlcuded in LDR and STR |
|
164 DT_PRE = (1 << 24), |
|
165 HDT_UH = (1 << 5), |
|
166 DT_LOAD = (1 << 20), |
|
167 }; |
|
168 |
|
169 // Masks of ARM instructions |
|
170 enum { |
|
171 BRANCH_MASK = 0x00ffffff, |
|
172 NONARM = 0xf0000000, |
|
173 SDT_MASK = 0x0c000000, |
|
174 SDT_OFFSET_MASK = 0xfff, |
|
175 }; |
|
176 |
|
177 enum { |
|
178 BOFFSET_MIN = -0x00800000, |
|
179 BOFFSET_MAX = 0x007fffff, |
|
180 SDT = 0x04000000, |
|
181 }; |
|
182 |
|
183 enum { |
|
184 padForAlign8 = 0x00, |
|
185 padForAlign16 = 0x0000, |
|
186 padForAlign32 = 0xee120070, |
|
187 }; |
|
188 |
|
189 static const ARMWord INVALID_IMM = 0xf0000000; |
|
190 static const ARMWord InvalidBranchTarget = 0xffffffff; |
|
191 static const int DefaultPrefetching = 2; |
|
192 |
|
193 class JmpSrc { |
|
194 friend class ARMAssembler; |
|
195 public: |
|
196 JmpSrc() |
|
197 : m_offset(-1) |
|
198 { |
|
199 } |
|
200 |
|
201 private: |
|
202 JmpSrc(int offset) |
|
203 : m_offset(offset) |
|
204 { |
|
205 } |
|
206 |
|
207 int m_offset; |
|
208 }; |
|
209 |
|
210 class JmpDst { |
|
211 friend class ARMAssembler; |
|
212 public: |
|
213 JmpDst() |
|
214 : m_offset(-1) |
|
215 , m_used(false) |
|
216 { |
|
217 } |
|
218 |
|
219 bool isUsed() const { return m_used; } |
|
220 void used() { m_used = true; } |
|
221 private: |
|
222 JmpDst(int offset) |
|
223 : m_offset(offset) |
|
224 , m_used(false) |
|
225 { |
|
226 ASSERT(m_offset == offset); |
|
227 } |
|
228 |
|
229 int m_offset : 31; |
|
230 int m_used : 1; |
|
231 }; |
|
232 |
|
233 // Instruction formating |
|
234 |
|
235 void emitInst(ARMWord op, int rd, int rn, ARMWord op2) |
|
236 { |
|
237 ASSERT ( ((op2 & ~OP2_IMM) <= 0xfff) || (((op2 & ~OP2_IMMh) <= 0xfff)) ); |
|
238 m_buffer.putInt(op | RN(rn) | RD(rd) | op2); |
|
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 orr_r(int rd, int rn, ARMWord op2, Condition cc = AL) |
|
337 { |
|
338 emitInst(static_cast<ARMWord>(cc) | ORR, rd, rn, op2); |
|
339 } |
|
340 |
|
341 void orrs_r(int rd, int rn, ARMWord op2, Condition cc = AL) |
|
342 { |
|
343 emitInst(static_cast<ARMWord>(cc) | ORR | SET_CC, rd, rn, op2); |
|
344 } |
|
345 |
|
346 void mov_r(int rd, ARMWord op2, Condition cc = AL) |
|
347 { |
|
348 emitInst(static_cast<ARMWord>(cc) | MOV, rd, ARMRegisters::r0, op2); |
|
349 } |
|
350 |
|
351 #if WTF_ARM_ARCH_AT_LEAST(7) |
|
352 void movw_r(int rd, ARMWord op2, Condition cc = AL) |
|
353 { |
|
354 ASSERT((op2 | 0xf0fff) == 0xf0fff); |
|
355 m_buffer.putInt(static_cast<ARMWord>(cc) | MOVW | RD(rd) | op2); |
|
356 } |
|
357 |
|
358 void movt_r(int rd, ARMWord op2, Condition cc = AL) |
|
359 { |
|
360 ASSERT((op2 | 0xf0fff) == 0xf0fff); |
|
361 m_buffer.putInt(static_cast<ARMWord>(cc) | MOVT | RD(rd) | op2); |
|
362 } |
|
363 #endif |
|
364 |
|
365 void movs_r(int rd, ARMWord op2, Condition cc = AL) |
|
366 { |
|
367 emitInst(static_cast<ARMWord>(cc) | MOV | SET_CC, rd, ARMRegisters::r0, op2); |
|
368 } |
|
369 |
|
370 void bic_r(int rd, int rn, ARMWord op2, Condition cc = AL) |
|
371 { |
|
372 emitInst(static_cast<ARMWord>(cc) | BIC, rd, rn, op2); |
|
373 } |
|
374 |
|
375 void bics_r(int rd, int rn, ARMWord op2, Condition cc = AL) |
|
376 { |
|
377 emitInst(static_cast<ARMWord>(cc) | BIC | SET_CC, rd, rn, op2); |
|
378 } |
|
379 |
|
380 void mvn_r(int rd, ARMWord op2, Condition cc = AL) |
|
381 { |
|
382 emitInst(static_cast<ARMWord>(cc) | MVN, rd, ARMRegisters::r0, op2); |
|
383 } |
|
384 |
|
385 void mvns_r(int rd, ARMWord op2, Condition cc = AL) |
|
386 { |
|
387 emitInst(static_cast<ARMWord>(cc) | MVN | SET_CC, rd, ARMRegisters::r0, op2); |
|
388 } |
|
389 |
|
390 void mul_r(int rd, int rn, int rm, Condition cc = AL) |
|
391 { |
|
392 m_buffer.putInt(static_cast<ARMWord>(cc) | MUL | RN(rd) | RS(rn) | RM(rm)); |
|
393 } |
|
394 |
|
395 void muls_r(int rd, int rn, int rm, Condition cc = AL) |
|
396 { |
|
397 m_buffer.putInt(static_cast<ARMWord>(cc) | MUL | SET_CC | RN(rd) | RS(rn) | RM(rm)); |
|
398 } |
|
399 |
|
400 void mull_r(int rdhi, int rdlo, int rn, int rm, Condition cc = AL) |
|
401 { |
|
402 m_buffer.putInt(static_cast<ARMWord>(cc) | MULL | RN(rdhi) | RD(rdlo) | RS(rn) | RM(rm)); |
|
403 } |
|
404 |
|
405 void faddd_r(int dd, int dn, int dm, Condition cc = AL) |
|
406 { |
|
407 emitInst(static_cast<ARMWord>(cc) | FADDD, dd, dn, dm); |
|
408 } |
|
409 |
|
410 void fdivd_r(int dd, int dn, int dm, Condition cc = AL) |
|
411 { |
|
412 emitInst(static_cast<ARMWord>(cc) | FDIVD, dd, dn, dm); |
|
413 } |
|
414 |
|
415 void fsubd_r(int dd, int dn, int dm, Condition cc = AL) |
|
416 { |
|
417 emitInst(static_cast<ARMWord>(cc) | FSUBD, dd, dn, dm); |
|
418 } |
|
419 |
|
420 void fmuld_r(int dd, int dn, int dm, Condition cc = AL) |
|
421 { |
|
422 emitInst(static_cast<ARMWord>(cc) | FMULD, dd, dn, dm); |
|
423 } |
|
424 |
|
425 void fcmpd_r(int dd, int dm, Condition cc = AL) |
|
426 { |
|
427 emitInst(static_cast<ARMWord>(cc) | FCMPD, dd, 0, dm); |
|
428 } |
|
429 |
|
430 void fsqrtd_r(int dd, int dm, Condition cc = AL) |
|
431 { |
|
432 emitInst(static_cast<ARMWord>(cc) | FSQRTD, dd, 0, dm); |
|
433 } |
|
434 |
|
435 void ldr_imm(int rd, ARMWord imm, Condition cc = AL) |
|
436 { |
|
437 m_buffer.putIntWithConstantInt(static_cast<ARMWord>(cc) | DTR | DT_LOAD | DT_UP | RN(ARMRegisters::pc) | RD(rd), imm, true); |
|
438 } |
|
439 |
|
440 void ldr_un_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); |
|
443 } |
|
444 |
|
445 void dtr_u(bool isLoad, int rd, int rb, ARMWord op2, Condition cc = AL) |
|
446 { |
|
447 emitInst(static_cast<ARMWord>(cc) | DTR | (isLoad ? DT_LOAD : 0) | DT_UP, rd, rb, op2); |
|
448 } |
|
449 |
|
450 void dtr_ur(bool isLoad, int rd, int rb, int rm, Condition cc = AL) |
|
451 { |
|
452 emitInst(static_cast<ARMWord>(cc) | DTR | (isLoad ? DT_LOAD : 0) | DT_UP | OP2_OFSREG, rd, rb, rm); |
|
453 } |
|
454 |
|
455 void dtr_d(bool isLoad, int rd, int rb, ARMWord op2, Condition cc = AL) |
|
456 { |
|
457 emitInst(static_cast<ARMWord>(cc) | DTR | (isLoad ? DT_LOAD : 0), rd, rb, op2); |
|
458 } |
|
459 |
|
460 void dtr_dr(bool isLoad, int rd, int rb, int rm, Condition cc = AL) |
|
461 { |
|
462 emitInst(static_cast<ARMWord>(cc) | DTR | (isLoad ? DT_LOAD : 0) | OP2_OFSREG, rd, rb, rm); |
|
463 } |
|
464 |
|
465 void ldrh_r(int rd, int rn, int rm, Condition cc = AL) |
|
466 { |
|
467 emitInst(static_cast<ARMWord>(cc) | LDRH | HDT_UH | DT_UP | DT_PRE, rd, rn, rm); |
|
468 } |
|
469 |
|
470 void ldrh_d(int rd, int rb, ARMWord op2, Condition cc = AL) |
|
471 { |
|
472 emitInst(static_cast<ARMWord>(cc) | LDRH | HDT_UH | DT_PRE, rd, rb, op2); |
|
473 } |
|
474 |
|
475 void ldrh_u(int rd, int rb, ARMWord op2, Condition cc = AL) |
|
476 { |
|
477 emitInst(static_cast<ARMWord>(cc) | LDRH | HDT_UH | DT_UP | DT_PRE, rd, rb, op2); |
|
478 } |
|
479 |
|
480 void strh_r(int rn, int rm, int rd, Condition cc = AL) |
|
481 { |
|
482 emitInst(static_cast<ARMWord>(cc) | STRH | HDT_UH | DT_UP | DT_PRE, rd, rn, rm); |
|
483 } |
|
484 |
|
485 void fdtr_u(bool isLoad, int rd, int rb, ARMWord op2, Condition cc = AL) |
|
486 { |
|
487 ASSERT(op2 <= 0xff); |
|
488 emitInst(static_cast<ARMWord>(cc) | FDTR | DT_UP | (isLoad ? DT_LOAD : 0), rd, rb, op2); |
|
489 } |
|
490 |
|
491 void fdtr_d(bool isLoad, int rd, int rb, ARMWord op2, Condition cc = AL) |
|
492 { |
|
493 ASSERT(op2 <= 0xff); |
|
494 emitInst(static_cast<ARMWord>(cc) | FDTR | (isLoad ? DT_LOAD : 0), rd, rb, op2); |
|
495 } |
|
496 |
|
497 void push_r(int reg, Condition cc = AL) |
|
498 { |
|
499 ASSERT(ARMWord(reg) <= 0xf); |
|
500 m_buffer.putInt(cc | DTR | DT_WB | RN(ARMRegisters::sp) | RD(reg) | 0x4); |
|
501 } |
|
502 |
|
503 void pop_r(int reg, Condition cc = AL) |
|
504 { |
|
505 ASSERT(ARMWord(reg) <= 0xf); |
|
506 m_buffer.putInt(cc | (DTR ^ DT_PRE) | DT_LOAD | DT_UP | RN(ARMRegisters::sp) | RD(reg) | 0x4); |
|
507 } |
|
508 |
|
509 inline void poke_r(int reg, Condition cc = AL) |
|
510 { |
|
511 dtr_d(false, ARMRegisters::sp, 0, reg, cc); |
|
512 } |
|
513 |
|
514 inline void peek_r(int reg, Condition cc = AL) |
|
515 { |
|
516 dtr_u(true, reg, ARMRegisters::sp, 0, cc); |
|
517 } |
|
518 |
|
519 void fmsr_r(int dd, int rn, Condition cc = AL) |
|
520 { |
|
521 emitInst(static_cast<ARMWord>(cc) | FMSR, rn, dd, 0); |
|
522 } |
|
523 |
|
524 void fmrs_r(int rd, int dn, Condition cc = AL) |
|
525 { |
|
526 emitInst(static_cast<ARMWord>(cc) | FMRS, rd, dn, 0); |
|
527 } |
|
528 |
|
529 void fsitod_r(int dd, int dm, Condition cc = AL) |
|
530 { |
|
531 emitInst(static_cast<ARMWord>(cc) | FSITOD, dd, 0, dm); |
|
532 } |
|
533 |
|
534 void ftosid_r(int fd, int dm, Condition cc = AL) |
|
535 { |
|
536 emitInst(static_cast<ARMWord>(cc) | FTOSID, fd, 0, dm); |
|
537 } |
|
538 |
|
539 void fmstat(Condition cc = AL) |
|
540 { |
|
541 m_buffer.putInt(static_cast<ARMWord>(cc) | FMSTAT); |
|
542 } |
|
543 |
|
544 #if WTF_ARM_ARCH_AT_LEAST(5) |
|
545 void clz_r(int rd, int rm, Condition cc = AL) |
|
546 { |
|
547 m_buffer.putInt(static_cast<ARMWord>(cc) | CLZ | RD(rd) | RM(rm)); |
|
548 } |
|
549 #endif |
|
550 |
|
551 void bkpt(ARMWord value) |
|
552 { |
|
553 #if WTF_ARM_ARCH_AT_LEAST(5) |
|
554 m_buffer.putInt(BKPT | ((value & 0xff0) << 4) | (value & 0xf)); |
|
555 #else |
|
556 // Cannot access to Zero memory address |
|
557 dtr_dr(true, ARMRegisters::S0, ARMRegisters::S0, ARMRegisters::S0); |
|
558 #endif |
|
559 } |
|
560 |
|
561 void bx(int rm, Condition cc = AL) |
|
562 { |
|
563 #if WTF_ARM_ARCH_AT_LEAST(5) || defined(__ARM_ARCH_4T__) |
|
564 emitInst(static_cast<ARMWord>(cc) | BX, 0, 0, RM(rm)); |
|
565 #else |
|
566 mov_r(ARMRegisters::pc, RM(rm), cc); |
|
567 #endif |
|
568 } |
|
569 |
|
570 JmpSrc blx(int rm, Condition cc = AL) |
|
571 { |
|
572 #if WTF_ARM_ARCH_AT_LEAST(5) |
|
573 int s = m_buffer.uncheckedSize(); |
|
574 emitInst(static_cast<ARMWord>(cc) | BLX, 0, 0, RM(rm)); |
|
575 #else |
|
576 ASSERT(rm != 14); |
|
577 ensureSpace(2 * sizeof(ARMWord), 0); |
|
578 mov_r(ARMRegisters::lr, ARMRegisters::pc, cc); |
|
579 int s = m_buffer.uncheckedSize(); |
|
580 bx(rm, cc); |
|
581 #endif |
|
582 return JmpSrc(s); |
|
583 } |
|
584 |
|
585 static ARMWord lsl(int reg, ARMWord value) |
|
586 { |
|
587 ASSERT(reg <= ARMRegisters::pc); |
|
588 ASSERT(value <= 0x1f); |
|
589 return reg | (value << 7) | 0x00; |
|
590 } |
|
591 |
|
592 static ARMWord lsr(int reg, ARMWord value) |
|
593 { |
|
594 ASSERT(reg <= ARMRegisters::pc); |
|
595 ASSERT(value <= 0x1f); |
|
596 return reg | (value << 7) | 0x20; |
|
597 } |
|
598 |
|
599 static ARMWord asr(int reg, ARMWord value) |
|
600 { |
|
601 ASSERT(reg <= ARMRegisters::pc); |
|
602 ASSERT(value <= 0x1f); |
|
603 return reg | (value << 7) | 0x40; |
|
604 } |
|
605 |
|
606 static ARMWord lsl_r(int reg, int shiftReg) |
|
607 { |
|
608 ASSERT(reg <= ARMRegisters::pc); |
|
609 ASSERT(shiftReg <= ARMRegisters::pc); |
|
610 return reg | (shiftReg << 8) | 0x10; |
|
611 } |
|
612 |
|
613 static ARMWord lsr_r(int reg, int shiftReg) |
|
614 { |
|
615 ASSERT(reg <= ARMRegisters::pc); |
|
616 ASSERT(shiftReg <= ARMRegisters::pc); |
|
617 return reg | (shiftReg << 8) | 0x30; |
|
618 } |
|
619 |
|
620 static ARMWord asr_r(int reg, int shiftReg) |
|
621 { |
|
622 ASSERT(reg <= ARMRegisters::pc); |
|
623 ASSERT(shiftReg <= ARMRegisters::pc); |
|
624 return reg | (shiftReg << 8) | 0x50; |
|
625 } |
|
626 |
|
627 // General helpers |
|
628 |
|
629 int size() |
|
630 { |
|
631 return m_buffer.size(); |
|
632 } |
|
633 |
|
634 void ensureSpace(int insnSpace, int constSpace) |
|
635 { |
|
636 m_buffer.ensureSpace(insnSpace, constSpace); |
|
637 } |
|
638 |
|
639 int sizeOfConstantPool() |
|
640 { |
|
641 return m_buffer.sizeOfConstantPool(); |
|
642 } |
|
643 |
|
644 JmpDst label() |
|
645 { |
|
646 return JmpDst(m_buffer.size()); |
|
647 } |
|
648 |
|
649 JmpDst align(int alignment) |
|
650 { |
|
651 while (!m_buffer.isAligned(alignment)) |
|
652 mov_r(ARMRegisters::r0, ARMRegisters::r0); |
|
653 |
|
654 return label(); |
|
655 } |
|
656 |
|
657 JmpSrc loadBranchTarget(int rd, Condition cc = AL, int useConstantPool = 0) |
|
658 { |
|
659 ensureSpace(sizeof(ARMWord), sizeof(ARMWord)); |
|
660 int s = m_buffer.uncheckedSize(); |
|
661 ldr_un_imm(rd, InvalidBranchTarget, cc); |
|
662 m_jumps.append(s | (useConstantPool & 0x1)); |
|
663 return JmpSrc(s); |
|
664 } |
|
665 |
|
666 JmpSrc jmp(Condition cc = AL, int useConstantPool = 0) |
|
667 { |
|
668 return loadBranchTarget(ARMRegisters::pc, cc, useConstantPool); |
|
669 } |
|
670 |
|
671 void* executableCopy(ExecutablePool* allocator); |
|
672 |
|
673 // Patching helpers |
|
674 |
|
675 static ARMWord* getLdrImmAddress(ARMWord* insn) |
|
676 { |
|
677 #if WTF_ARM_ARCH_AT_LEAST(5) |
|
678 // Check for call |
|
679 if ((*insn & 0x0f7f0000) != 0x051f0000) { |
|
680 // Must be BLX |
|
681 ASSERT((*insn & 0x012fff30) == 0x012fff30); |
|
682 insn--; |
|
683 } |
|
684 #endif |
|
685 // Must be an ldr ..., [pc +/- imm] |
|
686 ASSERT((*insn & 0x0f7f0000) == 0x051f0000); |
|
687 |
|
688 ARMWord addr = reinterpret_cast<ARMWord>(insn) + DefaultPrefetching * sizeof(ARMWord); |
|
689 if (*insn & DT_UP) |
|
690 return reinterpret_cast<ARMWord*>(addr + (*insn & SDT_OFFSET_MASK)); |
|
691 return reinterpret_cast<ARMWord*>(addr - (*insn & SDT_OFFSET_MASK)); |
|
692 } |
|
693 |
|
694 static ARMWord* getLdrImmAddressOnPool(ARMWord* insn, uint32_t* constPool) |
|
695 { |
|
696 // Must be an ldr ..., [pc +/- imm] |
|
697 ASSERT((*insn & 0x0f7f0000) == 0x051f0000); |
|
698 |
|
699 if (*insn & 0x1) |
|
700 return reinterpret_cast<ARMWord*>(constPool + ((*insn & SDT_OFFSET_MASK) >> 1)); |
|
701 return getLdrImmAddress(insn); |
|
702 } |
|
703 |
|
704 static void patchPointerInternal(intptr_t from, void* to) |
|
705 { |
|
706 ARMWord* insn = reinterpret_cast<ARMWord*>(from); |
|
707 ARMWord* addr = getLdrImmAddress(insn); |
|
708 *addr = reinterpret_cast<ARMWord>(to); |
|
709 } |
|
710 |
|
711 static ARMWord patchConstantPoolLoad(ARMWord load, ARMWord value) |
|
712 { |
|
713 value = (value << 1) + 1; |
|
714 ASSERT(!(value & ~0xfff)); |
|
715 return (load & ~0xfff) | value; |
|
716 } |
|
717 |
|
718 static void patchConstantPoolLoad(void* loadAddr, void* constPoolAddr); |
|
719 |
|
720 // Patch pointers |
|
721 |
|
722 static void linkPointer(void* code, JmpDst from, void* to) |
|
723 { |
|
724 patchPointerInternal(reinterpret_cast<intptr_t>(code) + from.m_offset, to); |
|
725 } |
|
726 |
|
727 static void repatchInt32(void* from, int32_t to) |
|
728 { |
|
729 patchPointerInternal(reinterpret_cast<intptr_t>(from), reinterpret_cast<void*>(to)); |
|
730 } |
|
731 |
|
732 static void repatchPointer(void* from, void* to) |
|
733 { |
|
734 patchPointerInternal(reinterpret_cast<intptr_t>(from), to); |
|
735 } |
|
736 |
|
737 static void repatchLoadPtrToLEA(void* from) |
|
738 { |
|
739 // On arm, this is a patch from LDR to ADD. It is restricted conversion, |
|
740 // from special case to special case, altough enough for its purpose |
|
741 ARMWord* insn = reinterpret_cast<ARMWord*>(from); |
|
742 ASSERT((*insn & 0x0ff00f00) == 0x05900000); |
|
743 |
|
744 *insn = (*insn & 0xf00ff0ff) | 0x02800000; |
|
745 ExecutableAllocator::cacheFlush(insn, sizeof(ARMWord)); |
|
746 } |
|
747 |
|
748 // Linkers |
|
749 |
|
750 void linkJump(JmpSrc from, JmpDst to) |
|
751 { |
|
752 ARMWord* insn = reinterpret_cast<ARMWord*>(m_buffer.data()) + (from.m_offset / sizeof(ARMWord)); |
|
753 ARMWord* addr = getLdrImmAddressOnPool(insn, m_buffer.poolAddress()); |
|
754 *addr = static_cast<ARMWord>(to.m_offset); |
|
755 } |
|
756 |
|
757 static void linkJump(void* code, JmpSrc from, void* to) |
|
758 { |
|
759 patchPointerInternal(reinterpret_cast<intptr_t>(code) + from.m_offset, to); |
|
760 } |
|
761 |
|
762 static void relinkJump(void* from, void* to) |
|
763 { |
|
764 patchPointerInternal(reinterpret_cast<intptr_t>(from) - sizeof(ARMWord), to); |
|
765 } |
|
766 |
|
767 static void linkCall(void* code, JmpSrc from, void* to) |
|
768 { |
|
769 patchPointerInternal(reinterpret_cast<intptr_t>(code) + from.m_offset, to); |
|
770 } |
|
771 |
|
772 static void relinkCall(void* from, void* to) |
|
773 { |
|
774 patchPointerInternal(reinterpret_cast<intptr_t>(from) - sizeof(ARMWord), to); |
|
775 } |
|
776 |
|
777 // Address operations |
|
778 |
|
779 static void* getRelocatedAddress(void* code, JmpSrc jump) |
|
780 { |
|
781 return reinterpret_cast<void*>(reinterpret_cast<ARMWord*>(code) + jump.m_offset / sizeof(ARMWord) + 1); |
|
782 } |
|
783 |
|
784 static void* getRelocatedAddress(void* code, JmpDst label) |
|
785 { |
|
786 return reinterpret_cast<void*>(reinterpret_cast<ARMWord*>(code) + label.m_offset / sizeof(ARMWord)); |
|
787 } |
|
788 |
|
789 // Address differences |
|
790 |
|
791 static int getDifferenceBetweenLabels(JmpDst from, JmpSrc to) |
|
792 { |
|
793 return (to.m_offset + sizeof(ARMWord)) - from.m_offset; |
|
794 } |
|
795 |
|
796 static int getDifferenceBetweenLabels(JmpDst from, JmpDst to) |
|
797 { |
|
798 return to.m_offset - from.m_offset; |
|
799 } |
|
800 |
|
801 static unsigned getCallReturnOffset(JmpSrc call) |
|
802 { |
|
803 return call.m_offset + sizeof(ARMWord); |
|
804 } |
|
805 |
|
806 // Handle immediates |
|
807 |
|
808 static ARMWord getOp2Byte(ARMWord imm) |
|
809 { |
|
810 ASSERT(imm <= 0xff); |
|
811 return OP2_IMMh | (imm & 0x0f) | ((imm & 0xf0) << 4) ; |
|
812 } |
|
813 |
|
814 static ARMWord getOp2(ARMWord imm); |
|
815 |
|
816 #if WTF_ARM_ARCH_AT_LEAST(7) |
|
817 static ARMWord getImm16Op2(ARMWord imm) |
|
818 { |
|
819 if (imm <= 0xffff) |
|
820 return (imm & 0xf000) << 4 | (imm & 0xfff); |
|
821 return INVALID_IMM; |
|
822 } |
|
823 #endif |
|
824 ARMWord getImm(ARMWord imm, int tmpReg, bool invert = false); |
|
825 void moveImm(ARMWord imm, int dest); |
|
826 ARMWord encodeComplexImm(ARMWord imm, int dest); |
|
827 |
|
828 ARMWord getOffsetForHalfwordDataTransfer(ARMWord imm, int tmpReg) |
|
829 { |
|
830 // Encode immediate data in the instruction if it is possible |
|
831 if (imm <= 0xff) |
|
832 return getOp2Byte(imm); |
|
833 // Otherwise, store the data in a temporary register |
|
834 return encodeComplexImm(imm, tmpReg); |
|
835 } |
|
836 |
|
837 // Memory load/store helpers |
|
838 |
|
839 void dataTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset, bool bytes = false); |
|
840 void baseIndexTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset); |
|
841 void doubleTransfer(bool isLoad, FPRegisterID srcDst, RegisterID base, int32_t offset); |
|
842 |
|
843 // Constant pool hnadlers |
|
844 |
|
845 static ARMWord placeConstantPoolBarrier(int offset) |
|
846 { |
|
847 offset = (offset - sizeof(ARMWord)) >> 2; |
|
848 ASSERT((offset <= BOFFSET_MAX && offset >= BOFFSET_MIN)); |
|
849 return AL | B | (offset & BRANCH_MASK); |
|
850 } |
|
851 |
|
852 private: |
|
853 ARMWord RM(int reg) |
|
854 { |
|
855 ASSERT(reg <= ARMRegisters::pc); |
|
856 return reg; |
|
857 } |
|
858 |
|
859 ARMWord RS(int reg) |
|
860 { |
|
861 ASSERT(reg <= ARMRegisters::pc); |
|
862 return reg << 8; |
|
863 } |
|
864 |
|
865 ARMWord RD(int reg) |
|
866 { |
|
867 ASSERT(reg <= ARMRegisters::pc); |
|
868 return reg << 12; |
|
869 } |
|
870 |
|
871 ARMWord RN(int reg) |
|
872 { |
|
873 ASSERT(reg <= ARMRegisters::pc); |
|
874 return reg << 16; |
|
875 } |
|
876 |
|
877 static ARMWord getConditionalField(ARMWord i) |
|
878 { |
|
879 return i & 0xf0000000; |
|
880 } |
|
881 |
|
882 int genInt(int reg, ARMWord imm, bool positive); |
|
883 |
|
884 ARMBuffer m_buffer; |
|
885 Jumps m_jumps; |
|
886 }; |
|
887 |
|
888 } // namespace JSC |
|
889 |
|
890 #endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) |
|
891 |
|
892 #endif // ARMAssembler_h |