]>
Commit | Line | Data |
---|---|---|
f9bf01c6 | 1 | /* |
81345200 | 2 | * Copyright (C) 2008, 2013 Apple Inc. |
4e4e5a6f | 3 | * Copyright (C) 2009, 2010 University of Szeged |
f9bf01c6 A |
4 | * All rights reserved. |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in the | |
13 | * documentation and/or other materials provided with the distribution. | |
14 | * | |
15 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | |
16 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
18 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR | |
19 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
22 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
23 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
26 | */ | |
27 | ||
28 | #ifndef MacroAssemblerARM_h | |
29 | #define MacroAssemblerARM_h | |
30 | ||
f9bf01c6 A |
31 | #if ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) |
32 | ||
33 | #include "ARMAssembler.h" | |
34 | #include "AbstractMacroAssembler.h" | |
35 | ||
36 | namespace JSC { | |
37 | ||
38 | class MacroAssemblerARM : public AbstractMacroAssembler<ARMAssembler> { | |
39 | static const int DoubleConditionMask = 0x0f; | |
40 | static const int DoubleConditionBitSpecial = 0x10; | |
41 | COMPILE_ASSERT(!(DoubleConditionBitSpecial & DoubleConditionMask), DoubleConditionBitSpecial_should_not_interfere_with_ARMAssembler_Condition_codes); | |
42 | public: | |
4e4e5a6f A |
43 | typedef ARMRegisters::FPRegisterID FPRegisterID; |
44 | ||
14957cd0 | 45 | enum RelationalCondition { |
f9bf01c6 A |
46 | Equal = ARMAssembler::EQ, |
47 | NotEqual = ARMAssembler::NE, | |
48 | Above = ARMAssembler::HI, | |
49 | AboveOrEqual = ARMAssembler::CS, | |
50 | Below = ARMAssembler::CC, | |
51 | BelowOrEqual = ARMAssembler::LS, | |
52 | GreaterThan = ARMAssembler::GT, | |
53 | GreaterThanOrEqual = ARMAssembler::GE, | |
54 | LessThan = ARMAssembler::LT, | |
14957cd0 A |
55 | LessThanOrEqual = ARMAssembler::LE |
56 | }; | |
57 | ||
58 | enum ResultCondition { | |
f9bf01c6 A |
59 | Overflow = ARMAssembler::VS, |
60 | Signed = ARMAssembler::MI, | |
93a37866 | 61 | PositiveOrZero = ARMAssembler::PL, |
f9bf01c6 A |
62 | Zero = ARMAssembler::EQ, |
63 | NonZero = ARMAssembler::NE | |
64 | }; | |
65 | ||
66 | enum DoubleCondition { | |
67 | // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN. | |
68 | DoubleEqual = ARMAssembler::EQ, | |
69 | DoubleNotEqual = ARMAssembler::NE | DoubleConditionBitSpecial, | |
70 | DoubleGreaterThan = ARMAssembler::GT, | |
71 | DoubleGreaterThanOrEqual = ARMAssembler::GE, | |
72 | DoubleLessThan = ARMAssembler::CC, | |
73 | DoubleLessThanOrEqual = ARMAssembler::LS, | |
74 | // If either operand is NaN, these conditions always evaluate to true. | |
75 | DoubleEqualOrUnordered = ARMAssembler::EQ | DoubleConditionBitSpecial, | |
76 | DoubleNotEqualOrUnordered = ARMAssembler::NE, | |
77 | DoubleGreaterThanOrUnordered = ARMAssembler::HI, | |
78 | DoubleGreaterThanOrEqualOrUnordered = ARMAssembler::CS, | |
79 | DoubleLessThanOrUnordered = ARMAssembler::LT, | |
80 | DoubleLessThanOrEqualOrUnordered = ARMAssembler::LE, | |
81 | }; | |
82 | ||
83 | static const RegisterID stackPointerRegister = ARMRegisters::sp; | |
81345200 | 84 | static const RegisterID framePointerRegister = ARMRegisters::fp; |
f9bf01c6 A |
85 | static const RegisterID linkRegister = ARMRegisters::lr; |
86 | ||
87 | static const Scale ScalePtr = TimesFour; | |
88 | ||
89 | void add32(RegisterID src, RegisterID dest) | |
90 | { | |
93a37866 A |
91 | m_assembler.adds(dest, dest, src); |
92 | } | |
93 | ||
94 | void add32(RegisterID op1, RegisterID op2, RegisterID dest) | |
95 | { | |
96 | m_assembler.adds(dest, op1, op2); | |
f9bf01c6 A |
97 | } |
98 | ||
14957cd0 | 99 | void add32(TrustedImm32 imm, Address address) |
f9bf01c6 A |
100 | { |
101 | load32(address, ARMRegisters::S1); | |
102 | add32(imm, ARMRegisters::S1); | |
103 | store32(ARMRegisters::S1, address); | |
104 | } | |
105 | ||
14957cd0 | 106 | void add32(TrustedImm32 imm, RegisterID dest) |
f9bf01c6 | 107 | { |
93a37866 A |
108 | m_assembler.adds(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); |
109 | } | |
110 | ||
111 | void add32(AbsoluteAddress src, RegisterID dest) | |
112 | { | |
113 | move(TrustedImmPtr(src.m_ptr), ARMRegisters::S1); | |
114 | m_assembler.dtrUp(ARMAssembler::LoadUint32, ARMRegisters::S1, ARMRegisters::S1, 0); | |
115 | add32(ARMRegisters::S1, dest); | |
f9bf01c6 A |
116 | } |
117 | ||
118 | void add32(Address src, RegisterID dest) | |
119 | { | |
120 | load32(src, ARMRegisters::S1); | |
121 | add32(ARMRegisters::S1, dest); | |
122 | } | |
123 | ||
6fe7ccc8 A |
124 | void add32(RegisterID src, TrustedImm32 imm, RegisterID dest) |
125 | { | |
93a37866 | 126 | m_assembler.adds(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); |
6fe7ccc8 A |
127 | } |
128 | ||
f9bf01c6 A |
129 | void and32(RegisterID src, RegisterID dest) |
130 | { | |
93a37866 A |
131 | m_assembler.bitAnds(dest, dest, src); |
132 | } | |
133 | ||
134 | void and32(RegisterID op1, RegisterID op2, RegisterID dest) | |
135 | { | |
136 | m_assembler.bitAnds(dest, op1, op2); | |
f9bf01c6 A |
137 | } |
138 | ||
14957cd0 | 139 | void and32(TrustedImm32 imm, RegisterID dest) |
f9bf01c6 A |
140 | { |
141 | ARMWord w = m_assembler.getImm(imm.m_value, ARMRegisters::S0, true); | |
93a37866 A |
142 | if (w & ARMAssembler::Op2InvertedImmediate) |
143 | m_assembler.bics(dest, dest, w & ~ARMAssembler::Op2InvertedImmediate); | |
f9bf01c6 | 144 | else |
93a37866 | 145 | m_assembler.bitAnds(dest, dest, w); |
f9bf01c6 A |
146 | } |
147 | ||
6fe7ccc8 A |
148 | void and32(TrustedImm32 imm, RegisterID src, RegisterID dest) |
149 | { | |
150 | ARMWord w = m_assembler.getImm(imm.m_value, ARMRegisters::S0, true); | |
93a37866 A |
151 | if (w & ARMAssembler::Op2InvertedImmediate) |
152 | m_assembler.bics(dest, src, w & ~ARMAssembler::Op2InvertedImmediate); | |
6fe7ccc8 | 153 | else |
93a37866 | 154 | m_assembler.bitAnds(dest, src, w); |
6fe7ccc8 A |
155 | } |
156 | ||
93a37866 | 157 | void and32(Address src, RegisterID dest) |
f9bf01c6 | 158 | { |
93a37866 A |
159 | load32(src, ARMRegisters::S1); |
160 | and32(ARMRegisters::S1, dest); | |
161 | } | |
f9bf01c6 | 162 | |
93a37866 A |
163 | void lshift32(RegisterID shiftAmount, RegisterID dest) |
164 | { | |
165 | lshift32(dest, shiftAmount, dest); | |
166 | } | |
167 | ||
168 | void lshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest) | |
169 | { | |
170 | ARMWord w = ARMAssembler::getOp2Byte(0x1f); | |
171 | m_assembler.bitAnd(ARMRegisters::S0, shiftAmount, w); | |
172 | ||
173 | m_assembler.movs(dest, m_assembler.lslRegister(src, ARMRegisters::S0)); | |
f9bf01c6 A |
174 | } |
175 | ||
14957cd0 | 176 | void lshift32(TrustedImm32 imm, RegisterID dest) |
f9bf01c6 | 177 | { |
93a37866 | 178 | m_assembler.movs(dest, m_assembler.lsl(dest, imm.m_value & 0x1f)); |
f9bf01c6 A |
179 | } |
180 | ||
6fe7ccc8 A |
181 | void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest) |
182 | { | |
93a37866 | 183 | m_assembler.movs(dest, m_assembler.lsl(src, imm.m_value & 0x1f)); |
6fe7ccc8 A |
184 | } |
185 | ||
93a37866 | 186 | void mul32(RegisterID op1, RegisterID op2, RegisterID dest) |
f9bf01c6 | 187 | { |
93a37866 A |
188 | if (op2 == dest) { |
189 | if (op1 == dest) { | |
190 | move(op2, ARMRegisters::S0); | |
191 | op2 = ARMRegisters::S0; | |
192 | } else { | |
193 | // Swap the operands. | |
194 | RegisterID tmp = op1; | |
195 | op1 = op2; | |
196 | op2 = tmp; | |
197 | } | |
f9bf01c6 | 198 | } |
93a37866 A |
199 | m_assembler.muls(dest, op1, op2); |
200 | } | |
201 | ||
202 | void mul32(RegisterID src, RegisterID dest) | |
203 | { | |
204 | mul32(src, dest, dest); | |
f9bf01c6 A |
205 | } |
206 | ||
14957cd0 | 207 | void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest) |
f9bf01c6 A |
208 | { |
209 | move(imm, ARMRegisters::S0); | |
93a37866 | 210 | m_assembler.muls(dest, src, ARMRegisters::S0); |
f9bf01c6 A |
211 | } |
212 | ||
213 | void neg32(RegisterID srcDest) | |
214 | { | |
93a37866 | 215 | m_assembler.rsbs(srcDest, srcDest, ARMAssembler::getOp2Byte(0)); |
f9bf01c6 A |
216 | } |
217 | ||
f9bf01c6 A |
218 | void or32(RegisterID src, RegisterID dest) |
219 | { | |
93a37866 A |
220 | m_assembler.orrs(dest, dest, src); |
221 | } | |
222 | ||
223 | void or32(RegisterID src, AbsoluteAddress dest) | |
224 | { | |
225 | move(TrustedImmPtr(dest.m_ptr), ARMRegisters::S0); | |
226 | load32(Address(ARMRegisters::S0), ARMRegisters::S1); | |
227 | or32(src, ARMRegisters::S1); | |
228 | store32(ARMRegisters::S1, ARMRegisters::S0); | |
f9bf01c6 A |
229 | } |
230 | ||
14957cd0 | 231 | void or32(TrustedImm32 imm, RegisterID dest) |
f9bf01c6 | 232 | { |
93a37866 | 233 | m_assembler.orrs(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); |
f9bf01c6 A |
234 | } |
235 | ||
6fe7ccc8 A |
236 | void or32(TrustedImm32 imm, RegisterID src, RegisterID dest) |
237 | { | |
93a37866 | 238 | m_assembler.orrs(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); |
6fe7ccc8 A |
239 | } |
240 | ||
241 | void or32(RegisterID op1, RegisterID op2, RegisterID dest) | |
242 | { | |
93a37866 | 243 | m_assembler.orrs(dest, op1, op2); |
6fe7ccc8 A |
244 | } |
245 | ||
93a37866 | 246 | void rshift32(RegisterID shiftAmount, RegisterID dest) |
f9bf01c6 | 247 | { |
93a37866 A |
248 | rshift32(dest, shiftAmount, dest); |
249 | } | |
f9bf01c6 | 250 | |
93a37866 A |
251 | void rshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest) |
252 | { | |
253 | ARMWord w = ARMAssembler::getOp2Byte(0x1f); | |
254 | m_assembler.bitAnd(ARMRegisters::S0, shiftAmount, w); | |
255 | ||
256 | m_assembler.movs(dest, m_assembler.asrRegister(src, ARMRegisters::S0)); | |
f9bf01c6 | 257 | } |
93a37866 | 258 | |
14957cd0 | 259 | void rshift32(TrustedImm32 imm, RegisterID dest) |
f9bf01c6 | 260 | { |
6fe7ccc8 A |
261 | rshift32(dest, imm, dest); |
262 | } | |
263 | ||
264 | void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest) | |
265 | { | |
93a37866 | 266 | m_assembler.movs(dest, m_assembler.asr(src, imm.m_value & 0x1f)); |
f9bf01c6 | 267 | } |
93a37866 A |
268 | |
269 | void urshift32(RegisterID shiftAmount, RegisterID dest) | |
4e4e5a6f | 270 | { |
93a37866 | 271 | urshift32(dest, shiftAmount, dest); |
4e4e5a6f | 272 | } |
93a37866 A |
273 | |
274 | void urshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest) | |
275 | { | |
276 | ARMWord w = ARMAssembler::getOp2Byte(0x1f); | |
277 | m_assembler.bitAnd(ARMRegisters::S0, shiftAmount, w); | |
278 | ||
279 | m_assembler.movs(dest, m_assembler.lsrRegister(src, ARMRegisters::S0)); | |
280 | } | |
281 | ||
14957cd0 | 282 | void urshift32(TrustedImm32 imm, RegisterID dest) |
4e4e5a6f | 283 | { |
93a37866 | 284 | m_assembler.movs(dest, m_assembler.lsr(dest, imm.m_value & 0x1f)); |
4e4e5a6f | 285 | } |
6fe7ccc8 A |
286 | |
287 | void urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest) | |
288 | { | |
93a37866 | 289 | m_assembler.movs(dest, m_assembler.lsr(src, imm.m_value & 0x1f)); |
6fe7ccc8 | 290 | } |
f9bf01c6 A |
291 | |
292 | void sub32(RegisterID src, RegisterID dest) | |
293 | { | |
93a37866 | 294 | m_assembler.subs(dest, dest, src); |
f9bf01c6 A |
295 | } |
296 | ||
14957cd0 | 297 | void sub32(TrustedImm32 imm, RegisterID dest) |
f9bf01c6 | 298 | { |
93a37866 | 299 | m_assembler.subs(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); |
f9bf01c6 A |
300 | } |
301 | ||
14957cd0 | 302 | void sub32(TrustedImm32 imm, Address address) |
f9bf01c6 A |
303 | { |
304 | load32(address, ARMRegisters::S1); | |
305 | sub32(imm, ARMRegisters::S1); | |
306 | store32(ARMRegisters::S1, address); | |
307 | } | |
308 | ||
309 | void sub32(Address src, RegisterID dest) | |
310 | { | |
311 | load32(src, ARMRegisters::S1); | |
312 | sub32(ARMRegisters::S1, dest); | |
313 | } | |
314 | ||
6fe7ccc8 A |
315 | void sub32(RegisterID src, TrustedImm32 imm, RegisterID dest) |
316 | { | |
93a37866 | 317 | m_assembler.subs(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); |
6fe7ccc8 A |
318 | } |
319 | ||
f9bf01c6 A |
320 | void xor32(RegisterID src, RegisterID dest) |
321 | { | |
93a37866 A |
322 | m_assembler.eors(dest, dest, src); |
323 | } | |
324 | ||
325 | void xor32(RegisterID op1, RegisterID op2, RegisterID dest) | |
326 | { | |
327 | m_assembler.eors(dest, op1, op2); | |
f9bf01c6 A |
328 | } |
329 | ||
14957cd0 | 330 | void xor32(TrustedImm32 imm, RegisterID dest) |
f9bf01c6 | 331 | { |
6fe7ccc8 | 332 | if (imm.m_value == -1) |
93a37866 | 333 | m_assembler.mvns(dest, dest); |
6fe7ccc8 | 334 | else |
93a37866 | 335 | m_assembler.eors(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); |
6fe7ccc8 A |
336 | } |
337 | ||
338 | void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest) | |
339 | { | |
340 | if (imm.m_value == -1) | |
93a37866 | 341 | m_assembler.mvns(dest, src); |
6fe7ccc8 | 342 | else |
93a37866 | 343 | m_assembler.eors(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); |
f9bf01c6 A |
344 | } |
345 | ||
14957cd0 A |
346 | void countLeadingZeros32(RegisterID src, RegisterID dest) |
347 | { | |
348 | #if WTF_ARM_ARCH_AT_LEAST(5) | |
93a37866 | 349 | m_assembler.clz(dest, src); |
14957cd0 A |
350 | #else |
351 | UNUSED_PARAM(src); | |
352 | UNUSED_PARAM(dest); | |
93a37866 | 353 | RELEASE_ASSERT_NOT_REACHED(); |
14957cd0 A |
354 | #endif |
355 | } | |
356 | ||
4e4e5a6f A |
357 | void load8(ImplicitAddress address, RegisterID dest) |
358 | { | |
93a37866 | 359 | m_assembler.dataTransfer32(ARMAssembler::LoadUint8, dest, address.base, address.offset); |
4e4e5a6f A |
360 | } |
361 | ||
6fe7ccc8 A |
362 | void load8(BaseIndex address, RegisterID dest) |
363 | { | |
93a37866 A |
364 | m_assembler.baseIndexTransfer32(ARMAssembler::LoadUint8, dest, address.base, address.index, static_cast<int>(address.scale), address.offset); |
365 | } | |
366 | ||
81345200 A |
367 | void load8(const void* address, RegisterID dest) |
368 | { | |
369 | move(TrustedImmPtr(address), ARMRegisters::S0); | |
370 | m_assembler.dataTransfer32(ARMAssembler::LoadUint8, dest, ARMRegisters::S0, 0); | |
371 | } | |
372 | ||
93a37866 A |
373 | void load8Signed(BaseIndex address, RegisterID dest) |
374 | { | |
375 | m_assembler.baseIndexTransfer16(ARMAssembler::LoadInt8, dest, address.base, address.index, static_cast<int>(address.scale), address.offset); | |
376 | } | |
377 | ||
378 | void load16(ImplicitAddress address, RegisterID dest) | |
379 | { | |
380 | m_assembler.dataTransfer16(ARMAssembler::LoadUint16, dest, address.base, address.offset); | |
381 | } | |
382 | ||
383 | void load16(BaseIndex address, RegisterID dest) | |
384 | { | |
385 | m_assembler.baseIndexTransfer16(ARMAssembler::LoadUint16, dest, address.base, address.index, static_cast<int>(address.scale), address.offset); | |
386 | } | |
387 | ||
388 | void load16Signed(BaseIndex address, RegisterID dest) | |
389 | { | |
390 | m_assembler.baseIndexTransfer16(ARMAssembler::LoadInt16, dest, address.base, address.index, static_cast<int>(address.scale), address.offset); | |
6fe7ccc8 A |
391 | } |
392 | ||
f9bf01c6 A |
393 | void load32(ImplicitAddress address, RegisterID dest) |
394 | { | |
93a37866 | 395 | m_assembler.dataTransfer32(ARMAssembler::LoadUint32, dest, address.base, address.offset); |
f9bf01c6 A |
396 | } |
397 | ||
398 | void load32(BaseIndex address, RegisterID dest) | |
399 | { | |
93a37866 | 400 | m_assembler.baseIndexTransfer32(ARMAssembler::LoadUint32, dest, address.base, address.index, static_cast<int>(address.scale), address.offset); |
f9bf01c6 A |
401 | } |
402 | ||
403 | #if CPU(ARMV5_OR_LOWER) | |
404 | void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest); | |
405 | #else | |
406 | void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest) | |
407 | { | |
408 | load32(address, dest); | |
409 | } | |
410 | #endif | |
411 | ||
6fe7ccc8 A |
412 | void load16Unaligned(BaseIndex address, RegisterID dest) |
413 | { | |
414 | load16(address, dest); | |
415 | } | |
416 | ||
81345200 A |
417 | void abortWithReason(AbortReason reason) |
418 | { | |
419 | move(TrustedImm32(reason), ARMRegisters::S0); | |
420 | breakpoint(); | |
421 | } | |
422 | ||
423 | void abortWithReason(AbortReason reason, intptr_t misc) | |
424 | { | |
425 | move(TrustedImm32(misc), ARMRegisters::S1); | |
426 | abortWithReason(reason); | |
427 | } | |
428 | ||
93a37866 | 429 | ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest) |
f9bf01c6 | 430 | { |
93a37866 A |
431 | ConvertibleLoadLabel result(this); |
432 | ASSERT(address.offset >= 0 && address.offset <= 255); | |
433 | m_assembler.dtrUp(ARMAssembler::LoadUint32, dest, address.base, address.offset); | |
434 | return result; | |
f9bf01c6 | 435 | } |
93a37866 A |
436 | |
437 | DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest) | |
f9bf01c6 | 438 | { |
93a37866 A |
439 | DataLabel32 dataLabel(this); |
440 | m_assembler.ldrUniqueImmediate(ARMRegisters::S0, 0); | |
441 | m_assembler.dtrUpRegister(ARMAssembler::LoadUint32, dest, address.base, ARMRegisters::S0); | |
14957cd0 | 442 | return dataLabel; |
f9bf01c6 A |
443 | } |
444 | ||
93a37866 | 445 | static bool isCompactPtrAlignedAddressOffset(ptrdiff_t value) |
f9bf01c6 | 446 | { |
93a37866 | 447 | return value >= -4095 && value <= 4095; |
f9bf01c6 | 448 | } |
93a37866 A |
449 | |
450 | DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest) | |
4e4e5a6f | 451 | { |
93a37866 A |
452 | DataLabelCompact dataLabel(this); |
453 | ASSERT(isCompactPtrAlignedAddressOffset(address.offset)); | |
4e4e5a6f | 454 | if (address.offset >= 0) |
93a37866 | 455 | m_assembler.dtrUp(ARMAssembler::LoadUint32, dest, address.base, address.offset); |
4e4e5a6f | 456 | else |
93a37866 A |
457 | m_assembler.dtrDown(ARMAssembler::LoadUint32, dest, address.base, address.offset); |
458 | return dataLabel; | |
4e4e5a6f | 459 | } |
f9bf01c6 A |
460 | |
461 | DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) | |
462 | { | |
463 | DataLabel32 dataLabel(this); | |
93a37866 A |
464 | m_assembler.ldrUniqueImmediate(ARMRegisters::S0, 0); |
465 | m_assembler.dtrUpRegister(ARMAssembler::StoreUint32, src, address.base, ARMRegisters::S0); | |
f9bf01c6 A |
466 | return dataLabel; |
467 | } | |
468 | ||
93a37866 A |
469 | void store8(RegisterID src, BaseIndex address) |
470 | { | |
471 | m_assembler.baseIndexTransfer32(ARMAssembler::StoreUint8, src, address.base, address.index, static_cast<int>(address.scale), address.offset); | |
472 | } | |
473 | ||
81345200 A |
474 | void store8(RegisterID src, ImplicitAddress address) |
475 | { | |
476 | m_assembler.dtrUp(ARMAssembler::StoreUint8, src, address.base, address.offset); | |
477 | } | |
478 | ||
479 | void store8(RegisterID src, const void* address) | |
480 | { | |
481 | move(TrustedImmPtr(address), ARMRegisters::S0); | |
482 | m_assembler.dtrUp(ARMAssembler::StoreUint8, src, ARMRegisters::S0, 0); | |
483 | } | |
484 | ||
485 | void store8(TrustedImm32 imm, ImplicitAddress address) | |
486 | { | |
487 | move(imm, ARMRegisters::S1); | |
488 | store8(ARMRegisters::S1, address); | |
489 | } | |
490 | ||
93a37866 A |
491 | void store8(TrustedImm32 imm, const void* address) |
492 | { | |
493 | move(TrustedImm32(reinterpret_cast<ARMWord>(address)), ARMRegisters::S0); | |
494 | move(imm, ARMRegisters::S1); | |
495 | m_assembler.dtrUp(ARMAssembler::StoreUint8, ARMRegisters::S1, ARMRegisters::S0, 0); | |
496 | } | |
497 | ||
498 | void store16(RegisterID src, BaseIndex address) | |
499 | { | |
500 | m_assembler.baseIndexTransfer16(ARMAssembler::StoreUint16, src, address.base, address.index, static_cast<int>(address.scale), address.offset); | |
501 | } | |
502 | ||
f9bf01c6 A |
503 | void store32(RegisterID src, ImplicitAddress address) |
504 | { | |
93a37866 | 505 | m_assembler.dataTransfer32(ARMAssembler::StoreUint32, src, address.base, address.offset); |
f9bf01c6 A |
506 | } |
507 | ||
508 | void store32(RegisterID src, BaseIndex address) | |
509 | { | |
93a37866 | 510 | m_assembler.baseIndexTransfer32(ARMAssembler::StoreUint32, src, address.base, address.index, static_cast<int>(address.scale), address.offset); |
f9bf01c6 A |
511 | } |
512 | ||
14957cd0 | 513 | void store32(TrustedImm32 imm, ImplicitAddress address) |
f9bf01c6 | 514 | { |
93a37866 | 515 | move(imm, ARMRegisters::S1); |
f9bf01c6 A |
516 | store32(ARMRegisters::S1, address); |
517 | } | |
518 | ||
93a37866 | 519 | void store32(TrustedImm32 imm, BaseIndex address) |
f9bf01c6 | 520 | { |
93a37866 A |
521 | move(imm, ARMRegisters::S1); |
522 | m_assembler.baseIndexTransfer32(ARMAssembler::StoreUint32, ARMRegisters::S1, address.base, address.index, static_cast<int>(address.scale), address.offset); | |
f9bf01c6 A |
523 | } |
524 | ||
93a37866 | 525 | void store32(RegisterID src, const void* address) |
f9bf01c6 | 526 | { |
93a37866 A |
527 | m_assembler.ldrUniqueImmediate(ARMRegisters::S0, reinterpret_cast<ARMWord>(address)); |
528 | m_assembler.dtrUp(ARMAssembler::StoreUint32, src, ARMRegisters::S0, 0); | |
529 | } | |
530 | ||
531 | void store32(TrustedImm32 imm, const void* address) | |
532 | { | |
533 | m_assembler.ldrUniqueImmediate(ARMRegisters::S0, reinterpret_cast<ARMWord>(address)); | |
534 | m_assembler.moveImm(imm.m_value, ARMRegisters::S1); | |
535 | m_assembler.dtrUp(ARMAssembler::StoreUint32, ARMRegisters::S1, ARMRegisters::S0, 0); | |
f9bf01c6 A |
536 | } |
537 | ||
538 | void pop(RegisterID dest) | |
539 | { | |
93a37866 | 540 | m_assembler.pop(dest); |
f9bf01c6 A |
541 | } |
542 | ||
81345200 A |
543 | void popPair(RegisterID dest1, RegisterID dest2) |
544 | { | |
545 | m_assembler.pop(dest1); | |
546 | m_assembler.pop(dest2); | |
547 | } | |
548 | ||
f9bf01c6 A |
549 | void push(RegisterID src) |
550 | { | |
93a37866 | 551 | m_assembler.push(src); |
f9bf01c6 A |
552 | } |
553 | ||
554 | void push(Address address) | |
555 | { | |
556 | load32(address, ARMRegisters::S1); | |
557 | push(ARMRegisters::S1); | |
558 | } | |
559 | ||
14957cd0 | 560 | void push(TrustedImm32 imm) |
f9bf01c6 A |
561 | { |
562 | move(imm, ARMRegisters::S0); | |
563 | push(ARMRegisters::S0); | |
564 | } | |
565 | ||
81345200 A |
566 | void pushPair(RegisterID src1, RegisterID src2) |
567 | { | |
568 | m_assembler.push(src2); | |
569 | m_assembler.push(src1); | |
570 | } | |
571 | ||
14957cd0 | 572 | void move(TrustedImm32 imm, RegisterID dest) |
f9bf01c6 | 573 | { |
93a37866 | 574 | m_assembler.moveImm(imm.m_value, dest); |
f9bf01c6 A |
575 | } |
576 | ||
577 | void move(RegisterID src, RegisterID dest) | |
578 | { | |
93a37866 A |
579 | if (src != dest) |
580 | m_assembler.mov(dest, src); | |
f9bf01c6 A |
581 | } |
582 | ||
14957cd0 | 583 | void move(TrustedImmPtr imm, RegisterID dest) |
f9bf01c6 | 584 | { |
14957cd0 | 585 | move(TrustedImm32(imm), dest); |
f9bf01c6 A |
586 | } |
587 | ||
588 | void swap(RegisterID reg1, RegisterID reg2) | |
589 | { | |
93a37866 A |
590 | xor32(reg1, reg2); |
591 | xor32(reg2, reg1); | |
592 | xor32(reg1, reg2); | |
f9bf01c6 A |
593 | } |
594 | ||
595 | void signExtend32ToPtr(RegisterID src, RegisterID dest) | |
596 | { | |
597 | if (src != dest) | |
598 | move(src, dest); | |
599 | } | |
600 | ||
601 | void zeroExtend32ToPtr(RegisterID src, RegisterID dest) | |
602 | { | |
603 | if (src != dest) | |
604 | move(src, dest); | |
605 | } | |
606 | ||
14957cd0 | 607 | Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right) |
4e4e5a6f A |
608 | { |
609 | load8(left, ARMRegisters::S1); | |
610 | return branch32(cond, ARMRegisters::S1, right); | |
611 | } | |
612 | ||
6fe7ccc8 A |
613 | Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right) |
614 | { | |
615 | ASSERT(!(right.m_value & 0xFFFFFF00)); | |
616 | load8(left, ARMRegisters::S1); | |
617 | return branch32(cond, ARMRegisters::S1, right); | |
618 | } | |
619 | ||
81345200 A |
620 | Jump branch8(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right) |
621 | { | |
622 | move(TrustedImmPtr(left.m_ptr), ARMRegisters::S1); | |
623 | load8(Address(ARMRegisters::S1), ARMRegisters::S1); | |
624 | return branch32(cond, ARMRegisters::S1, right); | |
625 | } | |
626 | ||
14957cd0 | 627 | Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right, int useConstantPool = 0) |
f9bf01c6 | 628 | { |
93a37866 | 629 | m_assembler.cmp(left, right); |
f9bf01c6 A |
630 | return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool)); |
631 | } | |
632 | ||
14957cd0 | 633 | Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right, int useConstantPool = 0) |
f9bf01c6 | 634 | { |
93a37866 | 635 | internalCompare32(left, right); |
f9bf01c6 A |
636 | return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool)); |
637 | } | |
638 | ||
14957cd0 | 639 | Jump branch32(RelationalCondition cond, RegisterID left, Address right) |
f9bf01c6 A |
640 | { |
641 | load32(right, ARMRegisters::S1); | |
642 | return branch32(cond, left, ARMRegisters::S1); | |
643 | } | |
644 | ||
14957cd0 | 645 | Jump branch32(RelationalCondition cond, Address left, RegisterID right) |
f9bf01c6 A |
646 | { |
647 | load32(left, ARMRegisters::S1); | |
648 | return branch32(cond, ARMRegisters::S1, right); | |
649 | } | |
650 | ||
14957cd0 | 651 | Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right) |
f9bf01c6 A |
652 | { |
653 | load32(left, ARMRegisters::S1); | |
654 | return branch32(cond, ARMRegisters::S1, right); | |
655 | } | |
656 | ||
14957cd0 | 657 | Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right) |
f9bf01c6 A |
658 | { |
659 | load32(left, ARMRegisters::S1); | |
660 | return branch32(cond, ARMRegisters::S1, right); | |
661 | } | |
662 | ||
14957cd0 | 663 | Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right) |
f9bf01c6 A |
664 | { |
665 | load32WithUnalignedHalfWords(left, ARMRegisters::S1); | |
666 | return branch32(cond, ARMRegisters::S1, right); | |
667 | } | |
668 | ||
14957cd0 | 669 | Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1)) |
4e4e5a6f A |
670 | { |
671 | load8(address, ARMRegisters::S1); | |
672 | return branchTest32(cond, ARMRegisters::S1, mask); | |
673 | } | |
674 | ||
81345200 A |
675 | Jump branchTest8(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1)) |
676 | { | |
677 | load8(address, ARMRegisters::S1); | |
678 | return branchTest32(cond, ARMRegisters::S1, mask); | |
679 | } | |
680 | ||
93a37866 A |
681 | Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1)) |
682 | { | |
683 | move(TrustedImmPtr(address.m_ptr), ARMRegisters::S1); | |
684 | load8(Address(ARMRegisters::S1), ARMRegisters::S1); | |
685 | return branchTest32(cond, ARMRegisters::S1, mask); | |
686 | } | |
687 | ||
14957cd0 | 688 | Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask) |
f9bf01c6 A |
689 | { |
690 | ASSERT((cond == Zero) || (cond == NonZero)); | |
93a37866 | 691 | m_assembler.tst(reg, mask); |
f9bf01c6 A |
692 | return Jump(m_assembler.jmp(ARMCondition(cond))); |
693 | } | |
694 | ||
14957cd0 | 695 | Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1)) |
f9bf01c6 A |
696 | { |
697 | ASSERT((cond == Zero) || (cond == NonZero)); | |
698 | ARMWord w = m_assembler.getImm(mask.m_value, ARMRegisters::S0, true); | |
93a37866 A |
699 | if (w & ARMAssembler::Op2InvertedImmediate) |
700 | m_assembler.bics(ARMRegisters::S0, reg, w & ~ARMAssembler::Op2InvertedImmediate); | |
f9bf01c6 | 701 | else |
93a37866 | 702 | m_assembler.tst(reg, w); |
f9bf01c6 A |
703 | return Jump(m_assembler.jmp(ARMCondition(cond))); |
704 | } | |
705 | ||
14957cd0 | 706 | Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1)) |
f9bf01c6 A |
707 | { |
708 | load32(address, ARMRegisters::S1); | |
709 | return branchTest32(cond, ARMRegisters::S1, mask); | |
710 | } | |
711 | ||
14957cd0 | 712 | Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1)) |
f9bf01c6 A |
713 | { |
714 | load32(address, ARMRegisters::S1); | |
715 | return branchTest32(cond, ARMRegisters::S1, mask); | |
716 | } | |
717 | ||
718 | Jump jump() | |
719 | { | |
720 | return Jump(m_assembler.jmp()); | |
721 | } | |
722 | ||
723 | void jump(RegisterID target) | |
724 | { | |
4e4e5a6f | 725 | m_assembler.bx(target); |
f9bf01c6 A |
726 | } |
727 | ||
728 | void jump(Address address) | |
729 | { | |
730 | load32(address, ARMRegisters::pc); | |
731 | } | |
732 | ||
93a37866 A |
733 | void jump(AbsoluteAddress address) |
734 | { | |
735 | move(TrustedImmPtr(address.m_ptr), ARMRegisters::S0); | |
736 | load32(Address(ARMRegisters::S0, 0), ARMRegisters::pc); | |
737 | } | |
738 | ||
739 | void moveDoubleToInts(FPRegisterID src, RegisterID dest1, RegisterID dest2) | |
740 | { | |
741 | m_assembler.vmov(dest1, dest2, src); | |
742 | } | |
743 | ||
744 | void moveIntsToDouble(RegisterID src1, RegisterID src2, FPRegisterID dest, FPRegisterID) | |
745 | { | |
746 | m_assembler.vmov(dest, src1, src2); | |
747 | } | |
748 | ||
14957cd0 | 749 | Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest) |
f9bf01c6 | 750 | { |
93a37866 A |
751 | ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) |
752 | || (cond == NonZero) || (cond == PositiveOrZero)); | |
f9bf01c6 A |
753 | add32(src, dest); |
754 | return Jump(m_assembler.jmp(ARMCondition(cond))); | |
755 | } | |
756 | ||
93a37866 A |
757 | Jump branchAdd32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest) |
758 | { | |
759 | ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) | |
760 | || (cond == NonZero) || (cond == PositiveOrZero)); | |
761 | add32(op1, op2, dest); | |
762 | return Jump(m_assembler.jmp(ARMCondition(cond))); | |
763 | } | |
764 | ||
14957cd0 | 765 | Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest) |
f9bf01c6 | 766 | { |
93a37866 A |
767 | ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) |
768 | || (cond == NonZero) || (cond == PositiveOrZero)); | |
f9bf01c6 A |
769 | add32(imm, dest); |
770 | return Jump(m_assembler.jmp(ARMCondition(cond))); | |
771 | } | |
772 | ||
6fe7ccc8 A |
773 | Jump branchAdd32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest) |
774 | { | |
93a37866 A |
775 | ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) |
776 | || (cond == NonZero) || (cond == PositiveOrZero)); | |
6fe7ccc8 A |
777 | add32(src, imm, dest); |
778 | return Jump(m_assembler.jmp(ARMCondition(cond))); | |
779 | } | |
780 | ||
93a37866 | 781 | Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest) |
f9bf01c6 | 782 | { |
93a37866 A |
783 | ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) |
784 | || (cond == NonZero) || (cond == PositiveOrZero)); | |
785 | add32(imm, dest); | |
786 | return Jump(m_assembler.jmp(ARMCondition(cond))); | |
787 | } | |
788 | ||
81345200 A |
789 | Jump branchAdd32(ResultCondition cond, Address src, RegisterID dest) |
790 | { | |
791 | load32(src, ARMRegisters::S0); | |
792 | return branchAdd32(cond, dest, ARMRegisters::S0, dest); | |
793 | } | |
93a37866 A |
794 | void mull32(RegisterID op1, RegisterID op2, RegisterID dest) |
795 | { | |
796 | if (op2 == dest) { | |
797 | if (op1 == dest) { | |
798 | move(op2, ARMRegisters::S0); | |
799 | op2 = ARMRegisters::S0; | |
800 | } else { | |
801 | // Swap the operands. | |
802 | RegisterID tmp = op1; | |
803 | op1 = op2; | |
804 | op2 = tmp; | |
805 | } | |
f9bf01c6 | 806 | } |
93a37866 A |
807 | m_assembler.mull(ARMRegisters::S1, dest, op1, op2); |
808 | m_assembler.cmp(ARMRegisters::S1, m_assembler.asr(dest, 31)); | |
f9bf01c6 A |
809 | } |
810 | ||
93a37866 | 811 | Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest) |
f9bf01c6 A |
812 | { |
813 | ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); | |
814 | if (cond == Overflow) { | |
93a37866 | 815 | mull32(src1, src2, dest); |
f9bf01c6 A |
816 | cond = NonZero; |
817 | } | |
818 | else | |
93a37866 | 819 | mul32(src1, src2, dest); |
f9bf01c6 A |
820 | return Jump(m_assembler.jmp(ARMCondition(cond))); |
821 | } | |
822 | ||
93a37866 A |
823 | Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest) |
824 | { | |
825 | return branchMul32(cond, src, dest, dest); | |
826 | } | |
827 | ||
14957cd0 | 828 | Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest) |
f9bf01c6 A |
829 | { |
830 | ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); | |
831 | if (cond == Overflow) { | |
832 | move(imm, ARMRegisters::S0); | |
833 | mull32(ARMRegisters::S0, src, dest); | |
834 | cond = NonZero; | |
835 | } | |
836 | else | |
837 | mul32(imm, src, dest); | |
838 | return Jump(m_assembler.jmp(ARMCondition(cond))); | |
839 | } | |
840 | ||
14957cd0 | 841 | Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest) |
f9bf01c6 A |
842 | { |
843 | ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); | |
844 | sub32(src, dest); | |
845 | return Jump(m_assembler.jmp(ARMCondition(cond))); | |
846 | } | |
847 | ||
14957cd0 | 848 | Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest) |
f9bf01c6 A |
849 | { |
850 | ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); | |
851 | sub32(imm, dest); | |
852 | return Jump(m_assembler.jmp(ARMCondition(cond))); | |
853 | } | |
854 | ||
6fe7ccc8 A |
855 | Jump branchSub32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest) |
856 | { | |
857 | ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); | |
858 | sub32(src, imm, dest); | |
859 | return Jump(m_assembler.jmp(ARMCondition(cond))); | |
860 | } | |
861 | ||
862 | Jump branchSub32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest) | |
863 | { | |
864 | ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); | |
93a37866 | 865 | m_assembler.subs(dest, op1, op2); |
6fe7ccc8 A |
866 | return Jump(m_assembler.jmp(ARMCondition(cond))); |
867 | } | |
868 | ||
14957cd0 | 869 | Jump branchNeg32(ResultCondition cond, RegisterID srcDest) |
4e4e5a6f A |
870 | { |
871 | ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); | |
872 | neg32(srcDest); | |
873 | return Jump(m_assembler.jmp(ARMCondition(cond))); | |
874 | } | |
875 | ||
14957cd0 | 876 | Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest) |
f9bf01c6 A |
877 | { |
878 | ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero)); | |
879 | or32(src, dest); | |
880 | return Jump(m_assembler.jmp(ARMCondition(cond))); | |
881 | } | |
882 | ||
81345200 A |
883 | PatchableJump patchableJump() |
884 | { | |
885 | return PatchableJump(m_assembler.jmp(ARMAssembler::AL, 1)); | |
886 | } | |
887 | ||
93a37866 A |
888 | PatchableJump patchableBranch32(RelationalCondition cond, RegisterID reg, TrustedImm32 imm) |
889 | { | |
890 | internalCompare32(reg, imm); | |
891 | Jump jump(m_assembler.loadBranchTarget(ARMRegisters::S1, ARMCondition(cond), true)); | |
892 | m_assembler.bx(ARMRegisters::S1, ARMCondition(cond)); | |
893 | return PatchableJump(jump); | |
894 | } | |
895 | ||
f9bf01c6 A |
896 | void breakpoint() |
897 | { | |
898 | m_assembler.bkpt(0); | |
899 | } | |
900 | ||
901 | Call nearCall() | |
902 | { | |
4e4e5a6f A |
903 | m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true); |
904 | return Call(m_assembler.blx(ARMRegisters::S1), Call::LinkableNear); | |
f9bf01c6 A |
905 | } |
906 | ||
907 | Call call(RegisterID target) | |
908 | { | |
14957cd0 | 909 | return Call(m_assembler.blx(target), Call::None); |
f9bf01c6 A |
910 | } |
911 | ||
912 | void call(Address address) | |
913 | { | |
914 | call32(address.base, address.offset); | |
915 | } | |
916 | ||
917 | void ret() | |
918 | { | |
4e4e5a6f | 919 | m_assembler.bx(linkRegister); |
f9bf01c6 A |
920 | } |
921 | ||
14957cd0 | 922 | void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest) |
f9bf01c6 | 923 | { |
93a37866 A |
924 | m_assembler.cmp(left, right); |
925 | m_assembler.mov(dest, ARMAssembler::getOp2Byte(0)); | |
926 | m_assembler.mov(dest, ARMAssembler::getOp2Byte(1), ARMCondition(cond)); | |
f9bf01c6 A |
927 | } |
928 | ||
14957cd0 | 929 | void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest) |
f9bf01c6 | 930 | { |
93a37866 A |
931 | m_assembler.cmp(left, m_assembler.getImm(right.m_value, ARMRegisters::S0)); |
932 | m_assembler.mov(dest, ARMAssembler::getOp2Byte(0)); | |
933 | m_assembler.mov(dest, ARMAssembler::getOp2Byte(1), ARMCondition(cond)); | |
f9bf01c6 A |
934 | } |
935 | ||
6fe7ccc8 A |
936 | void compare8(RelationalCondition cond, Address left, TrustedImm32 right, RegisterID dest) |
937 | { | |
938 | load8(left, ARMRegisters::S1); | |
939 | compare32(cond, ARMRegisters::S1, right, dest); | |
940 | } | |
941 | ||
14957cd0 | 942 | void test32(ResultCondition cond, RegisterID reg, TrustedImm32 mask, RegisterID dest) |
f9bf01c6 | 943 | { |
f9bf01c6 | 944 | if (mask.m_value == -1) |
93a37866 | 945 | m_assembler.cmp(0, reg); |
f9bf01c6 | 946 | else |
93a37866 A |
947 | m_assembler.tst(reg, m_assembler.getImm(mask.m_value, ARMRegisters::S0)); |
948 | m_assembler.mov(dest, ARMAssembler::getOp2Byte(0)); | |
949 | m_assembler.mov(dest, ARMAssembler::getOp2Byte(1), ARMCondition(cond)); | |
f9bf01c6 A |
950 | } |
951 | ||
14957cd0 A |
952 | void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest) |
953 | { | |
954 | load32(address, ARMRegisters::S1); | |
955 | test32(cond, ARMRegisters::S1, mask, dest); | |
956 | } | |
957 | ||
958 | void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest) | |
f9bf01c6 | 959 | { |
14957cd0 A |
960 | load8(address, ARMRegisters::S1); |
961 | test32(cond, ARMRegisters::S1, mask, dest); | |
f9bf01c6 A |
962 | } |
963 | ||
14957cd0 | 964 | void add32(TrustedImm32 imm, RegisterID src, RegisterID dest) |
f9bf01c6 | 965 | { |
93a37866 | 966 | m_assembler.add(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); |
f9bf01c6 A |
967 | } |
968 | ||
14957cd0 | 969 | void add32(TrustedImm32 imm, AbsoluteAddress address) |
f9bf01c6 | 970 | { |
93a37866 | 971 | load32(address.m_ptr, ARMRegisters::S1); |
f9bf01c6 | 972 | add32(imm, ARMRegisters::S1); |
93a37866 A |
973 | store32(ARMRegisters::S1, address.m_ptr); |
974 | } | |
975 | ||
976 | void add64(TrustedImm32 imm, AbsoluteAddress address) | |
977 | { | |
978 | ARMWord tmp; | |
979 | ||
980 | move(TrustedImmPtr(address.m_ptr), ARMRegisters::S1); | |
981 | m_assembler.dtrUp(ARMAssembler::LoadUint32, ARMRegisters::S0, ARMRegisters::S1, 0); | |
982 | ||
983 | if ((tmp = ARMAssembler::getOp2(imm.m_value)) != ARMAssembler::InvalidImmediate) | |
984 | m_assembler.adds(ARMRegisters::S0, ARMRegisters::S0, tmp); | |
985 | else if ((tmp = ARMAssembler::getOp2(-imm.m_value)) != ARMAssembler::InvalidImmediate) | |
986 | m_assembler.subs(ARMRegisters::S0, ARMRegisters::S0, tmp); | |
987 | else { | |
988 | m_assembler.adds(ARMRegisters::S0, ARMRegisters::S0, m_assembler.getImm(imm.m_value, ARMRegisters::S1)); | |
989 | move(TrustedImmPtr(address.m_ptr), ARMRegisters::S1); | |
990 | } | |
991 | m_assembler.dtrUp(ARMAssembler::StoreUint32, ARMRegisters::S0, ARMRegisters::S1, 0); | |
992 | ||
993 | m_assembler.dtrUp(ARMAssembler::LoadUint32, ARMRegisters::S0, ARMRegisters::S1, sizeof(ARMWord)); | |
994 | if (imm.m_value >= 0) | |
995 | m_assembler.adc(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Byte(0)); | |
996 | else | |
997 | m_assembler.sbc(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Byte(0)); | |
998 | m_assembler.dtrUp(ARMAssembler::StoreUint32, ARMRegisters::S0, ARMRegisters::S1, sizeof(ARMWord)); | |
f9bf01c6 A |
999 | } |
1000 | ||
14957cd0 | 1001 | void sub32(TrustedImm32 imm, AbsoluteAddress address) |
f9bf01c6 | 1002 | { |
93a37866 | 1003 | load32(address.m_ptr, ARMRegisters::S1); |
f9bf01c6 | 1004 | sub32(imm, ARMRegisters::S1); |
93a37866 | 1005 | store32(ARMRegisters::S1, address.m_ptr); |
f9bf01c6 A |
1006 | } |
1007 | ||
14957cd0 | 1008 | void load32(const void* address, RegisterID dest) |
f9bf01c6 | 1009 | { |
93a37866 A |
1010 | m_assembler.ldrUniqueImmediate(ARMRegisters::S0, reinterpret_cast<ARMWord>(address)); |
1011 | m_assembler.dtrUp(ARMAssembler::LoadUint32, dest, ARMRegisters::S0, 0); | |
f9bf01c6 A |
1012 | } |
1013 | ||
14957cd0 | 1014 | Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right) |
f9bf01c6 A |
1015 | { |
1016 | load32(left.m_ptr, ARMRegisters::S1); | |
1017 | return branch32(cond, ARMRegisters::S1, right); | |
1018 | } | |
1019 | ||
14957cd0 | 1020 | Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right) |
f9bf01c6 A |
1021 | { |
1022 | load32(left.m_ptr, ARMRegisters::S1); | |
1023 | return branch32(cond, ARMRegisters::S1, right); | |
1024 | } | |
1025 | ||
14957cd0 A |
1026 | void relativeTableJump(RegisterID index, int scale) |
1027 | { | |
1028 | ASSERT(scale >= 0 && scale <= 31); | |
93a37866 | 1029 | m_assembler.add(ARMRegisters::pc, ARMRegisters::pc, m_assembler.lsl(index, scale)); |
14957cd0 A |
1030 | |
1031 | // NOP the default prefetching | |
93a37866 | 1032 | m_assembler.mov(ARMRegisters::r0, ARMRegisters::r0); |
14957cd0 A |
1033 | } |
1034 | ||
f9bf01c6 A |
1035 | Call call() |
1036 | { | |
4e4e5a6f A |
1037 | ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord)); |
1038 | m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true); | |
1039 | return Call(m_assembler.blx(ARMRegisters::S1), Call::Linkable); | |
f9bf01c6 A |
1040 | } |
1041 | ||
1042 | Call tailRecursiveCall() | |
1043 | { | |
1044 | return Call::fromTailJump(jump()); | |
1045 | } | |
1046 | ||
1047 | Call makeTailRecursiveCall(Jump oldJump) | |
1048 | { | |
1049 | return Call::fromTailJump(oldJump); | |
1050 | } | |
1051 | ||
14957cd0 | 1052 | DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest) |
f9bf01c6 A |
1053 | { |
1054 | DataLabelPtr dataLabel(this); | |
93a37866 | 1055 | m_assembler.ldrUniqueImmediate(dest, reinterpret_cast<ARMWord>(initialValue.m_value)); |
f9bf01c6 A |
1056 | return dataLabel; |
1057 | } | |
1058 | ||
81345200 A |
1059 | DataLabel32 moveWithPatch(TrustedImm32 initialValue, RegisterID dest) |
1060 | { | |
1061 | DataLabel32 dataLabel(this); | |
1062 | m_assembler.ldrUniqueImmediate(dest, static_cast<ARMWord>(initialValue.m_value)); | |
1063 | return dataLabel; | |
1064 | } | |
1065 | ||
14957cd0 | 1066 | Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0)) |
f9bf01c6 | 1067 | { |
93a37866 | 1068 | ensureSpace(3 * sizeof(ARMWord), 2 * sizeof(ARMWord)); |
f9bf01c6 A |
1069 | dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S1); |
1070 | Jump jump = branch32(cond, left, ARMRegisters::S1, true); | |
1071 | return jump; | |
1072 | } | |
1073 | ||
14957cd0 | 1074 | Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0)) |
f9bf01c6 A |
1075 | { |
1076 | load32(left, ARMRegisters::S1); | |
93a37866 | 1077 | ensureSpace(3 * sizeof(ARMWord), 2 * sizeof(ARMWord)); |
f9bf01c6 A |
1078 | dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S0); |
1079 | Jump jump = branch32(cond, ARMRegisters::S0, ARMRegisters::S1, true); | |
1080 | return jump; | |
1081 | } | |
1082 | ||
81345200 A |
1083 | Jump branch32WithPatch(RelationalCondition cond, Address left, DataLabel32& dataLabel, TrustedImm32 initialRightValue = TrustedImm32(0)) |
1084 | { | |
1085 | load32(left, ARMRegisters::S1); | |
1086 | ensureSpace(3 * sizeof(ARMWord), 2 * sizeof(ARMWord)); | |
1087 | dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S0); | |
1088 | Jump jump = branch32(cond, ARMRegisters::S0, ARMRegisters::S1, true); | |
1089 | return jump; | |
1090 | } | |
1091 | ||
14957cd0 | 1092 | DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address) |
f9bf01c6 A |
1093 | { |
1094 | DataLabelPtr dataLabel = moveWithPatch(initialValue, ARMRegisters::S1); | |
1095 | store32(ARMRegisters::S1, address); | |
1096 | return dataLabel; | |
1097 | } | |
1098 | ||
1099 | DataLabelPtr storePtrWithPatch(ImplicitAddress address) | |
1100 | { | |
14957cd0 | 1101 | return storePtrWithPatch(TrustedImmPtr(0), address); |
f9bf01c6 A |
1102 | } |
1103 | ||
1104 | // Floating point operators | |
6fe7ccc8 | 1105 | static bool supportsFloatingPoint() |
f9bf01c6 A |
1106 | { |
1107 | return s_isVFPPresent; | |
1108 | } | |
1109 | ||
6fe7ccc8 | 1110 | static bool supportsFloatingPointTruncate() |
f9bf01c6 | 1111 | { |
6fe7ccc8 | 1112 | return false; |
f9bf01c6 A |
1113 | } |
1114 | ||
6fe7ccc8 | 1115 | static bool supportsFloatingPointSqrt() |
4e4e5a6f A |
1116 | { |
1117 | return s_isVFPPresent; | |
1118 | } | |
6fe7ccc8 | 1119 | static bool supportsFloatingPointAbs() { return false; } |
4e4e5a6f | 1120 | |
93a37866 A |
1121 | void loadFloat(BaseIndex address, FPRegisterID dest) |
1122 | { | |
1123 | m_assembler.baseIndexTransferFloat(ARMAssembler::LoadFloat, dest, address.base, address.index, static_cast<int>(address.scale), address.offset); | |
1124 | } | |
1125 | ||
f9bf01c6 A |
1126 | void loadDouble(ImplicitAddress address, FPRegisterID dest) |
1127 | { | |
93a37866 A |
1128 | m_assembler.dataTransferFloat(ARMAssembler::LoadDouble, dest, address.base, address.offset); |
1129 | } | |
1130 | ||
1131 | void loadDouble(BaseIndex address, FPRegisterID dest) | |
1132 | { | |
1133 | m_assembler.baseIndexTransferFloat(ARMAssembler::LoadDouble, dest, address.base, address.index, static_cast<int>(address.scale), address.offset); | |
f9bf01c6 A |
1134 | } |
1135 | ||
81345200 | 1136 | void loadDouble(TrustedImmPtr address, FPRegisterID dest) |
f9bf01c6 | 1137 | { |
81345200 | 1138 | move(TrustedImm32(reinterpret_cast<ARMWord>(address.m_value)), ARMRegisters::S0); |
93a37866 A |
1139 | m_assembler.doubleDtrUp(ARMAssembler::LoadDouble, dest, ARMRegisters::S0, 0); |
1140 | } | |
1141 | ||
1142 | void storeFloat(FPRegisterID src, BaseIndex address) | |
1143 | { | |
1144 | m_assembler.baseIndexTransferFloat(ARMAssembler::StoreFloat, src, address.base, address.index, static_cast<int>(address.scale), address.offset); | |
f9bf01c6 A |
1145 | } |
1146 | ||
1147 | void storeDouble(FPRegisterID src, ImplicitAddress address) | |
1148 | { | |
93a37866 A |
1149 | m_assembler.dataTransferFloat(ARMAssembler::StoreDouble, src, address.base, address.offset); |
1150 | } | |
1151 | ||
1152 | void storeDouble(FPRegisterID src, BaseIndex address) | |
1153 | { | |
1154 | m_assembler.baseIndexTransferFloat(ARMAssembler::StoreDouble, src, address.base, address.index, static_cast<int>(address.scale), address.offset); | |
1155 | } | |
1156 | ||
81345200 | 1157 | void storeDouble(FPRegisterID src, TrustedImmPtr address) |
93a37866 | 1158 | { |
81345200 | 1159 | move(TrustedImm32(reinterpret_cast<ARMWord>(address.m_value)), ARMRegisters::S0); |
93a37866 A |
1160 | m_assembler.dataTransferFloat(ARMAssembler::StoreDouble, src, ARMRegisters::S0, 0); |
1161 | } | |
1162 | ||
1163 | void moveDouble(FPRegisterID src, FPRegisterID dest) | |
1164 | { | |
1165 | if (src != dest) | |
1166 | m_assembler.vmov_f64(dest, src); | |
f9bf01c6 A |
1167 | } |
1168 | ||
1169 | void addDouble(FPRegisterID src, FPRegisterID dest) | |
1170 | { | |
93a37866 A |
1171 | m_assembler.vadd_f64(dest, dest, src); |
1172 | } | |
1173 | ||
1174 | void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest) | |
1175 | { | |
1176 | m_assembler.vadd_f64(dest, op1, op2); | |
f9bf01c6 A |
1177 | } |
1178 | ||
1179 | void addDouble(Address src, FPRegisterID dest) | |
1180 | { | |
1181 | loadDouble(src, ARMRegisters::SD0); | |
1182 | addDouble(ARMRegisters::SD0, dest); | |
1183 | } | |
1184 | ||
93a37866 A |
1185 | void addDouble(AbsoluteAddress address, FPRegisterID dest) |
1186 | { | |
81345200 | 1187 | loadDouble(TrustedImmPtr(address.m_ptr), ARMRegisters::SD0); |
93a37866 A |
1188 | addDouble(ARMRegisters::SD0, dest); |
1189 | } | |
1190 | ||
f9bf01c6 A |
1191 | void divDouble(FPRegisterID src, FPRegisterID dest) |
1192 | { | |
93a37866 A |
1193 | m_assembler.vdiv_f64(dest, dest, src); |
1194 | } | |
1195 | ||
1196 | void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest) | |
1197 | { | |
1198 | m_assembler.vdiv_f64(dest, op1, op2); | |
f9bf01c6 A |
1199 | } |
1200 | ||
1201 | void divDouble(Address src, FPRegisterID dest) | |
1202 | { | |
93a37866 | 1203 | RELEASE_ASSERT_NOT_REACHED(); // Untested |
f9bf01c6 A |
1204 | loadDouble(src, ARMRegisters::SD0); |
1205 | divDouble(ARMRegisters::SD0, dest); | |
1206 | } | |
1207 | ||
1208 | void subDouble(FPRegisterID src, FPRegisterID dest) | |
1209 | { | |
93a37866 A |
1210 | m_assembler.vsub_f64(dest, dest, src); |
1211 | } | |
1212 | ||
1213 | void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest) | |
1214 | { | |
1215 | m_assembler.vsub_f64(dest, op1, op2); | |
f9bf01c6 A |
1216 | } |
1217 | ||
1218 | void subDouble(Address src, FPRegisterID dest) | |
1219 | { | |
1220 | loadDouble(src, ARMRegisters::SD0); | |
1221 | subDouble(ARMRegisters::SD0, dest); | |
1222 | } | |
1223 | ||
1224 | void mulDouble(FPRegisterID src, FPRegisterID dest) | |
1225 | { | |
93a37866 | 1226 | m_assembler.vmul_f64(dest, dest, src); |
f9bf01c6 A |
1227 | } |
1228 | ||
1229 | void mulDouble(Address src, FPRegisterID dest) | |
1230 | { | |
1231 | loadDouble(src, ARMRegisters::SD0); | |
1232 | mulDouble(ARMRegisters::SD0, dest); | |
1233 | } | |
1234 | ||
93a37866 A |
1235 | void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest) |
1236 | { | |
1237 | m_assembler.vmul_f64(dest, op1, op2); | |
1238 | } | |
1239 | ||
4e4e5a6f A |
1240 | void sqrtDouble(FPRegisterID src, FPRegisterID dest) |
1241 | { | |
93a37866 | 1242 | m_assembler.vsqrt_f64(dest, src); |
4e4e5a6f | 1243 | } |
6fe7ccc8 | 1244 | |
93a37866 A |
1245 | void absDouble(FPRegisterID src, FPRegisterID dest) |
1246 | { | |
1247 | m_assembler.vabs_f64(dest, src); | |
1248 | } | |
1249 | ||
1250 | void negateDouble(FPRegisterID src, FPRegisterID dest) | |
6fe7ccc8 | 1251 | { |
93a37866 | 1252 | m_assembler.vneg_f64(dest, src); |
6fe7ccc8 | 1253 | } |
4e4e5a6f | 1254 | |
f9bf01c6 A |
1255 | void convertInt32ToDouble(RegisterID src, FPRegisterID dest) |
1256 | { | |
93a37866 A |
1257 | m_assembler.vmov_vfp32(dest << 1, src); |
1258 | m_assembler.vcvt_f64_s32(dest, dest << 1); | |
f9bf01c6 A |
1259 | } |
1260 | ||
1261 | void convertInt32ToDouble(Address src, FPRegisterID dest) | |
1262 | { | |
f9bf01c6 A |
1263 | load32(src, ARMRegisters::S1); |
1264 | convertInt32ToDouble(ARMRegisters::S1, dest); | |
1265 | } | |
1266 | ||
1267 | void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest) | |
1268 | { | |
93a37866 A |
1269 | move(TrustedImmPtr(src.m_ptr), ARMRegisters::S1); |
1270 | load32(Address(ARMRegisters::S1), ARMRegisters::S1); | |
f9bf01c6 A |
1271 | convertInt32ToDouble(ARMRegisters::S1, dest); |
1272 | } | |
1273 | ||
93a37866 A |
1274 | void convertFloatToDouble(FPRegisterID src, FPRegisterID dst) |
1275 | { | |
1276 | m_assembler.vcvt_f64_f32(dst, src); | |
1277 | } | |
1278 | ||
1279 | void convertDoubleToFloat(FPRegisterID src, FPRegisterID dst) | |
1280 | { | |
1281 | m_assembler.vcvt_f32_f64(dst, src); | |
1282 | } | |
1283 | ||
f9bf01c6 A |
1284 | Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right) |
1285 | { | |
93a37866 | 1286 | m_assembler.vcmp_f64(left, right); |
14957cd0 | 1287 | m_assembler.vmrs_apsr(); |
f9bf01c6 | 1288 | if (cond & DoubleConditionBitSpecial) |
93a37866 | 1289 | m_assembler.cmp(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::VS); |
f9bf01c6 A |
1290 | return Jump(m_assembler.jmp(static_cast<ARMAssembler::Condition>(cond & ~DoubleConditionMask))); |
1291 | } | |
1292 | ||
1293 | // Truncates 'src' to an integer, and places the resulting 'dest'. | |
1294 | // If the result is not representable as a 32 bit value, branch. | |
1295 | // May also branch for some values that are representable in 32 bits | |
6fe7ccc8 | 1296 | // (specifically, in this case, INT_MIN). |
93a37866 A |
1297 | enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful }; |
1298 | Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed) | |
f9bf01c6 | 1299 | { |
93a37866 A |
1300 | truncateDoubleToInt32(src, dest); |
1301 | ||
1302 | m_assembler.add(ARMRegisters::S0, dest, ARMAssembler::getOp2Byte(1)); | |
1303 | m_assembler.bic(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Byte(1)); | |
1304 | ||
1305 | ARMWord w = ARMAssembler::getOp2(0x80000000); | |
1306 | ASSERT(w != ARMAssembler::InvalidImmediate); | |
1307 | m_assembler.cmp(ARMRegisters::S0, w); | |
1308 | return Jump(m_assembler.jmp(branchType == BranchIfTruncateFailed ? ARMAssembler::EQ : ARMAssembler::NE)); | |
1309 | } | |
1310 | ||
1311 | Jump branchTruncateDoubleToUint32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed) | |
1312 | { | |
1313 | truncateDoubleToUint32(src, dest); | |
1314 | ||
1315 | m_assembler.add(ARMRegisters::S0, dest, ARMAssembler::getOp2Byte(1)); | |
1316 | m_assembler.bic(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Byte(1)); | |
1317 | ||
1318 | m_assembler.cmp(ARMRegisters::S0, ARMAssembler::getOp2Byte(0)); | |
1319 | return Jump(m_assembler.jmp(branchType == BranchIfTruncateFailed ? ARMAssembler::EQ : ARMAssembler::NE)); | |
1320 | } | |
1321 | ||
1322 | // Result is undefined if the value is outside of the integer range. | |
1323 | void truncateDoubleToInt32(FPRegisterID src, RegisterID dest) | |
1324 | { | |
1325 | m_assembler.vcvt_s32_f64(ARMRegisters::SD0 << 1, src); | |
1326 | m_assembler.vmov_arm32(dest, ARMRegisters::SD0 << 1); | |
1327 | } | |
1328 | ||
1329 | void truncateDoubleToUint32(FPRegisterID src, RegisterID dest) | |
1330 | { | |
1331 | m_assembler.vcvt_u32_f64(ARMRegisters::SD0 << 1, src); | |
1332 | m_assembler.vmov_arm32(dest, ARMRegisters::SD0 << 1); | |
f9bf01c6 A |
1333 | } |
1334 | ||
1335 | // Convert 'src' to an integer, and places the resulting 'dest'. | |
1336 | // If the result is not representable as a 32 bit value, branch. | |
1337 | // May also branch for some values that are representable in 32 bits | |
1338 | // (specifically, in this case, 0). | |
93a37866 | 1339 | void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID, bool negZeroCheck = true) |
f9bf01c6 | 1340 | { |
93a37866 A |
1341 | m_assembler.vcvt_s32_f64(ARMRegisters::SD0 << 1, src); |
1342 | m_assembler.vmov_arm32(dest, ARMRegisters::SD0 << 1); | |
f9bf01c6 A |
1343 | |
1344 | // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump. | |
93a37866 | 1345 | m_assembler.vcvt_f64_s32(ARMRegisters::SD0, ARMRegisters::SD0 << 1); |
f9bf01c6 A |
1346 | failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, ARMRegisters::SD0)); |
1347 | ||
1348 | // If the result is zero, it might have been -0.0, and 0.0 equals to -0.0 | |
93a37866 A |
1349 | if (negZeroCheck) |
1350 | failureCases.append(branchTest32(Zero, dest)); | |
f9bf01c6 A |
1351 | } |
1352 | ||
b80e6193 | 1353 | Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch) |
f9bf01c6 | 1354 | { |
93a37866 | 1355 | m_assembler.mov(ARMRegisters::S0, ARMAssembler::getOp2Byte(0)); |
b80e6193 A |
1356 | convertInt32ToDouble(ARMRegisters::S0, scratch); |
1357 | return branchDouble(DoubleNotEqual, reg, scratch); | |
1358 | } | |
1359 | ||
1360 | Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID scratch) | |
1361 | { | |
93a37866 | 1362 | m_assembler.mov(ARMRegisters::S0, ARMAssembler::getOp2Byte(0)); |
b80e6193 A |
1363 | convertInt32ToDouble(ARMRegisters::S0, scratch); |
1364 | return branchDouble(DoubleEqualOrUnordered, reg, scratch); | |
f9bf01c6 A |
1365 | } |
1366 | ||
93a37866 A |
1367 | // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc. |
1368 | static RelationalCondition invert(RelationalCondition cond) | |
1369 | { | |
1370 | ASSERT((static_cast<uint32_t>(cond & 0x0fffffff)) == 0 && static_cast<uint32_t>(cond) < static_cast<uint32_t>(ARMAssembler::AL)); | |
1371 | return static_cast<RelationalCondition>(cond ^ 0x10000000); | |
1372 | } | |
1373 | ||
14957cd0 A |
1374 | void nop() |
1375 | { | |
1376 | m_assembler.nop(); | |
1377 | } | |
1378 | ||
81345200 A |
1379 | void memoryFence() |
1380 | { | |
1381 | m_assembler.dmbSY(); | |
1382 | } | |
1383 | ||
6fe7ccc8 A |
1384 | static FunctionPtr readCallTarget(CodeLocationCall call) |
1385 | { | |
1386 | return FunctionPtr(reinterpret_cast<void(*)()>(ARMAssembler::readCallTarget(call.dataLocation()))); | |
1387 | } | |
1388 | ||
93a37866 A |
1389 | static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination) |
1390 | { | |
1391 | ARMAssembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation()); | |
1392 | } | |
1393 | ||
1394 | static ptrdiff_t maxJumpReplacementSize() | |
1395 | { | |
1396 | ARMAssembler::maxJumpReplacementSize(); | |
1397 | return 0; | |
1398 | } | |
1399 | ||
1400 | static bool canJumpReplacePatchableBranchPtrWithPatch() { return false; } | |
81345200 A |
1401 | static bool canJumpReplacePatchableBranch32WithPatch() { return false; } |
1402 | ||
1403 | static CodeLocationLabel startOfPatchableBranch32WithPatchOnAddress(CodeLocationDataLabel32) | |
1404 | { | |
1405 | UNREACHABLE_FOR_PLATFORM(); | |
1406 | return CodeLocationLabel(); | |
1407 | } | |
93a37866 A |
1408 | |
1409 | static CodeLocationLabel startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr) | |
1410 | { | |
1411 | UNREACHABLE_FOR_PLATFORM(); | |
1412 | return CodeLocationLabel(); | |
1413 | } | |
1414 | ||
1415 | static CodeLocationLabel startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label) | |
1416 | { | |
1417 | return label.labelAtOffset(0); | |
1418 | } | |
1419 | ||
1420 | static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID reg, void* initialValue) | |
1421 | { | |
1422 | ARMAssembler::revertBranchPtrWithPatch(instructionStart.dataLocation(), reg, reinterpret_cast<uintptr_t>(initialValue) & 0xffff); | |
1423 | } | |
1424 | ||
81345200 A |
1425 | static void revertJumpReplacementToPatchableBranch32WithPatch(CodeLocationLabel, Address, int32_t) |
1426 | { | |
1427 | UNREACHABLE_FOR_PLATFORM(); | |
1428 | } | |
1429 | ||
93a37866 A |
1430 | static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel, Address, void*) |
1431 | { | |
1432 | UNREACHABLE_FOR_PLATFORM(); | |
1433 | } | |
1434 | ||
81345200 A |
1435 | #if USE(MASM_PROBE) |
1436 | struct CPUState { | |
1437 | #define DECLARE_REGISTER(_type, _regName) \ | |
1438 | _type _regName; | |
1439 | FOR_EACH_CPU_REGISTER(DECLARE_REGISTER) | |
1440 | #undef DECLARE_REGISTER | |
1441 | }; | |
1442 | ||
1443 | struct ProbeContext; | |
1444 | typedef void (*ProbeFunction)(struct ProbeContext*); | |
1445 | ||
1446 | struct ProbeContext { | |
1447 | ProbeFunction probeFunction; | |
1448 | void* arg1; | |
1449 | void* arg2; | |
1450 | CPUState cpu; | |
1451 | ||
1452 | void dump(const char* indentation = 0); | |
1453 | private: | |
1454 | void dumpCPURegisters(const char* indentation); | |
1455 | }; | |
1456 | ||
1457 | // For details about probe(), see comment in MacroAssemblerX86_64.h. | |
1458 | void probe(ProbeFunction, void* arg1 = 0, void* arg2 = 0); | |
1459 | #endif // USE(MASM_PROBE) | |
1460 | ||
f9bf01c6 | 1461 | protected: |
14957cd0 A |
1462 | ARMAssembler::Condition ARMCondition(RelationalCondition cond) |
1463 | { | |
1464 | return static_cast<ARMAssembler::Condition>(cond); | |
1465 | } | |
1466 | ||
1467 | ARMAssembler::Condition ARMCondition(ResultCondition cond) | |
f9bf01c6 A |
1468 | { |
1469 | return static_cast<ARMAssembler::Condition>(cond); | |
1470 | } | |
1471 | ||
1472 | void ensureSpace(int insnSpace, int constSpace) | |
1473 | { | |
1474 | m_assembler.ensureSpace(insnSpace, constSpace); | |
1475 | } | |
1476 | ||
1477 | int sizeOfConstantPool() | |
1478 | { | |
1479 | return m_assembler.sizeOfConstantPool(); | |
1480 | } | |
1481 | ||
f9bf01c6 A |
1482 | void call32(RegisterID base, int32_t offset) |
1483 | { | |
93a37866 A |
1484 | load32(Address(base, offset), ARMRegisters::S1); |
1485 | m_assembler.blx(ARMRegisters::S1); | |
f9bf01c6 A |
1486 | } |
1487 | ||
1488 | private: | |
1489 | friend class LinkBuffer; | |
1490 | friend class RepatchBuffer; | |
1491 | ||
93a37866 A |
1492 | void internalCompare32(RegisterID left, TrustedImm32 right) |
1493 | { | |
1494 | ARMWord tmp = (static_cast<unsigned>(right.m_value) == 0x80000000) ? ARMAssembler::InvalidImmediate : m_assembler.getOp2(-right.m_value); | |
1495 | if (tmp != ARMAssembler::InvalidImmediate) | |
1496 | m_assembler.cmn(left, tmp); | |
1497 | else | |
1498 | m_assembler.cmp(left, m_assembler.getImm(right.m_value, ARMRegisters::S0)); | |
1499 | } | |
1500 | ||
f9bf01c6 A |
1501 | static void linkCall(void* code, Call call, FunctionPtr function) |
1502 | { | |
6fe7ccc8 | 1503 | ARMAssembler::linkCall(code, call.m_label, function.value()); |
f9bf01c6 A |
1504 | } |
1505 | ||
1506 | static void repatchCall(CodeLocationCall call, CodeLocationLabel destination) | |
1507 | { | |
1508 | ARMAssembler::relinkCall(call.dataLocation(), destination.executableAddress()); | |
1509 | } | |
1510 | ||
1511 | static void repatchCall(CodeLocationCall call, FunctionPtr destination) | |
1512 | { | |
1513 | ARMAssembler::relinkCall(call.dataLocation(), destination.executableAddress()); | |
1514 | } | |
1515 | ||
81345200 A |
1516 | #if USE(MASM_PROBE) |
1517 | inline TrustedImm32 trustedImm32FromPtr(void* ptr) | |
1518 | { | |
1519 | return TrustedImm32(TrustedImmPtr(ptr)); | |
1520 | } | |
1521 | ||
1522 | inline TrustedImm32 trustedImm32FromPtr(ProbeFunction function) | |
1523 | { | |
1524 | return TrustedImm32(TrustedImmPtr(reinterpret_cast<void*>(function))); | |
1525 | } | |
1526 | ||
1527 | inline TrustedImm32 trustedImm32FromPtr(void (*function)()) | |
1528 | { | |
1529 | return TrustedImm32(TrustedImmPtr(reinterpret_cast<void*>(function))); | |
1530 | } | |
1531 | #endif | |
1532 | ||
f9bf01c6 A |
1533 | static const bool s_isVFPPresent; |
1534 | }; | |
1535 | ||
1536 | } | |
1537 | ||
1538 | #endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) | |
1539 | ||
1540 | #endif // MacroAssemblerARM_h |