]> git.saurik.com Git - apple/javascriptcore.git/blame - assembler/MacroAssemblerARMv7.h
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / assembler / MacroAssemblerARMv7.h
CommitLineData
ba379fdc 1/*
81345200 2 * Copyright (C) 2009, 2010, 2014 Apple Inc. All rights reserved.
4e4e5a6f 3 * Copyright (C) 2010 University of Szeged
ba379fdc
A
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 APPLE INC. ``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 APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#ifndef MacroAssemblerARMv7_h
28#define MacroAssemblerARMv7_h
29
ba379fdc
A
30#if ENABLE(ASSEMBLER)
31
32#include "ARMv7Assembler.h"
33#include "AbstractMacroAssembler.h"
34
35namespace JSC {
36
ed1e77d3 37class MacroAssemblerARMv7 : public AbstractMacroAssembler<ARMv7Assembler, MacroAssemblerARMv7> {
4e4e5a6f 38 static const RegisterID dataTempRegister = ARMRegisters::ip;
81345200 39 static const RegisterID addressTempRegister = ARMRegisters::r6;
ba379fdc 40
4e4e5a6f
A
41 static const ARMRegisters::FPDoubleRegisterID fpTempRegister = ARMRegisters::d7;
42 inline ARMRegisters::FPSingleRegisterID fpTempRegisterAsSingle() { return ARMRegisters::asSingle(fpTempRegister); }
43
44public:
6fe7ccc8
A
45 MacroAssemblerARMv7()
46 : m_makeJumpPatchable(false)
47 {
48 }
49
b80e6193
A
50 typedef ARMv7Assembler::LinkRecord LinkRecord;
51 typedef ARMv7Assembler::JumpType JumpType;
52 typedef ARMv7Assembler::JumpLinkType JumpLinkType;
93a37866
A
53 typedef ARMv7Assembler::Condition Condition;
54
55 static const ARMv7Assembler::Condition DefaultCondition = ARMv7Assembler::ConditionInvalid;
56 static const ARMv7Assembler::JumpType DefaultJump = ARMv7Assembler::JumpNoConditionFixedSize;
57
58 static bool isCompactPtrAlignedAddressOffset(ptrdiff_t value)
59 {
60 return value >= -255 && value <= 255;
61 }
62
63 Vector<LinkRecord, 0, UnsafeVectorOverflow>& jumpsToLink() { return m_assembler.jumpsToLink(); }
b80e6193 64 void* unlinkedCode() { return m_assembler.unlinkedCode(); }
81345200
A
65 static bool canCompact(JumpType jumpType) { return ARMv7Assembler::canCompact(jumpType); }
66 static JumpLinkType computeJumpType(JumpType jumpType, const uint8_t* from, const uint8_t* to) { return ARMv7Assembler::computeJumpType(jumpType, from, to); }
67 static JumpLinkType computeJumpType(LinkRecord& record, const uint8_t* from, const uint8_t* to) { return ARMv7Assembler::computeJumpType(record, from, to); }
68 static int jumpSizeDelta(JumpType jumpType, JumpLinkType jumpLinkType) { return ARMv7Assembler::jumpSizeDelta(jumpType, jumpLinkType); }
69 static void link(LinkRecord& record, uint8_t* from, uint8_t* to) { return ARMv7Assembler::link(record, from, to); }
b80e6193 70
ba379fdc
A
71 struct ArmAddress {
72 enum AddressType {
73 HasOffset,
74 HasIndex,
75 } type;
76 RegisterID base;
77 union {
78 int32_t offset;
79 struct {
80 RegisterID index;
81 Scale scale;
82 };
83 } u;
84
85 explicit ArmAddress(RegisterID base, int32_t offset = 0)
86 : type(HasOffset)
87 , base(base)
88 {
89 u.offset = offset;
90 }
91
92 explicit ArmAddress(RegisterID base, RegisterID index, Scale scale = TimesOne)
93 : type(HasIndex)
94 , base(base)
95 {
96 u.index = index;
97 u.scale = scale;
98 }
99 };
100
101public:
ba379fdc
A
102 static const Scale ScalePtr = TimesFour;
103
14957cd0 104 enum RelationalCondition {
ba379fdc
A
105 Equal = ARMv7Assembler::ConditionEQ,
106 NotEqual = ARMv7Assembler::ConditionNE,
107 Above = ARMv7Assembler::ConditionHI,
108 AboveOrEqual = ARMv7Assembler::ConditionHS,
109 Below = ARMv7Assembler::ConditionLO,
110 BelowOrEqual = ARMv7Assembler::ConditionLS,
111 GreaterThan = ARMv7Assembler::ConditionGT,
112 GreaterThanOrEqual = ARMv7Assembler::ConditionGE,
113 LessThan = ARMv7Assembler::ConditionLT,
14957cd0
A
114 LessThanOrEqual = ARMv7Assembler::ConditionLE
115 };
116
117 enum ResultCondition {
ba379fdc
A
118 Overflow = ARMv7Assembler::ConditionVS,
119 Signed = ARMv7Assembler::ConditionMI,
93a37866 120 PositiveOrZero = ARMv7Assembler::ConditionPL,
ba379fdc
A
121 Zero = ARMv7Assembler::ConditionEQ,
122 NonZero = ARMv7Assembler::ConditionNE
123 };
14957cd0 124
ba379fdc 125 enum DoubleCondition {
f9bf01c6 126 // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
ba379fdc 127 DoubleEqual = ARMv7Assembler::ConditionEQ,
f9bf01c6 128 DoubleNotEqual = ARMv7Assembler::ConditionVC, // Not the right flag! check for this & handle differently.
ba379fdc
A
129 DoubleGreaterThan = ARMv7Assembler::ConditionGT,
130 DoubleGreaterThanOrEqual = ARMv7Assembler::ConditionGE,
131 DoubleLessThan = ARMv7Assembler::ConditionLO,
132 DoubleLessThanOrEqual = ARMv7Assembler::ConditionLS,
f9bf01c6
A
133 // If either operand is NaN, these conditions always evaluate to true.
134 DoubleEqualOrUnordered = ARMv7Assembler::ConditionVS, // Not the right flag! check for this & handle differently.
135 DoubleNotEqualOrUnordered = ARMv7Assembler::ConditionNE,
136 DoubleGreaterThanOrUnordered = ARMv7Assembler::ConditionHI,
137 DoubleGreaterThanOrEqualOrUnordered = ARMv7Assembler::ConditionHS,
138 DoubleLessThanOrUnordered = ARMv7Assembler::ConditionLT,
139 DoubleLessThanOrEqualOrUnordered = ARMv7Assembler::ConditionLE,
ba379fdc
A
140 };
141
f9bf01c6 142 static const RegisterID stackPointerRegister = ARMRegisters::sp;
81345200 143 static const RegisterID framePointerRegister = ARMRegisters::fp;
f9bf01c6 144 static const RegisterID linkRegister = ARMRegisters::lr;
ba379fdc
A
145
146 // Integer arithmetic operations:
147 //
148 // Operations are typically two operand - operation(source, srcDst)
14957cd0 149 // For many operations the source may be an TrustedImm32, the srcDst operand
ba379fdc
A
150 // may often be a memory location (explictly described using an Address
151 // object).
152
153 void add32(RegisterID src, RegisterID dest)
154 {
155 m_assembler.add(dest, dest, src);
156 }
157
14957cd0 158 void add32(TrustedImm32 imm, RegisterID dest)
ba379fdc
A
159 {
160 add32(imm, dest, dest);
161 }
93a37866
A
162
163 void add32(AbsoluteAddress src, RegisterID dest)
164 {
165 load32(src.m_ptr, dataTempRegister);
166 add32(dataTempRegister, dest);
167 }
ba379fdc 168
14957cd0 169 void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
ba379fdc
A
170 {
171 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
81345200
A
172
173 // For adds with stack pointer destination, moving the src first to sp is
174 // needed to avoid unpredictable instruction
175 if (dest == ARMRegisters::sp && src != dest) {
176 move(src, ARMRegisters::sp);
177 src = ARMRegisters::sp;
178 }
179
ba379fdc
A
180 if (armImm.isValid())
181 m_assembler.add(dest, src, armImm);
182 else {
183 move(imm, dataTempRegister);
184 m_assembler.add(dest, src, dataTempRegister);
185 }
186 }
187
14957cd0 188 void add32(TrustedImm32 imm, Address address)
ba379fdc
A
189 {
190 load32(address, dataTempRegister);
191
192 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
193 if (armImm.isValid())
194 m_assembler.add(dataTempRegister, dataTempRegister, armImm);
195 else {
196 // Hrrrm, since dataTempRegister holds the data loaded,
197 // use addressTempRegister to hold the immediate.
198 move(imm, addressTempRegister);
199 m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister);
200 }
201
202 store32(dataTempRegister, address);
203 }
204
205 void add32(Address src, RegisterID dest)
206 {
207 load32(src, dataTempRegister);
208 add32(dataTempRegister, dest);
209 }
210
14957cd0 211 void add32(TrustedImm32 imm, AbsoluteAddress address)
ba379fdc
A
212 {
213 load32(address.m_ptr, dataTempRegister);
214
215 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
216 if (armImm.isValid())
217 m_assembler.add(dataTempRegister, dataTempRegister, armImm);
218 else {
219 // Hrrrm, since dataTempRegister holds the data loaded,
220 // use addressTempRegister to hold the immediate.
221 move(imm, addressTempRegister);
222 m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister);
223 }
224
225 store32(dataTempRegister, address.m_ptr);
226 }
227
81345200
A
228 void addPtrNoFlags(TrustedImm32 imm, RegisterID srcDest)
229 {
230 add32(imm, srcDest);
231 }
232
6fe7ccc8
A
233 void add64(TrustedImm32 imm, AbsoluteAddress address)
234 {
235 move(TrustedImmPtr(address.m_ptr), addressTempRegister);
236
237 m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(0));
238 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
239 if (armImm.isValid())
240 m_assembler.add_S(dataTempRegister, dataTempRegister, armImm);
241 else {
242 move(imm, addressTempRegister);
243 m_assembler.add_S(dataTempRegister, dataTempRegister, addressTempRegister);
244 move(TrustedImmPtr(address.m_ptr), addressTempRegister);
245 }
246 m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(0));
247
248 m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(4));
249 m_assembler.adc(dataTempRegister, dataTempRegister, ARMThumbImmediate::makeEncodedImm(imm.m_value >> 31));
250 m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(4));
251 }
252
253 void and32(RegisterID op1, RegisterID op2, RegisterID dest)
ba379fdc 254 {
6fe7ccc8 255 m_assembler.ARM_and(dest, op1, op2);
ba379fdc
A
256 }
257
6fe7ccc8 258 void and32(TrustedImm32 imm, RegisterID src, RegisterID dest)
ba379fdc
A
259 {
260 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
261 if (armImm.isValid())
6fe7ccc8 262 m_assembler.ARM_and(dest, src, armImm);
ba379fdc
A
263 else {
264 move(imm, dataTempRegister);
6fe7ccc8 265 m_assembler.ARM_and(dest, src, dataTempRegister);
ba379fdc
A
266 }
267 }
268
6fe7ccc8
A
269 void and32(RegisterID src, RegisterID dest)
270 {
271 and32(dest, src, dest);
272 }
273
274 void and32(TrustedImm32 imm, RegisterID dest)
275 {
276 and32(imm, dest, dest);
277 }
278
93a37866
A
279 void and32(Address src, RegisterID dest)
280 {
281 load32(src, dataTempRegister);
282 and32(dataTempRegister, dest);
283 }
284
14957cd0
A
285 void countLeadingZeros32(RegisterID src, RegisterID dest)
286 {
287 m_assembler.clz(dest, src);
288 }
289
6fe7ccc8 290 void lshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
ba379fdc 291 {
f9bf01c6
A
292 // Clamp the shift to the range 0..31
293 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
294 ASSERT(armImm.isValid());
6fe7ccc8
A
295 m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm);
296
297 m_assembler.lsl(dest, src, dataTempRegister);
298 }
f9bf01c6 299
6fe7ccc8
A
300 void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
301 {
302 m_assembler.lsl(dest, src, imm.m_value & 0x1f);
303 }
304
305 void lshift32(RegisterID shiftAmount, RegisterID dest)
306 {
307 lshift32(dest, shiftAmount, dest);
ba379fdc
A
308 }
309
14957cd0 310 void lshift32(TrustedImm32 imm, RegisterID dest)
ba379fdc 311 {
6fe7ccc8 312 lshift32(dest, imm, dest);
ba379fdc
A
313 }
314
315 void mul32(RegisterID src, RegisterID dest)
316 {
317 m_assembler.smull(dest, dataTempRegister, dest, src);
318 }
319
14957cd0 320 void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
ba379fdc
A
321 {
322 move(imm, dataTempRegister);
323 m_assembler.smull(dest, dataTempRegister, src, dataTempRegister);
324 }
325
4e4e5a6f
A
326 void neg32(RegisterID srcDest)
327 {
328 m_assembler.neg(srcDest, srcDest);
329 }
330
ba379fdc
A
331 void or32(RegisterID src, RegisterID dest)
332 {
333 m_assembler.orr(dest, dest, src);
334 }
93a37866
A
335
336 void or32(RegisterID src, AbsoluteAddress dest)
337 {
338 move(TrustedImmPtr(dest.m_ptr), addressTempRegister);
339 load32(addressTempRegister, dataTempRegister);
340 or32(src, dataTempRegister);
341 store32(dataTempRegister, addressTempRegister);
342 }
ba379fdc 343
81345200
A
344 void or32(TrustedImm32 imm, Address address)
345 {
346 load32(address, dataTempRegister);
347 or32(imm, dataTempRegister, dataTempRegister);
348 store32(dataTempRegister, address);
349 }
350
14957cd0 351 void or32(TrustedImm32 imm, RegisterID dest)
6fe7ccc8
A
352 {
353 or32(imm, dest, dest);
354 }
355
356 void or32(RegisterID op1, RegisterID op2, RegisterID dest)
357 {
358 m_assembler.orr(dest, op1, op2);
359 }
360
361 void or32(TrustedImm32 imm, RegisterID src, RegisterID dest)
ba379fdc
A
362 {
363 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
364 if (armImm.isValid())
6fe7ccc8 365 m_assembler.orr(dest, src, armImm);
ba379fdc
A
366 else {
367 move(imm, dataTempRegister);
6fe7ccc8 368 m_assembler.orr(dest, src, dataTempRegister);
ba379fdc
A
369 }
370 }
371
6fe7ccc8 372 void rshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
ba379fdc 373 {
f9bf01c6
A
374 // Clamp the shift to the range 0..31
375 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
376 ASSERT(armImm.isValid());
6fe7ccc8 377 m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm);
f9bf01c6 378
6fe7ccc8 379 m_assembler.asr(dest, src, dataTempRegister);
ba379fdc
A
380 }
381
6fe7ccc8
A
382 void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
383 {
384 m_assembler.asr(dest, src, imm.m_value & 0x1f);
385 }
386
387 void rshift32(RegisterID shiftAmount, RegisterID dest)
ba379fdc 388 {
6fe7ccc8 389 rshift32(dest, shiftAmount, dest);
ba379fdc 390 }
4e4e5a6f 391
6fe7ccc8
A
392 void rshift32(TrustedImm32 imm, RegisterID dest)
393 {
394 rshift32(dest, imm, dest);
395 }
396
397 void urshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
4e4e5a6f
A
398 {
399 // Clamp the shift to the range 0..31
400 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
401 ASSERT(armImm.isValid());
6fe7ccc8 402 m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm);
4e4e5a6f 403
6fe7ccc8
A
404 m_assembler.lsr(dest, src, dataTempRegister);
405 }
406
407 void urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
408 {
409 m_assembler.lsr(dest, src, imm.m_value & 0x1f);
410 }
411
412 void urshift32(RegisterID shiftAmount, RegisterID dest)
413 {
414 urshift32(dest, shiftAmount, dest);
4e4e5a6f
A
415 }
416
14957cd0 417 void urshift32(TrustedImm32 imm, RegisterID dest)
4e4e5a6f 418 {
6fe7ccc8 419 urshift32(dest, imm, dest);
4e4e5a6f 420 }
ba379fdc
A
421
422 void sub32(RegisterID src, RegisterID dest)
423 {
424 m_assembler.sub(dest, dest, src);
425 }
426
14957cd0 427 void sub32(TrustedImm32 imm, RegisterID dest)
ba379fdc
A
428 {
429 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
430 if (armImm.isValid())
431 m_assembler.sub(dest, dest, armImm);
432 else {
433 move(imm, dataTempRegister);
434 m_assembler.sub(dest, dest, dataTempRegister);
435 }
436 }
437
14957cd0 438 void sub32(TrustedImm32 imm, Address address)
ba379fdc
A
439 {
440 load32(address, dataTempRegister);
441
442 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
443 if (armImm.isValid())
444 m_assembler.sub(dataTempRegister, dataTempRegister, armImm);
445 else {
446 // Hrrrm, since dataTempRegister holds the data loaded,
447 // use addressTempRegister to hold the immediate.
448 move(imm, addressTempRegister);
449 m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister);
450 }
451
452 store32(dataTempRegister, address);
453 }
454
455 void sub32(Address src, RegisterID dest)
456 {
457 load32(src, dataTempRegister);
458 sub32(dataTempRegister, dest);
459 }
460
14957cd0 461 void sub32(TrustedImm32 imm, AbsoluteAddress address)
ba379fdc
A
462 {
463 load32(address.m_ptr, dataTempRegister);
464
465 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
466 if (armImm.isValid())
467 m_assembler.sub(dataTempRegister, dataTempRegister, armImm);
468 else {
469 // Hrrrm, since dataTempRegister holds the data loaded,
470 // use addressTempRegister to hold the immediate.
471 move(imm, addressTempRegister);
472 m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister);
473 }
474
475 store32(dataTempRegister, address.m_ptr);
476 }
477
6fe7ccc8 478 void xor32(RegisterID op1, RegisterID op2, RegisterID dest)
ba379fdc 479 {
6fe7ccc8 480 m_assembler.eor(dest, op1, op2);
ba379fdc
A
481 }
482
6fe7ccc8 483 void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest)
ba379fdc 484 {
6fe7ccc8
A
485 if (imm.m_value == -1) {
486 m_assembler.mvn(dest, src);
487 return;
488 }
489
ba379fdc
A
490 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
491 if (armImm.isValid())
6fe7ccc8 492 m_assembler.eor(dest, src, armImm);
ba379fdc
A
493 else {
494 move(imm, dataTempRegister);
6fe7ccc8 495 m_assembler.eor(dest, src, dataTempRegister);
ba379fdc
A
496 }
497 }
6fe7ccc8
A
498
499 void xor32(RegisterID src, RegisterID dest)
500 {
501 xor32(dest, src, dest);
502 }
503
504 void xor32(TrustedImm32 imm, RegisterID dest)
505 {
506 if (imm.m_value == -1)
507 m_assembler.mvn(dest, dest);
508 else
509 xor32(imm, dest, dest);
510 }
ba379fdc
A
511
512
513 // Memory access operations:
514 //
515 // Loads are of the form load(address, destination) and stores of the form
14957cd0 516 // store(source, address). The source for a store may be an TrustedImm32. Address
ba379fdc
A
517 // operand objects to loads and store will be implicitly constructed if a
518 // register is passed.
519
520private:
521 void load32(ArmAddress address, RegisterID dest)
522 {
523 if (address.type == ArmAddress::HasIndex)
524 m_assembler.ldr(dest, address.base, address.u.index, address.u.scale);
525 else if (address.u.offset >= 0) {
526 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
527 ASSERT(armImm.isValid());
528 m_assembler.ldr(dest, address.base, armImm);
529 } else {
530 ASSERT(address.u.offset >= -255);
531 m_assembler.ldr(dest, address.base, address.u.offset, true, false);
532 }
533 }
534
535 void load16(ArmAddress address, RegisterID dest)
536 {
537 if (address.type == ArmAddress::HasIndex)
538 m_assembler.ldrh(dest, address.base, address.u.index, address.u.scale);
539 else if (address.u.offset >= 0) {
540 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
541 ASSERT(armImm.isValid());
542 m_assembler.ldrh(dest, address.base, armImm);
543 } else {
544 ASSERT(address.u.offset >= -255);
545 m_assembler.ldrh(dest, address.base, address.u.offset, true, false);
546 }
547 }
6fe7ccc8 548
ed1e77d3 549 void load16SignedExtendTo32(ArmAddress address, RegisterID dest)
6fe7ccc8
A
550 {
551 ASSERT(address.type == ArmAddress::HasIndex);
552 m_assembler.ldrsh(dest, address.base, address.u.index, address.u.scale);
553 }
ba379fdc 554
4e4e5a6f
A
555 void load8(ArmAddress address, RegisterID dest)
556 {
557 if (address.type == ArmAddress::HasIndex)
558 m_assembler.ldrb(dest, address.base, address.u.index, address.u.scale);
559 else if (address.u.offset >= 0) {
560 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
561 ASSERT(armImm.isValid());
562 m_assembler.ldrb(dest, address.base, armImm);
563 } else {
564 ASSERT(address.u.offset >= -255);
565 m_assembler.ldrb(dest, address.base, address.u.offset, true, false);
566 }
567 }
6fe7ccc8 568
ed1e77d3 569 void load8SignedExtendTo32(ArmAddress address, RegisterID dest)
6fe7ccc8
A
570 {
571 ASSERT(address.type == ArmAddress::HasIndex);
572 m_assembler.ldrsb(dest, address.base, address.u.index, address.u.scale);
573 }
4e4e5a6f 574
6fe7ccc8 575protected:
ba379fdc
A
576 void store32(RegisterID src, ArmAddress address)
577 {
578 if (address.type == ArmAddress::HasIndex)
579 m_assembler.str(src, address.base, address.u.index, address.u.scale);
580 else if (address.u.offset >= 0) {
581 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
582 ASSERT(armImm.isValid());
583 m_assembler.str(src, address.base, armImm);
584 } else {
585 ASSERT(address.u.offset >= -255);
586 m_assembler.str(src, address.base, address.u.offset, true, false);
587 }
588 }
589
6fe7ccc8
A
590private:
591 void store8(RegisterID src, ArmAddress address)
592 {
593 if (address.type == ArmAddress::HasIndex)
594 m_assembler.strb(src, address.base, address.u.index, address.u.scale);
595 else if (address.u.offset >= 0) {
596 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
597 ASSERT(armImm.isValid());
598 m_assembler.strb(src, address.base, armImm);
599 } else {
600 ASSERT(address.u.offset >= -255);
601 m_assembler.strb(src, address.base, address.u.offset, true, false);
602 }
603 }
604
605 void store16(RegisterID src, ArmAddress address)
606 {
607 if (address.type == ArmAddress::HasIndex)
608 m_assembler.strh(src, address.base, address.u.index, address.u.scale);
609 else if (address.u.offset >= 0) {
610 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
611 ASSERT(armImm.isValid());
612 m_assembler.strh(src, address.base, armImm);
613 } else {
614 ASSERT(address.u.offset >= -255);
615 m_assembler.strh(src, address.base, address.u.offset, true, false);
616 }
617 }
618
ba379fdc
A
619public:
620 void load32(ImplicitAddress address, RegisterID dest)
621 {
622 load32(setupArmAddress(address), dest);
623 }
624
625 void load32(BaseIndex address, RegisterID dest)
626 {
627 load32(setupArmAddress(address), dest);
628 }
629
f9bf01c6
A
630 void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
631 {
632 load32(setupArmAddress(address), dest);
633 }
634
6fe7ccc8
A
635 void load16Unaligned(BaseIndex address, RegisterID dest)
636 {
637 load16(setupArmAddress(address), dest);
638 }
639
14957cd0 640 void load32(const void* address, RegisterID dest)
ba379fdc 641 {
14957cd0 642 move(TrustedImmPtr(address), addressTempRegister);
ba379fdc
A
643 m_assembler.ldr(dest, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
644 }
93a37866 645
81345200
A
646 void abortWithReason(AbortReason reason)
647 {
648 move(TrustedImm32(reason), dataTempRegister);
649 breakpoint();
650 }
651
652 void abortWithReason(AbortReason reason, intptr_t misc)
653 {
654 move(TrustedImm32(misc), addressTempRegister);
655 abortWithReason(reason);
656 }
657
93a37866
A
658 ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest)
659 {
660 ConvertibleLoadLabel result(this);
661 ASSERT(address.offset >= 0 && address.offset <= 255);
662 m_assembler.ldrWide8BitImmediate(dest, address.base, address.offset);
663 return result;
664 }
ba379fdc 665
4e4e5a6f
A
666 void load8(ImplicitAddress address, RegisterID dest)
667 {
668 load8(setupArmAddress(address), dest);
669 }
670
ed1e77d3 671 void load8SignedExtendTo32(ImplicitAddress, RegisterID)
6fe7ccc8 672 {
93a37866 673 UNREACHABLE_FOR_PLATFORM();
6fe7ccc8
A
674 }
675
676 void load8(BaseIndex address, RegisterID dest)
677 {
678 load8(setupArmAddress(address), dest);
679 }
680
ed1e77d3 681 void load8SignedExtendTo32(BaseIndex address, RegisterID dest)
6fe7ccc8 682 {
ed1e77d3 683 load8SignedExtendTo32(setupArmAddress(address), dest);
6fe7ccc8
A
684 }
685
81345200
A
686 void load8(const void* address, RegisterID dest)
687 {
688 move(TrustedImmPtr(address), dest);
689 load8(dest, dest);
690 }
691
ba379fdc
A
692 DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
693 {
14957cd0 694 DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
ba379fdc
A
695 load32(ArmAddress(address.base, dataTempRegister), dest);
696 return label;
697 }
14957cd0
A
698
699 DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
ba379fdc 700 {
93a37866
A
701 padBeforePatch();
702
6fe7ccc8
A
703 RegisterID base = address.base;
704
14957cd0 705 DataLabelCompact label(this);
93a37866
A
706 ASSERT(isCompactPtrAlignedAddressOffset(address.offset));
707
708 m_assembler.ldr(dest, base, address.offset, true, false);
ba379fdc
A
709 return label;
710 }
711
712 void load16(BaseIndex address, RegisterID dest)
713 {
714 m_assembler.ldrh(dest, makeBaseIndexBase(address), address.index, address.scale);
715 }
4e4e5a6f 716
ed1e77d3 717 void load16SignedExtendTo32(BaseIndex address, RegisterID dest)
6fe7ccc8 718 {
ed1e77d3 719 load16SignedExtendTo32(setupArmAddress(address), dest);
6fe7ccc8
A
720 }
721
4e4e5a6f
A
722 void load16(ImplicitAddress address, RegisterID dest)
723 {
724 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.offset);
725 if (armImm.isValid())
726 m_assembler.ldrh(dest, address.base, armImm);
727 else {
14957cd0 728 move(TrustedImm32(address.offset), dataTempRegister);
4e4e5a6f
A
729 m_assembler.ldrh(dest, address.base, dataTempRegister);
730 }
731 }
6fe7ccc8 732
ed1e77d3 733 void load16SignedExtendTo32(ImplicitAddress, RegisterID)
6fe7ccc8 734 {
93a37866 735 UNREACHABLE_FOR_PLATFORM();
6fe7ccc8 736 }
ba379fdc
A
737
738 DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
739 {
14957cd0 740 DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
ba379fdc
A
741 store32(src, ArmAddress(address.base, dataTempRegister));
742 return label;
743 }
744
745 void store32(RegisterID src, ImplicitAddress address)
746 {
747 store32(src, setupArmAddress(address));
748 }
749
750 void store32(RegisterID src, BaseIndex address)
751 {
752 store32(src, setupArmAddress(address));
753 }
754
14957cd0 755 void store32(TrustedImm32 imm, ImplicitAddress address)
ba379fdc
A
756 {
757 move(imm, dataTempRegister);
758 store32(dataTempRegister, setupArmAddress(address));
759 }
760
6fe7ccc8
A
761 void store32(TrustedImm32 imm, BaseIndex address)
762 {
763 move(imm, dataTempRegister);
764 store32(dataTempRegister, setupArmAddress(address));
765 }
766
14957cd0 767 void store32(RegisterID src, const void* address)
ba379fdc 768 {
14957cd0 769 move(TrustedImmPtr(address), addressTempRegister);
ba379fdc
A
770 m_assembler.str(src, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
771 }
772
14957cd0 773 void store32(TrustedImm32 imm, const void* address)
ba379fdc
A
774 {
775 move(imm, dataTempRegister);
776 store32(dataTempRegister, address);
777 }
778
81345200
A
779 void store8(RegisterID src, Address address)
780 {
781 store8(src, setupArmAddress(address));
782 }
783
6fe7ccc8
A
784 void store8(RegisterID src, BaseIndex address)
785 {
786 store8(src, setupArmAddress(address));
787 }
788
93a37866
A
789 void store8(RegisterID src, void* address)
790 {
791 move(TrustedImmPtr(address), addressTempRegister);
792 store8(src, ArmAddress(addressTempRegister, 0));
793 }
794
795 void store8(TrustedImm32 imm, void* address)
796 {
797 move(imm, dataTempRegister);
798 store8(dataTempRegister, address);
799 }
800
81345200
A
801 void store8(TrustedImm32 imm, Address address)
802 {
803 move(imm, dataTempRegister);
804 store8(dataTempRegister, address);
805 }
806
6fe7ccc8
A
807 void store16(RegisterID src, BaseIndex address)
808 {
809 store16(src, setupArmAddress(address));
810 }
ba379fdc 811
93a37866
A
812 // Possibly clobbers src, but not on this architecture.
813 void moveDoubleToInts(FPRegisterID src, RegisterID dest1, RegisterID dest2)
814 {
815 m_assembler.vmov(dest1, dest2, src);
816 }
817
818 void moveIntsToDouble(RegisterID src1, RegisterID src2, FPRegisterID dest, FPRegisterID scratch)
819 {
820 UNUSED_PARAM(scratch);
821 m_assembler.vmov(dest, src1, src2);
822 }
823
6fe7ccc8
A
824 static bool shouldBlindForSpecificArch(uint32_t value)
825 {
826 ARMThumbImmediate immediate = ARMThumbImmediate::makeEncodedImm(value);
ba379fdc 827
6fe7ccc8
A
828 // Couldn't be encoded as an immediate, so assume it's untrusted.
829 if (!immediate.isValid())
830 return true;
831
832 // If we can encode the immediate, we have less than 16 attacker
833 // controlled bits.
834 if (immediate.isEncodedImm())
835 return false;
ba379fdc 836
6fe7ccc8
A
837 // Don't let any more than 12 bits of an instruction word
838 // be controlled by an attacker.
839 return !immediate.isUInt12();
4e4e5a6f 840 }
6fe7ccc8
A
841
842 // Floating-point operations:
843
844 static bool supportsFloatingPoint() { return true; }
845 static bool supportsFloatingPointTruncate() { return true; }
846 static bool supportsFloatingPointSqrt() { return true; }
847 static bool supportsFloatingPointAbs() { return true; }
4e4e5a6f 848
ba379fdc
A
849 void loadDouble(ImplicitAddress address, FPRegisterID dest)
850 {
851 RegisterID base = address.base;
852 int32_t offset = address.offset;
853
854 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
855 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
14957cd0 856 add32(TrustedImm32(offset), base, addressTempRegister);
ba379fdc
A
857 base = addressTempRegister;
858 offset = 0;
859 }
860
861 m_assembler.vldr(dest, base, offset);
862 }
863
6fe7ccc8
A
864 void loadFloat(ImplicitAddress address, FPRegisterID dest)
865 {
866 RegisterID base = address.base;
867 int32_t offset = address.offset;
868
869 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
870 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
871 add32(TrustedImm32(offset), base, addressTempRegister);
872 base = addressTempRegister;
873 offset = 0;
874 }
875
876 m_assembler.flds(ARMRegisters::asSingle(dest), base, offset);
877 }
878
879 void loadDouble(BaseIndex address, FPRegisterID dest)
880 {
881 move(address.index, addressTempRegister);
882 lshift32(TrustedImm32(address.scale), addressTempRegister);
883 add32(address.base, addressTempRegister);
884 loadDouble(Address(addressTempRegister, address.offset), dest);
885 }
886
887 void loadFloat(BaseIndex address, FPRegisterID dest)
888 {
889 move(address.index, addressTempRegister);
890 lshift32(TrustedImm32(address.scale), addressTempRegister);
891 add32(address.base, addressTempRegister);
892 loadFloat(Address(addressTempRegister, address.offset), dest);
893 }
894
895 void moveDouble(FPRegisterID src, FPRegisterID dest)
896 {
897 if (src != dest)
898 m_assembler.vmov(dest, src);
899 }
900
81345200 901 void loadDouble(TrustedImmPtr address, FPRegisterID dest)
4e4e5a6f 902 {
81345200 903 move(address, addressTempRegister);
4e4e5a6f
A
904 m_assembler.vldr(dest, addressTempRegister, 0);
905 }
906
ba379fdc
A
907 void storeDouble(FPRegisterID src, ImplicitAddress address)
908 {
909 RegisterID base = address.base;
910 int32_t offset = address.offset;
911
912 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
913 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
14957cd0 914 add32(TrustedImm32(offset), base, addressTempRegister);
ba379fdc
A
915 base = addressTempRegister;
916 offset = 0;
917 }
918
919 m_assembler.vstr(src, base, offset);
920 }
921
6fe7ccc8
A
922 void storeFloat(FPRegisterID src, ImplicitAddress address)
923 {
924 RegisterID base = address.base;
925 int32_t offset = address.offset;
926
927 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
928 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
929 add32(TrustedImm32(offset), base, addressTempRegister);
930 base = addressTempRegister;
931 offset = 0;
932 }
933
934 m_assembler.fsts(ARMRegisters::asSingle(src), base, offset);
935 }
936
81345200 937 void storeDouble(FPRegisterID src, TrustedImmPtr address)
6fe7ccc8 938 {
81345200 939 move(address, addressTempRegister);
6fe7ccc8
A
940 storeDouble(src, addressTempRegister);
941 }
942
943 void storeDouble(FPRegisterID src, BaseIndex address)
944 {
945 move(address.index, addressTempRegister);
946 lshift32(TrustedImm32(address.scale), addressTempRegister);
947 add32(address.base, addressTempRegister);
948 storeDouble(src, Address(addressTempRegister, address.offset));
949 }
950
951 void storeFloat(FPRegisterID src, BaseIndex address)
952 {
953 move(address.index, addressTempRegister);
954 lshift32(TrustedImm32(address.scale), addressTempRegister);
955 add32(address.base, addressTempRegister);
956 storeFloat(src, Address(addressTempRegister, address.offset));
957 }
958
ba379fdc
A
959 void addDouble(FPRegisterID src, FPRegisterID dest)
960 {
6fe7ccc8 961 m_assembler.vadd(dest, dest, src);
ba379fdc
A
962 }
963
964 void addDouble(Address src, FPRegisterID dest)
965 {
966 loadDouble(src, fpTempRegister);
967 addDouble(fpTempRegister, dest);
968 }
969
6fe7ccc8
A
970 void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
971 {
972 m_assembler.vadd(dest, op1, op2);
973 }
974
975 void addDouble(AbsoluteAddress address, FPRegisterID dest)
976 {
81345200 977 loadDouble(TrustedImmPtr(address.m_ptr), fpTempRegister);
6fe7ccc8
A
978 m_assembler.vadd(dest, dest, fpTempRegister);
979 }
980
4e4e5a6f
A
981 void divDouble(FPRegisterID src, FPRegisterID dest)
982 {
6fe7ccc8
A
983 m_assembler.vdiv(dest, dest, src);
984 }
985
986 void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
987 {
988 m_assembler.vdiv(dest, op1, op2);
4e4e5a6f
A
989 }
990
ba379fdc
A
991 void subDouble(FPRegisterID src, FPRegisterID dest)
992 {
6fe7ccc8 993 m_assembler.vsub(dest, dest, src);
ba379fdc
A
994 }
995
996 void subDouble(Address src, FPRegisterID dest)
997 {
998 loadDouble(src, fpTempRegister);
999 subDouble(fpTempRegister, dest);
1000 }
1001
6fe7ccc8
A
1002 void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1003 {
1004 m_assembler.vsub(dest, op1, op2);
1005 }
1006
ba379fdc
A
1007 void mulDouble(FPRegisterID src, FPRegisterID dest)
1008 {
6fe7ccc8 1009 m_assembler.vmul(dest, dest, src);
ba379fdc
A
1010 }
1011
1012 void mulDouble(Address src, FPRegisterID dest)
1013 {
1014 loadDouble(src, fpTempRegister);
1015 mulDouble(fpTempRegister, dest);
1016 }
1017
6fe7ccc8
A
1018 void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1019 {
1020 m_assembler.vmul(dest, op1, op2);
1021 }
1022
1023 void sqrtDouble(FPRegisterID src, FPRegisterID dest)
1024 {
1025 m_assembler.vsqrt(dest, src);
1026 }
1027
1028 void absDouble(FPRegisterID src, FPRegisterID dest)
1029 {
1030 m_assembler.vabs(dest, src);
1031 }
1032
1033 void negateDouble(FPRegisterID src, FPRegisterID dest)
4e4e5a6f 1034 {
6fe7ccc8 1035 m_assembler.vneg(dest, src);
4e4e5a6f
A
1036 }
1037
ba379fdc
A
1038 void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
1039 {
6fe7ccc8
A
1040 m_assembler.vmov(fpTempRegister, src, src);
1041 m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
4e4e5a6f
A
1042 }
1043
1044 void convertInt32ToDouble(Address address, FPRegisterID dest)
1045 {
1046 // Fixme: load directly into the fpr!
1047 load32(address, dataTempRegister);
6fe7ccc8
A
1048 m_assembler.vmov(fpTempRegister, dataTempRegister, dataTempRegister);
1049 m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
4e4e5a6f
A
1050 }
1051
1052 void convertInt32ToDouble(AbsoluteAddress address, FPRegisterID dest)
1053 {
1054 // Fixme: load directly into the fpr!
1055 load32(address.m_ptr, dataTempRegister);
6fe7ccc8
A
1056 m_assembler.vmov(fpTempRegister, dataTempRegister, dataTempRegister);
1057 m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
1058 }
1059
1060 void convertFloatToDouble(FPRegisterID src, FPRegisterID dst)
1061 {
1062 m_assembler.vcvtds(dst, ARMRegisters::asSingle(src));
1063 }
1064
1065 void convertDoubleToFloat(FPRegisterID src, FPRegisterID dst)
1066 {
1067 m_assembler.vcvtsd(ARMRegisters::asSingle(dst), src);
ba379fdc
A
1068 }
1069
1070 Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
1071 {
6fe7ccc8 1072 m_assembler.vcmp(left, right);
4e4e5a6f 1073 m_assembler.vmrs();
f9bf01c6
A
1074
1075 if (cond == DoubleNotEqual) {
1076 // ConditionNE jumps if NotEqual *or* unordered - force the unordered cases not to jump.
1077 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1078 Jump result = makeBranch(ARMv7Assembler::ConditionNE);
1079 unordered.link(this);
1080 return result;
1081 }
1082 if (cond == DoubleEqualOrUnordered) {
1083 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1084 Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
1085 unordered.link(this);
b80e6193 1086 // We get here if either unordered or equal.
14957cd0 1087 Jump result = jump();
f9bf01c6
A
1088 notEqual.link(this);
1089 return result;
1090 }
ba379fdc
A
1091 return makeBranch(cond);
1092 }
1093
6fe7ccc8
A
1094 enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful };
1095 Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
ba379fdc 1096 {
6fe7ccc8
A
1097 // Convert into dest.
1098 m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1099 m_assembler.vmov(dest, fpTempRegisterAsSingle());
1100
1101 // Calculate 2x dest. If the value potentially underflowed, it will have
1102 // clamped to 0x80000000, so 2x dest is zero in this case. In the case of
1103 // overflow the result will be equal to -2.
1104 Jump underflow = branchAdd32(Zero, dest, dest, dataTempRegister);
1105 Jump noOverflow = branch32(NotEqual, dataTempRegister, TrustedImm32(-2));
1106
1107 // For BranchIfTruncateSuccessful, we branch if 'noOverflow' jumps.
1108 underflow.link(this);
1109 if (branchType == BranchIfTruncateSuccessful)
1110 return noOverflow;
1111
1112 // We'll reach the current point in the code on failure, so plant a
1113 // jump here & link the success case.
1114 Jump failure = jump();
1115 noOverflow.link(this);
1116 return failure;
ba379fdc
A
1117 }
1118
6fe7ccc8
A
1119 // Result is undefined if the value is outside of the integer range.
1120 void truncateDoubleToInt32(FPRegisterID src, RegisterID dest)
1121 {
1122 m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1123 m_assembler.vmov(dest, fpTempRegisterAsSingle());
1124 }
1125
1126 void truncateDoubleToUint32(FPRegisterID src, RegisterID dest)
1127 {
1128 m_assembler.vcvt_floatingPointToUnsigned(fpTempRegisterAsSingle(), src);
1129 m_assembler.vmov(dest, fpTempRegisterAsSingle());
1130 }
1131
4e4e5a6f
A
1132 // Convert 'src' to an integer, and places the resulting 'dest'.
1133 // If the result is not representable as a 32 bit value, branch.
1134 // May also branch for some values that are representable in 32 bits
1135 // (specifically, in this case, 0).
93a37866 1136 void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID, bool negZeroCheck = true)
4e4e5a6f 1137 {
6fe7ccc8 1138 m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
4e4e5a6f
A
1139 m_assembler.vmov(dest, fpTempRegisterAsSingle());
1140
1141 // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
6fe7ccc8 1142 m_assembler.vcvt_signedToFloatingPoint(fpTempRegister, fpTempRegisterAsSingle());
4e4e5a6f
A
1143 failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, fpTempRegister));
1144
1145 // If the result is zero, it might have been -0.0, and the double comparison won't catch this!
93a37866
A
1146 if (negZeroCheck)
1147 failureCases.append(branchTest32(Zero, dest));
4e4e5a6f
A
1148 }
1149
b80e6193 1150 Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID)
4e4e5a6f 1151 {
6fe7ccc8 1152 m_assembler.vcmpz(reg);
b80e6193
A
1153 m_assembler.vmrs();
1154 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1155 Jump result = makeBranch(ARMv7Assembler::ConditionNE);
1156 unordered.link(this);
1157 return result;
1158 }
1159
1160 Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID)
1161 {
6fe7ccc8 1162 m_assembler.vcmpz(reg);
b80e6193
A
1163 m_assembler.vmrs();
1164 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1165 Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
1166 unordered.link(this);
1167 // We get here if either unordered or equal.
14957cd0 1168 Jump result = jump();
b80e6193
A
1169 notEqual.link(this);
1170 return result;
4e4e5a6f 1171 }
ba379fdc
A
1172
1173 // Stack manipulation operations:
1174 //
1175 // The ABI is assumed to provide a stack abstraction to memory,
1176 // containing machine word sized units of data. Push and pop
1177 // operations add and remove a single register sized unit of data
1178 // to or from the stack. Peek and poke operations read or write
1179 // values on the stack, without moving the current stack position.
1180
1181 void pop(RegisterID dest)
1182 {
81345200 1183 m_assembler.pop(dest);
ba379fdc
A
1184 }
1185
1186 void push(RegisterID src)
1187 {
81345200 1188 m_assembler.push(src);
ba379fdc
A
1189 }
1190
1191 void push(Address address)
1192 {
1193 load32(address, dataTempRegister);
1194 push(dataTempRegister);
1195 }
1196
14957cd0 1197 void push(TrustedImm32 imm)
ba379fdc
A
1198 {
1199 move(imm, dataTempRegister);
1200 push(dataTempRegister);
1201 }
1202
81345200
A
1203 void popPair(RegisterID dest1, RegisterID dest2)
1204 {
1205 m_assembler.pop(1 << dest1 | 1 << dest2);
1206 }
1207
1208 void pushPair(RegisterID src1, RegisterID src2)
1209 {
1210 m_assembler.push(1 << src1 | 1 << src2);
1211 }
1212
ba379fdc
A
1213 // Register move operations:
1214 //
1215 // Move values in registers.
1216
14957cd0 1217 void move(TrustedImm32 imm, RegisterID dest)
ba379fdc
A
1218 {
1219 uint32_t value = imm.m_value;
1220
93a37866 1221 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(value);
ba379fdc 1222
93a37866
A
1223 if (armImm.isValid())
1224 m_assembler.mov(dest, armImm);
1225 else if ((armImm = ARMThumbImmediate::makeEncodedImm(~value)).isValid())
1226 m_assembler.mvn(dest, armImm);
1227 else {
1228 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(value));
1229 if (value & 0xffff0000)
1230 m_assembler.movt(dest, ARMThumbImmediate::makeUInt16(value >> 16));
ba379fdc
A
1231 }
1232 }
1233
1234 void move(RegisterID src, RegisterID dest)
1235 {
6fe7ccc8
A
1236 if (src != dest)
1237 m_assembler.mov(dest, src);
ba379fdc
A
1238 }
1239
14957cd0 1240 void move(TrustedImmPtr imm, RegisterID dest)
ba379fdc 1241 {
14957cd0 1242 move(TrustedImm32(imm), dest);
ba379fdc
A
1243 }
1244
1245 void swap(RegisterID reg1, RegisterID reg2)
1246 {
1247 move(reg1, dataTempRegister);
1248 move(reg2, reg1);
1249 move(dataTempRegister, reg2);
1250 }
1251
1252 void signExtend32ToPtr(RegisterID src, RegisterID dest)
1253 {
6fe7ccc8 1254 move(src, dest);
ba379fdc
A
1255 }
1256
1257 void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
1258 {
6fe7ccc8
A
1259 move(src, dest);
1260 }
1261
1262 // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc.
1263 static RelationalCondition invert(RelationalCondition cond)
1264 {
1265 return static_cast<RelationalCondition>(cond ^ 1);
ba379fdc
A
1266 }
1267
14957cd0
A
1268 void nop()
1269 {
1270 m_assembler.nop();
1271 }
93a37866 1272
81345200
A
1273 void memoryFence()
1274 {
1275 m_assembler.dmbSY();
1276 }
1277
93a37866
A
1278 static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
1279 {
1280 ARMv7Assembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation());
1281 }
1282
1283 static ptrdiff_t maxJumpReplacementSize()
1284 {
1285 return ARMv7Assembler::maxJumpReplacementSize();
1286 }
ba379fdc
A
1287
1288 // Forwards / external control flow operations:
1289 //
1290 // This set of jump and conditional branch operations return a Jump
1291 // object which may linked at a later point, allow forwards jump,
1292 // or jumps that will require external linkage (after the code has been
1293 // relocated).
1294 //
1295 // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
1296 // respecitvely, for unsigned comparisons the names b, a, be, and ae are
1297 // used (representing the names 'below' and 'above').
1298 //
1299 // Operands to the comparision are provided in the expected order, e.g.
14957cd0 1300 // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
ba379fdc
A
1301 // treated as a signed 32bit value, is less than or equal to 5.
1302 //
1303 // jz and jnz test whether the first operand is equal to zero, and take
1304 // an optional second operand of a mask under which to perform the test.
1305private:
1306
1307 // Should we be using TEQ for equal/not-equal?
14957cd0 1308 void compare32(RegisterID left, TrustedImm32 right)
ba379fdc
A
1309 {
1310 int32_t imm = right.m_value;
81345200
A
1311 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
1312 if (armImm.isValid())
1313 m_assembler.cmp(left, armImm);
1314 else if ((armImm = ARMThumbImmediate::makeEncodedImm(-imm)).isValid())
1315 m_assembler.cmn(left, armImm);
ba379fdc 1316 else {
81345200
A
1317 move(TrustedImm32(imm), dataTempRegister);
1318 m_assembler.cmp(left, dataTempRegister);
ba379fdc
A
1319 }
1320 }
1321
14957cd0 1322 void test32(RegisterID reg, TrustedImm32 mask)
ba379fdc
A
1323 {
1324 int32_t imm = mask.m_value;
1325
1326 if (imm == -1)
1327 m_assembler.tst(reg, reg);
1328 else {
1329 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
81345200
A
1330 if (armImm.isValid()) {
1331 if (reg == ARMRegisters::sp) {
1332 move(reg, addressTempRegister);
1333 m_assembler.tst(addressTempRegister, armImm);
1334 } else
1335 m_assembler.tst(reg, armImm);
1336 } else {
ba379fdc 1337 move(mask, dataTempRegister);
81345200
A
1338 if (reg == ARMRegisters::sp) {
1339 move(reg, addressTempRegister);
1340 m_assembler.tst(addressTempRegister, dataTempRegister);
1341 } else
1342 m_assembler.tst(reg, dataTempRegister);
ba379fdc
A
1343 }
1344 }
1345 }
1346
1347public:
81345200
A
1348 void test32(ResultCondition, RegisterID reg, TrustedImm32 mask)
1349 {
1350 test32(reg, mask);
1351 }
1352
1353 Jump branch(ResultCondition cond)
1354 {
1355 return Jump(makeBranch(cond));
1356 }
1357
14957cd0 1358 Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
ba379fdc
A
1359 {
1360 m_assembler.cmp(left, right);
1361 return Jump(makeBranch(cond));
1362 }
1363
14957cd0 1364 Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
ba379fdc
A
1365 {
1366 compare32(left, right);
1367 return Jump(makeBranch(cond));
1368 }
1369
14957cd0 1370 Jump branch32(RelationalCondition cond, RegisterID left, Address right)
ba379fdc
A
1371 {
1372 load32(right, dataTempRegister);
1373 return branch32(cond, left, dataTempRegister);
1374 }
1375
14957cd0 1376 Jump branch32(RelationalCondition cond, Address left, RegisterID right)
ba379fdc
A
1377 {
1378 load32(left, dataTempRegister);
1379 return branch32(cond, dataTempRegister, right);
1380 }
1381
14957cd0 1382 Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
ba379fdc
A
1383 {
1384 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1385 load32(left, addressTempRegister);
1386 return branch32(cond, addressTempRegister, right);
1387 }
1388
14957cd0 1389 Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
ba379fdc
A
1390 {
1391 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1392 load32(left, addressTempRegister);
1393 return branch32(cond, addressTempRegister, right);
1394 }
1395
14957cd0 1396 Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
f9bf01c6
A
1397 {
1398 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1399 load32WithUnalignedHalfWords(left, addressTempRegister);
1400 return branch32(cond, addressTempRegister, right);
1401 }
1402
14957cd0 1403 Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
ba379fdc
A
1404 {
1405 load32(left.m_ptr, dataTempRegister);
1406 return branch32(cond, dataTempRegister, right);
1407 }
1408
14957cd0 1409 Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
ba379fdc
A
1410 {
1411 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1412 load32(left.m_ptr, addressTempRegister);
1413 return branch32(cond, addressTempRegister, right);
1414 }
1415
81345200
A
1416 Jump branchPtr(RelationalCondition cond, BaseIndex left, RegisterID right)
1417 {
1418 load32(left, dataTempRegister);
1419 return branch32(cond, dataTempRegister, right);
1420 }
1421
14957cd0 1422 Jump branch8(RelationalCondition cond, RegisterID left, TrustedImm32 right)
4e4e5a6f
A
1423 {
1424 compare32(left, right);
1425 return Jump(makeBranch(cond));
1426 }
1427
14957cd0 1428 Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
4e4e5a6f 1429 {
6fe7ccc8 1430 ASSERT(!(0xffffff00 & right.m_value));
4e4e5a6f
A
1431 // use addressTempRegister incase the branch8 we call uses dataTempRegister. :-/
1432 load8(left, addressTempRegister);
1433 return branch8(cond, addressTempRegister, right);
1434 }
1435
6fe7ccc8
A
1436 Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1437 {
1438 ASSERT(!(0xffffff00 & right.m_value));
1439 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1440 load8(left, addressTempRegister);
1441 return branch32(cond, addressTempRegister, right);
1442 }
1443
81345200
A
1444 Jump branch8(RelationalCondition cond, AbsoluteAddress address, TrustedImm32 right)
1445 {
1446 // Use addressTempRegister instead of dataTempRegister, since branch32 uses dataTempRegister.
1447 move(TrustedImmPtr(address.m_ptr), addressTempRegister);
1448 load8(Address(addressTempRegister), addressTempRegister);
1449 return branch32(cond, addressTempRegister, right);
1450 }
1451
14957cd0 1452 Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
ba379fdc 1453 {
ba379fdc
A
1454 m_assembler.tst(reg, mask);
1455 return Jump(makeBranch(cond));
1456 }
1457
14957cd0 1458 Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
ba379fdc 1459 {
ba379fdc
A
1460 test32(reg, mask);
1461 return Jump(makeBranch(cond));
1462 }
1463
14957cd0 1464 Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
ba379fdc 1465 {
ba379fdc
A
1466 // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
1467 load32(address, addressTempRegister);
1468 return branchTest32(cond, addressTempRegister, mask);
1469 }
1470
14957cd0 1471 Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
ba379fdc 1472 {
ba379fdc
A
1473 // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
1474 load32(address, addressTempRegister);
1475 return branchTest32(cond, addressTempRegister, mask);
1476 }
1477
81345200
A
1478 Jump branchTest8(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
1479 {
1480 // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
1481 load8(address, addressTempRegister);
1482 return branchTest32(cond, addressTempRegister, mask);
1483 }
1484
14957cd0 1485 Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
4e4e5a6f 1486 {
4e4e5a6f
A
1487 // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
1488 load8(address, addressTempRegister);
6fe7ccc8 1489 return branchTest32(cond, addressTempRegister, mask);
4e4e5a6f
A
1490 }
1491
93a37866
A
1492 Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
1493 {
1494 // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
1495 move(TrustedImmPtr(address.m_ptr), addressTempRegister);
1496 load8(Address(addressTempRegister), addressTempRegister);
1497 return branchTest32(cond, addressTempRegister, mask);
1498 }
1499
ba379fdc
A
1500 void jump(RegisterID target)
1501 {
14957cd0 1502 m_assembler.bx(target);
ba379fdc
A
1503 }
1504
1505 // Address is a memory location containing the address to jump to
1506 void jump(Address address)
1507 {
1508 load32(address, dataTempRegister);
14957cd0 1509 m_assembler.bx(dataTempRegister);
ba379fdc 1510 }
6fe7ccc8
A
1511
1512 void jump(AbsoluteAddress address)
1513 {
1514 move(TrustedImmPtr(address.m_ptr), dataTempRegister);
1515 load32(Address(dataTempRegister), dataTempRegister);
1516 m_assembler.bx(dataTempRegister);
1517 }
ba379fdc
A
1518
1519
1520 // Arithmetic control flow operations:
1521 //
1522 // This set of conditional branch operations branch based
1523 // on the result of an arithmetic operation. The operation
1524 // is performed as normal, storing the result.
1525 //
1526 // * jz operations branch if the result is zero.
1527 // * jo operations branch if the (signed) arithmetic
1528 // operation caused an overflow to occur.
1529
6fe7ccc8 1530 Jump branchAdd32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
ba379fdc 1531 {
6fe7ccc8 1532 m_assembler.add_S(dest, op1, op2);
ba379fdc
A
1533 return Jump(makeBranch(cond));
1534 }
1535
6fe7ccc8 1536 Jump branchAdd32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
ba379fdc 1537 {
ba379fdc
A
1538 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1539 if (armImm.isValid())
6fe7ccc8 1540 m_assembler.add_S(dest, op1, armImm);
ba379fdc
A
1541 else {
1542 move(imm, dataTempRegister);
6fe7ccc8
A
1543 m_assembler.add_S(dest, op1, dataTempRegister);
1544 }
1545 return Jump(makeBranch(cond));
1546 }
1547
1548 Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
1549 {
1550 return branchAdd32(cond, dest, src, dest);
1551 }
1552
4be4e309
A
1553 Jump branchAdd32(ResultCondition cond, Address src, RegisterID dest)
1554 {
1555 load32(src, dataTempRegister);
1556 return branchAdd32(cond, dest, dataTempRegister, dest);
1557 }
1558
6fe7ccc8
A
1559 Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1560 {
1561 return branchAdd32(cond, dest, imm, dest);
1562 }
1563
1564 Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest)
1565 {
1566 // Move the high bits of the address into addressTempRegister,
1567 // and load the value into dataTempRegister.
1568 move(TrustedImmPtr(dest.m_ptr), addressTempRegister);
1569 m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
1570
1571 // Do the add.
1572 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1573 if (armImm.isValid())
1574 m_assembler.add_S(dataTempRegister, dataTempRegister, armImm);
1575 else {
1576 // If the operand does not fit into an immediate then load it temporarily
1577 // into addressTempRegister; since we're overwriting addressTempRegister
1578 // we'll need to reload it with the high bits of the address afterwards.
1579 move(imm, addressTempRegister);
1580 m_assembler.add_S(dataTempRegister, dataTempRegister, addressTempRegister);
1581 move(TrustedImmPtr(dest.m_ptr), addressTempRegister);
ba379fdc 1582 }
6fe7ccc8
A
1583
1584 // Store the result.
1585 m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
1586
ba379fdc
A
1587 return Jump(makeBranch(cond));
1588 }
1589
14957cd0 1590 Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
ba379fdc 1591 {
14957cd0
A
1592 m_assembler.smull(dest, dataTempRegister, src1, src2);
1593
1594 if (cond == Overflow) {
1595 m_assembler.asr(addressTempRegister, dest, 31);
1596 return branch32(NotEqual, addressTempRegister, dataTempRegister);
1597 }
1598
1599 return branchTest32(cond, dest);
ba379fdc
A
1600 }
1601
14957cd0
A
1602 Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
1603 {
1604 return branchMul32(cond, src, dest, dest);
1605 }
1606
1607 Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
ba379fdc 1608 {
ba379fdc 1609 move(imm, dataTempRegister);
14957cd0 1610 return branchMul32(cond, dataTempRegister, src, dest);
ba379fdc
A
1611 }
1612
6fe7ccc8
A
1613 Jump branchNeg32(ResultCondition cond, RegisterID srcDest)
1614 {
1615 ARMThumbImmediate zero = ARMThumbImmediate::makeUInt12(0);
1616 m_assembler.sub_S(srcDest, zero, srcDest);
1617 return Jump(makeBranch(cond));
1618 }
1619
14957cd0 1620 Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
4e4e5a6f 1621 {
4e4e5a6f
A
1622 m_assembler.orr_S(dest, dest, src);
1623 return Jump(makeBranch(cond));
1624 }
1625
6fe7ccc8 1626 Jump branchSub32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
ba379fdc 1627 {
6fe7ccc8 1628 m_assembler.sub_S(dest, op1, op2);
ba379fdc
A
1629 return Jump(makeBranch(cond));
1630 }
1631
6fe7ccc8 1632 Jump branchSub32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
ba379fdc 1633 {
ba379fdc
A
1634 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1635 if (armImm.isValid())
6fe7ccc8 1636 m_assembler.sub_S(dest, op1, armImm);
ba379fdc
A
1637 else {
1638 move(imm, dataTempRegister);
6fe7ccc8 1639 m_assembler.sub_S(dest, op1, dataTempRegister);
ba379fdc
A
1640 }
1641 return Jump(makeBranch(cond));
1642 }
1643
6fe7ccc8
A
1644 Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
1645 {
1646 return branchSub32(cond, dest, src, dest);
1647 }
1648
1649 Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1650 {
1651 return branchSub32(cond, dest, imm, dest);
1652 }
1653
14957cd0
A
1654 void relativeTableJump(RegisterID index, int scale)
1655 {
1656 ASSERT(scale >= 0 && scale <= 31);
1657
1658 // dataTempRegister will point after the jump if index register contains zero
1659 move(ARMRegisters::pc, dataTempRegister);
1660 m_assembler.add(dataTempRegister, dataTempRegister, ARMThumbImmediate::makeEncodedImm(9));
1661
1662 ShiftTypeAndAmount shift(SRType_LSL, scale);
1663 m_assembler.add(dataTempRegister, dataTempRegister, index, shift);
1664 jump(dataTempRegister);
1665 }
ba379fdc
A
1666
1667 // Miscellaneous operations:
1668
6fe7ccc8 1669 void breakpoint(uint8_t imm = 0)
ba379fdc 1670 {
6fe7ccc8 1671 m_assembler.bkpt(imm);
ba379fdc
A
1672 }
1673
14957cd0 1674 ALWAYS_INLINE Call nearCall()
ba379fdc 1675 {
14957cd0
A
1676 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1677 return Call(m_assembler.blx(dataTempRegister), Call::LinkableNear);
ba379fdc
A
1678 }
1679
14957cd0 1680 ALWAYS_INLINE Call call()
ba379fdc 1681 {
14957cd0
A
1682 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1683 return Call(m_assembler.blx(dataTempRegister), Call::Linkable);
ba379fdc
A
1684 }
1685
14957cd0 1686 ALWAYS_INLINE Call call(RegisterID target)
ba379fdc 1687 {
14957cd0 1688 return Call(m_assembler.blx(target), Call::None);
ba379fdc
A
1689 }
1690
14957cd0 1691 ALWAYS_INLINE Call call(Address address)
ba379fdc
A
1692 {
1693 load32(address, dataTempRegister);
14957cd0 1694 return Call(m_assembler.blx(dataTempRegister), Call::None);
ba379fdc
A
1695 }
1696
14957cd0 1697 ALWAYS_INLINE void ret()
ba379fdc 1698 {
14957cd0 1699 m_assembler.bx(linkRegister);
ba379fdc
A
1700 }
1701
14957cd0 1702 void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
ba379fdc
A
1703 {
1704 m_assembler.cmp(left, right);
1705 m_assembler.it(armV7Condition(cond), false);
1706 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1707 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1708 }
1709
14957cd0 1710 void compare32(RelationalCondition cond, Address left, RegisterID right, RegisterID dest)
4e4e5a6f
A
1711 {
1712 load32(left, dataTempRegister);
14957cd0 1713 compare32(cond, dataTempRegister, right, dest);
4e4e5a6f
A
1714 }
1715
6fe7ccc8
A
1716 void compare8(RelationalCondition cond, Address left, TrustedImm32 right, RegisterID dest)
1717 {
1718 load8(left, addressTempRegister);
1719 compare32(cond, addressTempRegister, right, dest);
1720 }
1721
14957cd0 1722 void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
ba379fdc
A
1723 {
1724 compare32(left, right);
1725 m_assembler.it(armV7Condition(cond), false);
1726 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1727 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1728 }
1729
1730 // FIXME:
1731 // The mask should be optional... paerhaps the argument order should be
1732 // dest-src, operations always have a dest? ... possibly not true, considering
1733 // asm ops like test, or pseudo ops like pop().
14957cd0 1734 void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
ba379fdc
A
1735 {
1736 load32(address, dataTempRegister);
1737 test32(dataTempRegister, mask);
1738 m_assembler.it(armV7Condition(cond), false);
1739 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1740 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1741 }
1742
14957cd0 1743 void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
4e4e5a6f
A
1744 {
1745 load8(address, dataTempRegister);
1746 test32(dataTempRegister, mask);
1747 m_assembler.it(armV7Condition(cond), false);
1748 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1749 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1750 }
ba379fdc 1751
14957cd0 1752 ALWAYS_INLINE DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dst)
ba379fdc 1753 {
93a37866 1754 padBeforePatch();
ba379fdc
A
1755 moveFixedWidthEncoding(imm, dst);
1756 return DataLabel32(this);
1757 }
1758
14957cd0 1759 ALWAYS_INLINE DataLabelPtr moveWithPatch(TrustedImmPtr imm, RegisterID dst)
ba379fdc 1760 {
93a37866 1761 padBeforePatch();
14957cd0 1762 moveFixedWidthEncoding(TrustedImm32(imm), dst);
ba379fdc
A
1763 return DataLabelPtr(this);
1764 }
1765
14957cd0 1766 ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
ba379fdc
A
1767 {
1768 dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1769 return branch32(cond, left, dataTempRegister);
1770 }
1771
14957cd0 1772 ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
ba379fdc
A
1773 {
1774 load32(left, addressTempRegister);
1775 dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1776 return branch32(cond, addressTempRegister, dataTempRegister);
1777 }
93a37866 1778
81345200
A
1779 ALWAYS_INLINE Jump branch32WithPatch(RelationalCondition cond, Address left, DataLabel32& dataLabel, TrustedImm32 initialRightValue = TrustedImm32(0))
1780 {
1781 load32(left, addressTempRegister);
1782 dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1783 return branch32(cond, addressTempRegister, dataTempRegister);
1784 }
1785
93a37866
A
1786 PatchableJump patchableBranchPtr(RelationalCondition cond, Address left, TrustedImmPtr right = TrustedImmPtr(0))
1787 {
1788 m_makeJumpPatchable = true;
1789 Jump result = branch32(cond, left, TrustedImm32(right));
1790 m_makeJumpPatchable = false;
1791 return PatchableJump(result);
1792 }
1793
1794 PatchableJump patchableBranchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1795 {
1796 m_makeJumpPatchable = true;
1797 Jump result = branchTest32(cond, reg, mask);
1798 m_makeJumpPatchable = false;
1799 return PatchableJump(result);
1800 }
1801
1802 PatchableJump patchableBranch32(RelationalCondition cond, RegisterID reg, TrustedImm32 imm)
1803 {
1804 m_makeJumpPatchable = true;
1805 Jump result = branch32(cond, reg, imm);
1806 m_makeJumpPatchable = false;
1807 return PatchableJump(result);
1808 }
ba379fdc 1809
6fe7ccc8
A
1810 PatchableJump patchableBranchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1811 {
1812 m_makeJumpPatchable = true;
1813 Jump result = branchPtrWithPatch(cond, left, dataLabel, initialRightValue);
1814 m_makeJumpPatchable = false;
1815 return PatchableJump(result);
1816 }
1817
81345200
A
1818 PatchableJump patchableBranch32WithPatch(RelationalCondition cond, Address left, DataLabel32& dataLabel, TrustedImm32 initialRightValue = TrustedImm32(0))
1819 {
1820 m_makeJumpPatchable = true;
1821 Jump result = branch32WithPatch(cond, left, dataLabel, initialRightValue);
1822 m_makeJumpPatchable = false;
1823 return PatchableJump(result);
1824 }
1825
6fe7ccc8
A
1826 PatchableJump patchableJump()
1827 {
93a37866 1828 padBeforePatch();
6fe7ccc8
A
1829 m_makeJumpPatchable = true;
1830 Jump result = jump();
1831 m_makeJumpPatchable = false;
1832 return PatchableJump(result);
1833 }
1834
14957cd0 1835 ALWAYS_INLINE DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
ba379fdc
A
1836 {
1837 DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister);
1838 store32(dataTempRegister, address);
1839 return label;
1840 }
14957cd0 1841 ALWAYS_INLINE DataLabelPtr storePtrWithPatch(ImplicitAddress address) { return storePtrWithPatch(TrustedImmPtr(0), address); }
ba379fdc
A
1842
1843
14957cd0 1844 ALWAYS_INLINE Call tailRecursiveCall()
ba379fdc
A
1845 {
1846 // Like a normal call, but don't link.
14957cd0
A
1847 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1848 return Call(m_assembler.bx(dataTempRegister), Call::Linkable);
ba379fdc
A
1849 }
1850
14957cd0 1851 ALWAYS_INLINE Call makeTailRecursiveCall(Jump oldJump)
ba379fdc
A
1852 {
1853 oldJump.link(this);
1854 return tailRecursiveCall();
1855 }
1856
b80e6193 1857
6fe7ccc8 1858 static FunctionPtr readCallTarget(CodeLocationCall call)
b80e6193 1859 {
6fe7ccc8 1860 return FunctionPtr(reinterpret_cast<void(*)()>(ARMv7Assembler::readCallTarget(call.dataLocation())));
b80e6193 1861 }
93a37866
A
1862
1863 static bool canJumpReplacePatchableBranchPtrWithPatch() { return false; }
81345200 1864 static bool canJumpReplacePatchableBranch32WithPatch() { return false; }
93a37866
A
1865
1866 static CodeLocationLabel startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label)
1867 {
1868 const unsigned twoWordOpSize = 4;
1869 return label.labelAtOffset(-twoWordOpSize * 2);
1870 }
1871
1872 static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID rd, void* initialValue)
1873 {
81345200 1874#if OS(LINUX)
93a37866
A
1875 ARMv7Assembler::revertJumpTo_movT3movtcmpT2(instructionStart.dataLocation(), rd, dataTempRegister, reinterpret_cast<uintptr_t>(initialValue));
1876#else
1877 UNUSED_PARAM(rd);
1878 ARMv7Assembler::revertJumpTo_movT3(instructionStart.dataLocation(), dataTempRegister, ARMThumbImmediate::makeUInt16(reinterpret_cast<uintptr_t>(initialValue) & 0xffff));
1879#endif
1880 }
1881
1882 static CodeLocationLabel startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr)
1883 {
1884 UNREACHABLE_FOR_PLATFORM();
1885 return CodeLocationLabel();
1886 }
1887
81345200
A
1888 static CodeLocationLabel startOfPatchableBranch32WithPatchOnAddress(CodeLocationDataLabel32)
1889 {
1890 UNREACHABLE_FOR_PLATFORM();
1891 return CodeLocationLabel();
1892 }
1893
93a37866
A
1894 static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel, Address, void*)
1895 {
1896 UNREACHABLE_FOR_PLATFORM();
1897 }
b80e6193 1898
81345200
A
1899 static void revertJumpReplacementToPatchableBranch32WithPatch(CodeLocationLabel, Address, int32_t)
1900 {
1901 UNREACHABLE_FOR_PLATFORM();
1902 }
1903
ed1e77d3
A
1904#if ENABLE(MASM_PROBE)
1905 // Methods required by the MASM_PROBE mechanism as defined in
1906 // AbstractMacroAssembler.h.
1907 static void printCPURegisters(CPUState&, int indentation = 0);
1908 static void printRegister(CPUState&, RegisterID);
1909 static void printRegister(CPUState&, FPRegisterID);
81345200 1910 void probe(ProbeFunction, void* arg1 = 0, void* arg2 = 0);
ed1e77d3 1911#endif // ENABLE(MASM_PROBE)
81345200 1912
6fe7ccc8 1913protected:
14957cd0 1914 ALWAYS_INLINE Jump jump()
ba379fdc 1915 {
93a37866 1916 m_assembler.label(); // Force nop-padding if we're in the middle of a watchpoint.
14957cd0 1917 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
6fe7ccc8 1918 return Jump(m_assembler.bx(dataTempRegister), m_makeJumpPatchable ? ARMv7Assembler::JumpNoConditionFixedSize : ARMv7Assembler::JumpNoCondition);
ba379fdc
A
1919 }
1920
14957cd0 1921 ALWAYS_INLINE Jump makeBranch(ARMv7Assembler::Condition cond)
ba379fdc 1922 {
93a37866 1923 m_assembler.label(); // Force nop-padding if we're in the middle of a watchpoint.
f9bf01c6 1924 m_assembler.it(cond, true, true);
14957cd0 1925 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
6fe7ccc8 1926 return Jump(m_assembler.bx(dataTempRegister), m_makeJumpPatchable ? ARMv7Assembler::JumpConditionFixedSize : ARMv7Assembler::JumpCondition, cond);
ba379fdc 1927 }
14957cd0
A
1928 ALWAYS_INLINE Jump makeBranch(RelationalCondition cond) { return makeBranch(armV7Condition(cond)); }
1929 ALWAYS_INLINE Jump makeBranch(ResultCondition cond) { return makeBranch(armV7Condition(cond)); }
1930 ALWAYS_INLINE Jump makeBranch(DoubleCondition cond) { return makeBranch(armV7Condition(cond)); }
ba379fdc
A
1931
1932 ArmAddress setupArmAddress(BaseIndex address)
1933 {
1934 if (address.offset) {
1935 ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
1936 if (imm.isValid())
1937 m_assembler.add(addressTempRegister, address.base, imm);
1938 else {
14957cd0 1939 move(TrustedImm32(address.offset), addressTempRegister);
ba379fdc
A
1940 m_assembler.add(addressTempRegister, addressTempRegister, address.base);
1941 }
1942
1943 return ArmAddress(addressTempRegister, address.index, address.scale);
1944 } else
1945 return ArmAddress(address.base, address.index, address.scale);
1946 }
1947
1948 ArmAddress setupArmAddress(Address address)
1949 {
1950 if ((address.offset >= -0xff) && (address.offset <= 0xfff))
1951 return ArmAddress(address.base, address.offset);
1952
14957cd0 1953 move(TrustedImm32(address.offset), addressTempRegister);
ba379fdc
A
1954 return ArmAddress(address.base, addressTempRegister);
1955 }
1956
1957 ArmAddress setupArmAddress(ImplicitAddress address)
1958 {
1959 if ((address.offset >= -0xff) && (address.offset <= 0xfff))
1960 return ArmAddress(address.base, address.offset);
1961
14957cd0 1962 move(TrustedImm32(address.offset), addressTempRegister);
ba379fdc
A
1963 return ArmAddress(address.base, addressTempRegister);
1964 }
1965
1966 RegisterID makeBaseIndexBase(BaseIndex address)
1967 {
1968 if (!address.offset)
1969 return address.base;
1970
1971 ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
1972 if (imm.isValid())
1973 m_assembler.add(addressTempRegister, address.base, imm);
1974 else {
14957cd0 1975 move(TrustedImm32(address.offset), addressTempRegister);
ba379fdc
A
1976 m_assembler.add(addressTempRegister, addressTempRegister, address.base);
1977 }
1978
1979 return addressTempRegister;
1980 }
1981
14957cd0 1982 void moveFixedWidthEncoding(TrustedImm32 imm, RegisterID dst)
ba379fdc
A
1983 {
1984 uint32_t value = imm.m_value;
1985 m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff));
1986 m_assembler.movt(dst, ARMThumbImmediate::makeUInt16(value >> 16));
1987 }
1988
14957cd0
A
1989 ARMv7Assembler::Condition armV7Condition(RelationalCondition cond)
1990 {
1991 return static_cast<ARMv7Assembler::Condition>(cond);
1992 }
1993
1994 ARMv7Assembler::Condition armV7Condition(ResultCondition cond)
ba379fdc
A
1995 {
1996 return static_cast<ARMv7Assembler::Condition>(cond);
1997 }
1998
1999 ARMv7Assembler::Condition armV7Condition(DoubleCondition cond)
2000 {
2001 return static_cast<ARMv7Assembler::Condition>(cond);
2002 }
6fe7ccc8 2003
ba379fdc
A
2004private:
2005 friend class LinkBuffer;
2006 friend class RepatchBuffer;
2007
2008 static void linkCall(void* code, Call call, FunctionPtr function)
2009 {
6fe7ccc8 2010 ARMv7Assembler::linkCall(code, call.m_label, function.value());
ba379fdc
A
2011 }
2012
2013 static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
2014 {
2015 ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
2016 }
2017
2018 static void repatchCall(CodeLocationCall call, FunctionPtr destination)
2019 {
2020 ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
2021 }
6fe7ccc8 2022
ed1e77d3 2023#if ENABLE(MASM_PROBE)
81345200
A
2024 inline TrustedImm32 trustedImm32FromPtr(void* ptr)
2025 {
2026 return TrustedImm32(TrustedImmPtr(ptr));
2027 }
2028
2029 inline TrustedImm32 trustedImm32FromPtr(ProbeFunction function)
2030 {
2031 return TrustedImm32(TrustedImmPtr(reinterpret_cast<void*>(function)));
2032 }
2033
2034 inline TrustedImm32 trustedImm32FromPtr(void (*function)())
2035 {
2036 return TrustedImm32(TrustedImmPtr(reinterpret_cast<void*>(function)));
2037 }
2038#endif
2039
6fe7ccc8 2040 bool m_makeJumpPatchable;
ba379fdc
A
2041};
2042
2043} // namespace JSC
2044
2045#endif // ENABLE(ASSEMBLER)
2046
2047#endif // MacroAssemblerARMv7_h