]> git.saurik.com Git - apple/javascriptcore.git/blame - assembler/ARMAssembler.cpp
JavaScriptCore-1218.34.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
93a37866 49 *ldr = (*ldr & ~(0xfff | ARMAssembler::DataTransferUp)) | sizeof(ARMWord);
f9bf01c6
A
50}
51
52// Handle immediates
53
54ARMWord ARMAssembler::getOp2(ARMWord imm)
55{
56 int rol;
57
58 if (imm <= 0xff)
93a37866 59 return Op2Immediate | imm;
f9bf01c6
A
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)
93a37866 86 return Op2Immediate | (imm >> 24) | (rol << 8);
f9bf01c6 87
93a37866 88 return InvalidImmediate;
f9bf01c6
A
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) {
93a37866
A
132 imm1 = Op2Immediate | ((imm >> 16) & 0xff) | (((rol + 4) & 0xf) << 8);
133 imm2 = Op2Immediate | ((imm >> 8) & 0xff) | (((rol + 8) & 0xf) << 8);
f9bf01c6 134 } else if (imm & 0xc0000000) {
93a37866 135 imm1 = Op2Immediate | ((imm >> 24) & 0xff) | ((rol & 0xf) << 8);
f9bf01c6
A
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)
93a37866 155 imm2 = Op2Immediate | (imm >> 24) | ((rol & 0xf) << 8);
f9bf01c6
A
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
93a37866 169 imm1 = Op2Immediate | ((imm >> 24) & 0xff) | ((rol & 0xf) << 8);
f9bf01c6
A
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)
93a37866 184 imm2 = Op2Immediate | (imm >> 24) | ((rol & 0xf) << 8);
f9bf01c6
A
185 else
186 return 0;
187 }
188
189 if (positive) {
93a37866
A
190 mov(reg, imm1);
191 orr(reg, reg, imm2);
f9bf01c6 192 } else {
93a37866
A
193 mvn(reg, imm1);
194 bic(reg, reg, imm2);
f9bf01c6
A
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);
93a37866 206 if (tmp != InvalidImmediate)
f9bf01c6
A
207 return tmp;
208
209 tmp = getOp2(~imm);
93a37866 210 if (tmp != InvalidImmediate) {
f9bf01c6 211 if (invert)
93a37866
A
212 return tmp | Op2InvertedImmediate;
213 mvn(tmpReg, tmp);
f9bf01c6
A
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);
93a37866
A
226 if (tmp != InvalidImmediate) {
227 mov(dest, tmp);
f9bf01c6
A
228 return;
229 }
230
231 tmp = getOp2(~imm);
93a37866
A
232 if (tmp != InvalidImmediate) {
233 mvn(dest, tmp);
f9bf01c6
A
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);
93a37866
A
244 if (tmp != InvalidImmediate) {
245 movw(dest, tmp);
f9bf01c6
A
246 return dest;
247 }
93a37866
A
248 movw(dest, getImm16Op2(imm & 0xffff));
249 movt(dest, getImm16Op2(imm >> 16));
f9bf01c6
A
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
93a37866 258 ldrImmediate(dest, imm);
f9bf01c6
A
259 return dest;
260#endif
261}
262
263// Memory load/store helpers
264
93a37866 265void ARMAssembler::dataTransfer32(DataTransferTypeA transferType, RegisterID srcDst, RegisterID base, int32_t offset)
f9bf01c6
A
266{
267 if (offset >= 0) {
268 if (offset <= 0xfff)
93a37866 269 dtrUp(transferType, srcDst, base, offset);
f9bf01c6 270 else if (offset <= 0xfffff) {
93a37866
A
271 add(ARMRegisters::S0, base, Op2Immediate | (offset >> 12) | (10 << 8));
272 dtrUp(transferType, srcDst, ARMRegisters::S0, (offset & 0xfff));
f9bf01c6 273 } else {
14957cd0 274 moveImm(offset, ARMRegisters::S0);
93a37866 275 dtrUpRegister(transferType, srcDst, base, ARMRegisters::S0);
f9bf01c6
A
276 }
277 } else {
6fe7ccc8 278 if (offset >= -0xfff)
93a37866 279 dtrDown(transferType, srcDst, base, -offset);
6fe7ccc8 280 else if (offset >= -0xfffff) {
93a37866
A
281 sub(ARMRegisters::S0, base, Op2Immediate | (-offset >> 12) | (10 << 8));
282 dtrDown(transferType, srcDst, ARMRegisters::S0, (-offset & 0xfff));
f9bf01c6 283 } else {
14957cd0 284 moveImm(offset, ARMRegisters::S0);
93a37866 285 dtrUpRegister(transferType, srcDst, base, ARMRegisters::S0);
f9bf01c6
A
286 }
287 }
288}
289
93a37866 290void ARMAssembler::baseIndexTransfer32(DataTransferTypeA transferType, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset)
f9bf01c6 291{
f9bf01c6 292 ASSERT(scale >= 0 && scale <= 3);
93a37866 293 ARMWord op2 = lsl(index, scale);
f9bf01c6 294
93a37866
A
295 if (!offset) {
296 dtrUpRegister(transferType, srcDst, base, op2);
f9bf01c6
A
297 return;
298 }
93a37866
A
299
300 if (offset <= 0xfffff && offset >= -0xfffff) {
301 add(ARMRegisters::S0, base, op2);
302 dataTransfer32(transferType, srcDst, ARMRegisters::S0, offset);
f9bf01c6
A
303 return;
304 }
305
93a37866
A
306 moveImm(offset, ARMRegisters::S0);
307 add(ARMRegisters::S0, ARMRegisters::S0, op2);
308 dtrUpRegister(transferType, srcDst, base, ARMRegisters::S0);
309}
310
311void ARMAssembler::dataTransfer16(DataTransferTypeB transferType, RegisterID srcDst, RegisterID base, int32_t offset)
312{
313 if (offset >= 0) {
314 if (offset <= 0xff)
315 halfDtrUp(transferType, srcDst, base, getOp2Half(offset));
316 else if (offset <= 0xffff) {
317 add(ARMRegisters::S0, base, Op2Immediate | (offset >> 8) | (12 << 8));
318 halfDtrUp(transferType, srcDst, ARMRegisters::S0, getOp2Half(offset & 0xff));
319 } else {
320 moveImm(offset, ARMRegisters::S0);
321 halfDtrUpRegister(transferType, srcDst, base, ARMRegisters::S0);
322 }
323 } else {
324 if (offset >= -0xff)
325 halfDtrDown(transferType, srcDst, base, getOp2Half(-offset));
326 else if (offset >= -0xffff) {
327 sub(ARMRegisters::S0, base, Op2Immediate | (-offset >> 8) | (12 << 8));
328 halfDtrDown(transferType, srcDst, ARMRegisters::S0, getOp2Half(-offset & 0xff));
329 } else {
330 moveImm(offset, ARMRegisters::S0);
331 halfDtrUpRegister(transferType, srcDst, base, ARMRegisters::S0);
332 }
333 }
f9bf01c6
A
334}
335
93a37866
A
336void ARMAssembler::baseIndexTransfer16(DataTransferTypeB transferType, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset)
337{
338 if (!scale && !offset) {
339 halfDtrUpRegister(transferType, srcDst, base, index);
340 return;
341 }
342
343 ARMWord op2 = lsl(index, scale);
344
345 if (offset <= 0xffff && offset >= -0xffff) {
346 add(ARMRegisters::S0, base, op2);
347 dataTransfer16(transferType, srcDst, ARMRegisters::S0, offset);
348 return;
349 }
350
351 moveImm(offset, ARMRegisters::S0);
352 add(ARMRegisters::S0, ARMRegisters::S0, op2);
353 halfDtrUpRegister(transferType, srcDst, base, ARMRegisters::S0);
354}
355
356void ARMAssembler::dataTransferFloat(DataTransferTypeFloat transferType, FPRegisterID srcDst, RegisterID base, int32_t offset)
f9bf01c6 357{
6fe7ccc8
A
358 // VFP cannot directly access memory that is not four-byte-aligned
359 if (!(offset & 0x3)) {
f9bf01c6 360 if (offset <= 0x3ff && offset >= 0) {
93a37866 361 doubleDtrUp(transferType, srcDst, base, offset >> 2);
f9bf01c6
A
362 return;
363 }
364 if (offset <= 0x3ffff && offset >= 0) {
93a37866
A
365 add(ARMRegisters::S0, base, Op2Immediate | (offset >> 10) | (11 << 8));
366 doubleDtrUp(transferType, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff);
f9bf01c6
A
367 return;
368 }
369 offset = -offset;
370
371 if (offset <= 0x3ff && offset >= 0) {
93a37866 372 doubleDtrDown(transferType, srcDst, base, offset >> 2);
f9bf01c6
A
373 return;
374 }
375 if (offset <= 0x3ffff && offset >= 0) {
93a37866
A
376 sub(ARMRegisters::S0, base, Op2Immediate | (offset >> 10) | (11 << 8));
377 doubleDtrDown(transferType, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff);
f9bf01c6
A
378 return;
379 }
380 offset = -offset;
381 }
382
93a37866
A
383 moveImm(offset, ARMRegisters::S0);
384 add(ARMRegisters::S0, ARMRegisters::S0, base);
385 doubleDtrUp(transferType, srcDst, ARMRegisters::S0, 0);
386}
387
388void ARMAssembler::baseIndexTransferFloat(DataTransferTypeFloat transferType, FPRegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset)
389{
390 add(ARMRegisters::S1, base, lsl(index, scale));
391 dataTransferFloat(transferType, srcDst, ARMRegisters::S1, offset);
f9bf01c6
A
392}
393
93a37866 394PassRefPtr<ExecutableMemoryHandle> ARMAssembler::executableCopy(VM& vm, void* ownerUID, JITCompilationEffort effort)
f9bf01c6
A
395{
396 // 64-bit alignment is required for next constant pool and JIT code as well
397 m_buffer.flushWithoutBarrier(true);
14957cd0 398 if (!m_buffer.isAligned(8))
f9bf01c6
A
399 bkpt(0);
400
93a37866 401 RefPtr<ExecutableMemoryHandle> result = m_buffer.executableCopy(vm, ownerUID, effort);
6fe7ccc8 402 char* data = reinterpret_cast<char*>(result->start());
f9bf01c6
A
403
404 for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) {
405 // The last bit is set if the constant must be placed on constant pool.
14957cd0
A
406 int pos = (iter->m_offset) & (~0x1);
407 ARMWord* ldrAddr = reinterpret_cast_ptr<ARMWord*>(data + pos);
f9bf01c6 408 ARMWord* addr = getLdrImmAddress(ldrAddr);
4e4e5a6f 409 if (*addr != InvalidBranchTarget) {
14957cd0 410 if (!(iter->m_offset & 1)) {
93a37866 411 intptr_t difference = reinterpret_cast_ptr<ARMWord*>(data + *addr) - (ldrAddr + DefaultPrefetchOffset);
f9bf01c6 412
93a37866
A
413 if ((difference <= MaximumBranchOffsetDistance && difference >= MinimumBranchOffsetDistance)) {
414 *ldrAddr = B | getConditionalField(*ldrAddr) | (difference & BranchOffsetMask);
f9bf01c6
A
415 continue;
416 }
417 }
418 *addr = reinterpret_cast<ARMWord>(data + *addr);
419 }
420 }
421
6fe7ccc8 422 return result;
f9bf01c6
A
423}
424
6fe7ccc8
A
425#if OS(LINUX) && COMPILER(RVCT)
426
427__asm void ARMAssembler::cacheFlush(void* code, size_t size)
428{
429 ARM
430 push {r7}
431 add r1, r1, r0
432 mov r7, #0xf0000
433 add r7, r7, #0x2
434 mov r2, #0x0
435 svc #0x0
436 pop {r7}
437 bx lr
438}
439
440#endif
441
f9bf01c6
A
442} // namespace JSC
443
444#endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)