]>
Commit | Line | Data |
---|---|---|
f9bf01c6 A |
1 | /* |
2 | * Copyright (C) 2009 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 | #include "config.h" | |
28 | ||
29 | #if ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) | |
30 | ||
31 | #include "ARMAssembler.h" | |
32 | ||
33 | namespace JSC { | |
34 | ||
35 | // Patching helpers | |
36 | ||
37 | void ARMAssembler::patchConstantPoolLoad(void* loadAddr, void* constPoolAddr) | |
38 | { | |
39 | ARMWord *ldr = reinterpret_cast<ARMWord*>(loadAddr); | |
40 | ARMWord diff = reinterpret_cast<ARMWord*>(constPoolAddr) - ldr; | |
41 | ARMWord index = (*ldr & 0xfff) >> 1; | |
42 | ||
43 | ASSERT(diff >= 1); | |
44 | if (diff >= 2 || index > 0) { | |
45 | diff = (diff + index - 2) * sizeof(ARMWord); | |
46 | ASSERT(diff <= 0xfff); | |
47 | *ldr = (*ldr & ~0xfff) | diff; | |
48 | } else | |
49 | *ldr = (*ldr & ~(0xfff | ARMAssembler::DT_UP)) | sizeof(ARMWord); | |
50 | } | |
51 | ||
52 | // Handle immediates | |
53 | ||
54 | ARMWord ARMAssembler::getOp2(ARMWord imm) | |
55 | { | |
56 | int rol; | |
57 | ||
58 | if (imm <= 0xff) | |
59 | return OP2_IMM | imm; | |
60 | ||
61 | if ((imm & 0xff000000) == 0) { | |
62 | imm <<= 8; | |
63 | rol = 8; | |
64 | } | |
65 | else { | |
66 | imm = (imm << 24) | (imm >> 8); | |
67 | rol = 0; | |
68 | } | |
69 | ||
70 | if ((imm & 0xff000000) == 0) { | |
71 | imm <<= 8; | |
72 | rol += 4; | |
73 | } | |
74 | ||
75 | if ((imm & 0xf0000000) == 0) { | |
76 | imm <<= 4; | |
77 | rol += 2; | |
78 | } | |
79 | ||
80 | if ((imm & 0xc0000000) == 0) { | |
81 | imm <<= 2; | |
82 | rol += 1; | |
83 | } | |
84 | ||
85 | if ((imm & 0x00ffffff) == 0) | |
86 | return OP2_IMM | (imm >> 24) | (rol << 8); | |
87 | ||
88 | return INVALID_IMM; | |
89 | } | |
90 | ||
91 | int ARMAssembler::genInt(int reg, ARMWord imm, bool positive) | |
92 | { | |
93 | // Step1: Search a non-immediate part | |
94 | ARMWord mask; | |
95 | ARMWord imm1; | |
96 | ARMWord imm2; | |
97 | int rol; | |
98 | ||
99 | mask = 0xff000000; | |
100 | rol = 8; | |
101 | while(1) { | |
102 | if ((imm & mask) == 0) { | |
103 | imm = (imm << rol) | (imm >> (32 - rol)); | |
104 | rol = 4 + (rol >> 1); | |
105 | break; | |
106 | } | |
107 | rol += 2; | |
108 | mask >>= 2; | |
109 | if (mask & 0x3) { | |
110 | // rol 8 | |
111 | imm = (imm << 8) | (imm >> 24); | |
112 | mask = 0xff00; | |
113 | rol = 24; | |
114 | while (1) { | |
115 | if ((imm & mask) == 0) { | |
116 | imm = (imm << rol) | (imm >> (32 - rol)); | |
117 | rol = (rol >> 1) - 8; | |
118 | break; | |
119 | } | |
120 | rol += 2; | |
121 | mask >>= 2; | |
122 | if (mask & 0x3) | |
123 | return 0; | |
124 | } | |
125 | break; | |
126 | } | |
127 | } | |
128 | ||
129 | ASSERT((imm & 0xff) == 0); | |
130 | ||
131 | if ((imm & 0xff000000) == 0) { | |
132 | imm1 = OP2_IMM | ((imm >> 16) & 0xff) | (((rol + 4) & 0xf) << 8); | |
133 | imm2 = OP2_IMM | ((imm >> 8) & 0xff) | (((rol + 8) & 0xf) << 8); | |
134 | } else if (imm & 0xc0000000) { | |
135 | imm1 = OP2_IMM | ((imm >> 24) & 0xff) | ((rol & 0xf) << 8); | |
136 | imm <<= 8; | |
137 | rol += 4; | |
138 | ||
139 | if ((imm & 0xff000000) == 0) { | |
140 | imm <<= 8; | |
141 | rol += 4; | |
142 | } | |
143 | ||
144 | if ((imm & 0xf0000000) == 0) { | |
145 | imm <<= 4; | |
146 | rol += 2; | |
147 | } | |
148 | ||
149 | if ((imm & 0xc0000000) == 0) { | |
150 | imm <<= 2; | |
151 | rol += 1; | |
152 | } | |
153 | ||
154 | if ((imm & 0x00ffffff) == 0) | |
155 | imm2 = OP2_IMM | (imm >> 24) | ((rol & 0xf) << 8); | |
156 | else | |
157 | return 0; | |
158 | } else { | |
159 | if ((imm & 0xf0000000) == 0) { | |
160 | imm <<= 4; | |
161 | rol += 2; | |
162 | } | |
163 | ||
164 | if ((imm & 0xc0000000) == 0) { | |
165 | imm <<= 2; | |
166 | rol += 1; | |
167 | } | |
168 | ||
169 | imm1 = OP2_IMM | ((imm >> 24) & 0xff) | ((rol & 0xf) << 8); | |
170 | imm <<= 8; | |
171 | rol += 4; | |
172 | ||
173 | if ((imm & 0xf0000000) == 0) { | |
174 | imm <<= 4; | |
175 | rol += 2; | |
176 | } | |
177 | ||
178 | if ((imm & 0xc0000000) == 0) { | |
179 | imm <<= 2; | |
180 | rol += 1; | |
181 | } | |
182 | ||
183 | if ((imm & 0x00ffffff) == 0) | |
184 | imm2 = OP2_IMM | (imm >> 24) | ((rol & 0xf) << 8); | |
185 | else | |
186 | return 0; | |
187 | } | |
188 | ||
189 | if (positive) { | |
190 | mov_r(reg, imm1); | |
191 | orr_r(reg, reg, imm2); | |
192 | } else { | |
193 | mvn_r(reg, imm1); | |
194 | bic_r(reg, reg, imm2); | |
195 | } | |
196 | ||
197 | return 1; | |
198 | } | |
199 | ||
200 | ARMWord ARMAssembler::getImm(ARMWord imm, int tmpReg, bool invert) | |
201 | { | |
202 | ARMWord tmp; | |
203 | ||
204 | // Do it by 1 instruction | |
205 | tmp = getOp2(imm); | |
206 | if (tmp != INVALID_IMM) | |
207 | return tmp; | |
208 | ||
209 | tmp = getOp2(~imm); | |
210 | if (tmp != INVALID_IMM) { | |
211 | if (invert) | |
212 | return tmp | OP2_INV_IMM; | |
213 | mvn_r(tmpReg, tmp); | |
214 | return tmpReg; | |
215 | } | |
216 | ||
217 | return encodeComplexImm(imm, tmpReg); | |
218 | } | |
219 | ||
220 | void ARMAssembler::moveImm(ARMWord imm, int dest) | |
221 | { | |
222 | ARMWord tmp; | |
223 | ||
224 | // Do it by 1 instruction | |
225 | tmp = getOp2(imm); | |
226 | if (tmp != INVALID_IMM) { | |
227 | mov_r(dest, tmp); | |
228 | return; | |
229 | } | |
230 | ||
231 | tmp = getOp2(~imm); | |
232 | if (tmp != INVALID_IMM) { | |
233 | mvn_r(dest, tmp); | |
234 | return; | |
235 | } | |
236 | ||
237 | encodeComplexImm(imm, dest); | |
238 | } | |
239 | ||
240 | ARMWord ARMAssembler::encodeComplexImm(ARMWord imm, int dest) | |
241 | { | |
242 | #if WTF_ARM_ARCH_AT_LEAST(7) | |
243 | ARMWord tmp = getImm16Op2(imm); | |
244 | if (tmp != INVALID_IMM) { | |
245 | movw_r(dest, tmp); | |
246 | return dest; | |
247 | } | |
248 | movw_r(dest, getImm16Op2(imm & 0xffff)); | |
249 | movt_r(dest, getImm16Op2(imm >> 16)); | |
250 | return dest; | |
251 | #else | |
252 | // Do it by 2 instruction | |
253 | if (genInt(dest, imm, true)) | |
254 | return dest; | |
255 | if (genInt(dest, ~imm, false)) | |
256 | return dest; | |
257 | ||
258 | ldr_imm(dest, imm); | |
259 | return dest; | |
260 | #endif | |
261 | } | |
262 | ||
263 | // Memory load/store helpers | |
264 | ||
265 | void ARMAssembler::dataTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset) | |
266 | { | |
267 | if (offset >= 0) { | |
268 | if (offset <= 0xfff) | |
269 | dtr_u(isLoad, srcDst, base, offset); | |
270 | else if (offset <= 0xfffff) { | |
271 | add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8)); | |
272 | dtr_u(isLoad, srcDst, ARMRegisters::S0, offset & 0xfff); | |
273 | } else { | |
274 | ARMWord reg = getImm(offset, ARMRegisters::S0); | |
275 | dtr_ur(isLoad, srcDst, base, reg); | |
276 | } | |
277 | } else { | |
278 | offset = -offset; | |
279 | if (offset <= 0xfff) | |
280 | dtr_d(isLoad, srcDst, base, offset); | |
281 | else if (offset <= 0xfffff) { | |
282 | sub_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8)); | |
283 | dtr_d(isLoad, srcDst, ARMRegisters::S0, offset & 0xfff); | |
284 | } else { | |
285 | ARMWord reg = getImm(offset, ARMRegisters::S0); | |
286 | dtr_dr(isLoad, srcDst, base, reg); | |
287 | } | |
288 | } | |
289 | } | |
290 | ||
291 | void ARMAssembler::baseIndexTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset) | |
292 | { | |
293 | ARMWord op2; | |
294 | ||
295 | ASSERT(scale >= 0 && scale <= 3); | |
296 | op2 = lsl(index, scale); | |
297 | ||
298 | if (offset >= 0 && offset <= 0xfff) { | |
299 | add_r(ARMRegisters::S0, base, op2); | |
300 | dtr_u(isLoad, srcDst, ARMRegisters::S0, offset); | |
301 | return; | |
302 | } | |
303 | if (offset <= 0 && offset >= -0xfff) { | |
304 | add_r(ARMRegisters::S0, base, op2); | |
305 | dtr_d(isLoad, srcDst, ARMRegisters::S0, -offset); | |
306 | return; | |
307 | } | |
308 | ||
309 | ldr_un_imm(ARMRegisters::S0, offset); | |
310 | add_r(ARMRegisters::S0, ARMRegisters::S0, op2); | |
311 | dtr_ur(isLoad, srcDst, base, ARMRegisters::S0); | |
312 | } | |
313 | ||
314 | void ARMAssembler::doubleTransfer(bool isLoad, FPRegisterID srcDst, RegisterID base, int32_t offset) | |
315 | { | |
316 | if (offset & 0x3) { | |
317 | if (offset <= 0x3ff && offset >= 0) { | |
318 | fdtr_u(isLoad, srcDst, base, offset >> 2); | |
319 | return; | |
320 | } | |
321 | if (offset <= 0x3ffff && offset >= 0) { | |
322 | add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 10) | (11 << 8)); | |
323 | fdtr_u(isLoad, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff); | |
324 | return; | |
325 | } | |
326 | offset = -offset; | |
327 | ||
328 | if (offset <= 0x3ff && offset >= 0) { | |
329 | fdtr_d(isLoad, srcDst, base, offset >> 2); | |
330 | return; | |
331 | } | |
332 | if (offset <= 0x3ffff && offset >= 0) { | |
333 | sub_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 10) | (11 << 8)); | |
334 | fdtr_d(isLoad, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff); | |
335 | return; | |
336 | } | |
337 | offset = -offset; | |
338 | } | |
339 | ||
340 | ldr_un_imm(ARMRegisters::S0, offset); | |
341 | add_r(ARMRegisters::S0, ARMRegisters::S0, base); | |
342 | fdtr_u(isLoad, srcDst, ARMRegisters::S0, 0); | |
343 | } | |
344 | ||
345 | void* ARMAssembler::executableCopy(ExecutablePool* allocator) | |
346 | { | |
347 | // 64-bit alignment is required for next constant pool and JIT code as well | |
348 | m_buffer.flushWithoutBarrier(true); | |
349 | if (m_buffer.uncheckedSize() & 0x7) | |
350 | bkpt(0); | |
351 | ||
352 | char* data = reinterpret_cast<char*>(m_buffer.executableCopy(allocator)); | |
353 | ||
354 | for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) { | |
355 | // The last bit is set if the constant must be placed on constant pool. | |
356 | int pos = (*iter) & (~0x1); | |
357 | ARMWord* ldrAddr = reinterpret_cast<ARMWord*>(data + pos); | |
358 | ARMWord* addr = getLdrImmAddress(ldrAddr); | |
359 | if (*addr != 0xffffffff) { | |
360 | if (!(*iter & 1)) { | |
361 | int diff = reinterpret_cast<ARMWord*>(data + *addr) - (ldrAddr + DefaultPrefetching); | |
362 | ||
363 | if ((diff <= BOFFSET_MAX && diff >= BOFFSET_MIN)) { | |
364 | *ldrAddr = B | getConditionalField(*ldrAddr) | (diff & BRANCH_MASK); | |
365 | continue; | |
366 | } | |
367 | } | |
368 | *addr = reinterpret_cast<ARMWord>(data + *addr); | |
369 | } | |
370 | } | |
371 | ||
372 | return data; | |
373 | } | |
374 | ||
375 | } // namespace JSC | |
376 | ||
377 | #endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) |