]> git.saurik.com Git - apple/javascriptcore.git/blame - assembler/ARMAssembler.cpp
JavaScriptCore-1097.13.tar.gz
[apple/javascriptcore.git] / assembler / ARMAssembler.cpp
CommitLineData
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
33namespace JSC {
34
35// Patching helpers
36
37void 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
54ARMWord 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
91int 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
200ARMWord 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
220void 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
240ARMWord 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
4e4e5a6f 265void ARMAssembler::dataTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset, bool bytes)
f9bf01c6 266{
4e4e5a6f 267 ARMWord transferFlag = bytes ? DT_BYTE : 0;
f9bf01c6
A
268 if (offset >= 0) {
269 if (offset <= 0xfff)
4e4e5a6f 270 dtr_u(isLoad, srcDst, base, offset | transferFlag);
f9bf01c6
A
271 else if (offset <= 0xfffff) {
272 add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8));
4e4e5a6f 273 dtr_u(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff) | transferFlag);
f9bf01c6 274 } else {
14957cd0
A
275 moveImm(offset, ARMRegisters::S0);
276 dtr_ur(isLoad, srcDst, base, ARMRegisters::S0 | transferFlag);
f9bf01c6
A
277 }
278 } else {
6fe7ccc8
A
279 if (offset >= -0xfff)
280 dtr_d(isLoad, srcDst, base, -offset | transferFlag);
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) | transferFlag);
f9bf01c6 284 } else {
14957cd0 285 moveImm(offset, ARMRegisters::S0);
6fe7ccc8 286 dtr_ur(isLoad, srcDst, base, ARMRegisters::S0 | transferFlag);
f9bf01c6
A
287 }
288 }
289}
290
6fe7ccc8 291void ARMAssembler::baseIndexTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset, bool bytes)
f9bf01c6
A
292{
293 ARMWord op2;
6fe7ccc8 294 ARMWord transferFlag = bytes ? DT_BYTE : 0;
f9bf01c6
A
295
296 ASSERT(scale >= 0 && scale <= 3);
297 op2 = lsl(index, scale);
298
299 if (offset >= 0 && offset <= 0xfff) {
300 add_r(ARMRegisters::S0, base, op2);
6fe7ccc8 301 dtr_u(isLoad, srcDst, ARMRegisters::S0, offset | transferFlag);
f9bf01c6
A
302 return;
303 }
304 if (offset <= 0 && offset >= -0xfff) {
305 add_r(ARMRegisters::S0, base, op2);
6fe7ccc8 306 dtr_d(isLoad, srcDst, ARMRegisters::S0, (-offset & 0xfff) | transferFlag);
f9bf01c6
A
307 return;
308 }
309
310 ldr_un_imm(ARMRegisters::S0, offset);
311 add_r(ARMRegisters::S0, ARMRegisters::S0, op2);
6fe7ccc8 312 dtr_ur(isLoad, srcDst, base, ARMRegisters::S0 | transferFlag);
f9bf01c6
A
313}
314
315void ARMAssembler::doubleTransfer(bool isLoad, FPRegisterID srcDst, RegisterID base, int32_t offset)
316{
6fe7ccc8
A
317 // VFP cannot directly access memory that is not four-byte-aligned
318 if (!(offset & 0x3)) {
f9bf01c6
A
319 if (offset <= 0x3ff && offset >= 0) {
320 fdtr_u(isLoad, srcDst, base, offset >> 2);
321 return;
322 }
323 if (offset <= 0x3ffff && offset >= 0) {
324 add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 10) | (11 << 8));
325 fdtr_u(isLoad, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff);
326 return;
327 }
328 offset = -offset;
329
330 if (offset <= 0x3ff && offset >= 0) {
331 fdtr_d(isLoad, srcDst, base, offset >> 2);
332 return;
333 }
334 if (offset <= 0x3ffff && offset >= 0) {
335 sub_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 10) | (11 << 8));
336 fdtr_d(isLoad, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff);
337 return;
338 }
339 offset = -offset;
340 }
341
342 ldr_un_imm(ARMRegisters::S0, offset);
343 add_r(ARMRegisters::S0, ARMRegisters::S0, base);
344 fdtr_u(isLoad, srcDst, ARMRegisters::S0, 0);
345}
346
6fe7ccc8 347PassRefPtr<ExecutableMemoryHandle> ARMAssembler::executableCopy(JSGlobalData& globalData, void* ownerUID, JITCompilationEffort effort)
f9bf01c6
A
348{
349 // 64-bit alignment is required for next constant pool and JIT code as well
350 m_buffer.flushWithoutBarrier(true);
14957cd0 351 if (!m_buffer.isAligned(8))
f9bf01c6
A
352 bkpt(0);
353
6fe7ccc8
A
354 RefPtr<ExecutableMemoryHandle> result = m_buffer.executableCopy(globalData, ownerUID, effort);
355 char* data = reinterpret_cast<char*>(result->start());
f9bf01c6
A
356
357 for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) {
358 // The last bit is set if the constant must be placed on constant pool.
14957cd0
A
359 int pos = (iter->m_offset) & (~0x1);
360 ARMWord* ldrAddr = reinterpret_cast_ptr<ARMWord*>(data + pos);
f9bf01c6 361 ARMWord* addr = getLdrImmAddress(ldrAddr);
4e4e5a6f 362 if (*addr != InvalidBranchTarget) {
14957cd0
A
363 if (!(iter->m_offset & 1)) {
364 int diff = reinterpret_cast_ptr<ARMWord*>(data + *addr) - (ldrAddr + DefaultPrefetching);
f9bf01c6
A
365
366 if ((diff <= BOFFSET_MAX && diff >= BOFFSET_MIN)) {
367 *ldrAddr = B | getConditionalField(*ldrAddr) | (diff & BRANCH_MASK);
368 continue;
369 }
370 }
371 *addr = reinterpret_cast<ARMWord>(data + *addr);
372 }
373 }
374
6fe7ccc8 375 return result;
f9bf01c6
A
376}
377
6fe7ccc8
A
378#if OS(LINUX) && COMPILER(RVCT)
379
380__asm void ARMAssembler::cacheFlush(void* code, size_t size)
381{
382 ARM
383 push {r7}
384 add r1, r1, r0
385 mov r7, #0xf0000
386 add r7, r7, #0x2
387 mov r2, #0x0
388 svc #0x0
389 pop {r7}
390 bx lr
391}
392
393#endif
394
f9bf01c6
A
395} // namespace JSC
396
397#endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)