2 * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
3 * Copyright (C) 2010 University of Szeged
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
27 #ifndef MacroAssemblerARMv7_h
28 #define MacroAssemblerARMv7_h
32 #include "ARMv7Assembler.h"
33 #include "AbstractMacroAssembler.h"
37 class MacroAssemblerARMv7 : public AbstractMacroAssembler<ARMv7Assembler> {
38 // FIXME: switch dataTempRegister & addressTempRegister, or possibly use r7?
39 // - dTR is likely used more than aTR, and we'll get better instruction
40 // encoding if it's in the low 8 registers.
41 static const RegisterID dataTempRegister = ARMRegisters::ip;
42 static const RegisterID addressTempRegister = ARMRegisters::r3;
44 static const ARMRegisters::FPDoubleRegisterID fpTempRegister = ARMRegisters::d7;
45 inline ARMRegisters::FPSingleRegisterID fpTempRegisterAsSingle() { return ARMRegisters::asSingle(fpTempRegister); }
48 typedef ARMv7Assembler::LinkRecord LinkRecord;
49 typedef ARMv7Assembler::JumpType JumpType;
50 typedef ARMv7Assembler::JumpLinkType JumpLinkType;
51 // Magic number is the biggest useful offset we can get on ARMv7 with
52 // a LDR_imm_T2 encoding
53 static const int MaximumCompactPtrAlignedAddressOffset = 124;
56 : m_inUninterruptedSequence(false)
60 void beginUninterruptedSequence() { m_inUninterruptedSequence = true; }
61 void endUninterruptedSequence() { m_inUninterruptedSequence = false; }
62 Vector<LinkRecord>& jumpsToLink() { return m_assembler.jumpsToLink(); }
63 void* unlinkedCode() { return m_assembler.unlinkedCode(); }
64 bool canCompact(JumpType jumpType) { return m_assembler.canCompact(jumpType); }
65 JumpLinkType computeJumpType(JumpType jumpType, const uint8_t* from, const uint8_t* to) { return m_assembler.computeJumpType(jumpType, from, to); }
66 JumpLinkType computeJumpType(LinkRecord& record, const uint8_t* from, const uint8_t* to) { return m_assembler.computeJumpType(record, from, to); }
67 void recordLinkOffsets(int32_t regionStart, int32_t regionEnd, int32_t offset) {return m_assembler.recordLinkOffsets(regionStart, regionEnd, offset); }
68 int jumpSizeDelta(JumpType jumpType, JumpLinkType jumpLinkType) { return m_assembler.jumpSizeDelta(jumpType, jumpLinkType); }
69 void link(LinkRecord& record, uint8_t* from, uint8_t* to) { return m_assembler.link(record, from, to); }
85 explicit ArmAddress(RegisterID base, int32_t offset = 0)
92 explicit ArmAddress(RegisterID base, RegisterID index, Scale scale = TimesOne)
102 typedef ARMRegisters::FPDoubleRegisterID FPRegisterID;
104 static const Scale ScalePtr = TimesFour;
106 enum RelationalCondition {
107 Equal = ARMv7Assembler::ConditionEQ,
108 NotEqual = ARMv7Assembler::ConditionNE,
109 Above = ARMv7Assembler::ConditionHI,
110 AboveOrEqual = ARMv7Assembler::ConditionHS,
111 Below = ARMv7Assembler::ConditionLO,
112 BelowOrEqual = ARMv7Assembler::ConditionLS,
113 GreaterThan = ARMv7Assembler::ConditionGT,
114 GreaterThanOrEqual = ARMv7Assembler::ConditionGE,
115 LessThan = ARMv7Assembler::ConditionLT,
116 LessThanOrEqual = ARMv7Assembler::ConditionLE
119 enum ResultCondition {
120 Overflow = ARMv7Assembler::ConditionVS,
121 Signed = ARMv7Assembler::ConditionMI,
122 Zero = ARMv7Assembler::ConditionEQ,
123 NonZero = ARMv7Assembler::ConditionNE
126 enum DoubleCondition {
127 // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
128 DoubleEqual = ARMv7Assembler::ConditionEQ,
129 DoubleNotEqual = ARMv7Assembler::ConditionVC, // Not the right flag! check for this & handle differently.
130 DoubleGreaterThan = ARMv7Assembler::ConditionGT,
131 DoubleGreaterThanOrEqual = ARMv7Assembler::ConditionGE,
132 DoubleLessThan = ARMv7Assembler::ConditionLO,
133 DoubleLessThanOrEqual = ARMv7Assembler::ConditionLS,
134 // If either operand is NaN, these conditions always evaluate to true.
135 DoubleEqualOrUnordered = ARMv7Assembler::ConditionVS, // Not the right flag! check for this & handle differently.
136 DoubleNotEqualOrUnordered = ARMv7Assembler::ConditionNE,
137 DoubleGreaterThanOrUnordered = ARMv7Assembler::ConditionHI,
138 DoubleGreaterThanOrEqualOrUnordered = ARMv7Assembler::ConditionHS,
139 DoubleLessThanOrUnordered = ARMv7Assembler::ConditionLT,
140 DoubleLessThanOrEqualOrUnordered = ARMv7Assembler::ConditionLE,
143 static const RegisterID stackPointerRegister = ARMRegisters::sp;
144 static const RegisterID linkRegister = ARMRegisters::lr;
146 // Integer arithmetic operations:
148 // Operations are typically two operand - operation(source, srcDst)
149 // For many operations the source may be an TrustedImm32, the srcDst operand
150 // may often be a memory location (explictly described using an Address
153 void add32(RegisterID src, RegisterID dest)
155 m_assembler.add(dest, dest, src);
158 void add32(TrustedImm32 imm, RegisterID dest)
160 add32(imm, dest, dest);
163 void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
165 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
166 if (armImm.isValid())
167 m_assembler.add(dest, src, armImm);
169 move(imm, dataTempRegister);
170 m_assembler.add(dest, src, dataTempRegister);
174 void add32(TrustedImm32 imm, Address address)
176 load32(address, dataTempRegister);
178 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
179 if (armImm.isValid())
180 m_assembler.add(dataTempRegister, dataTempRegister, armImm);
182 // Hrrrm, since dataTempRegister holds the data loaded,
183 // use addressTempRegister to hold the immediate.
184 move(imm, addressTempRegister);
185 m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister);
188 store32(dataTempRegister, address);
191 void add32(Address src, RegisterID dest)
193 load32(src, dataTempRegister);
194 add32(dataTempRegister, dest);
197 void add32(TrustedImm32 imm, AbsoluteAddress address)
199 load32(address.m_ptr, dataTempRegister);
201 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
202 if (armImm.isValid())
203 m_assembler.add(dataTempRegister, dataTempRegister, armImm);
205 // Hrrrm, since dataTempRegister holds the data loaded,
206 // use addressTempRegister to hold the immediate.
207 move(imm, addressTempRegister);
208 m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister);
211 store32(dataTempRegister, address.m_ptr);
214 void add64(TrustedImm32 imm, AbsoluteAddress address)
216 move(TrustedImmPtr(address.m_ptr), addressTempRegister);
218 m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(0));
219 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
220 if (armImm.isValid())
221 m_assembler.add_S(dataTempRegister, dataTempRegister, armImm);
223 move(imm, addressTempRegister);
224 m_assembler.add_S(dataTempRegister, dataTempRegister, addressTempRegister);
225 move(TrustedImmPtr(address.m_ptr), addressTempRegister);
227 m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(0));
229 m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(4));
230 m_assembler.adc(dataTempRegister, dataTempRegister, ARMThumbImmediate::makeEncodedImm(imm.m_value >> 31));
231 m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(4));
234 void and32(RegisterID op1, RegisterID op2, RegisterID dest)
236 m_assembler.ARM_and(dest, op1, op2);
239 void and32(TrustedImm32 imm, RegisterID src, RegisterID dest)
241 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
242 if (armImm.isValid())
243 m_assembler.ARM_and(dest, src, armImm);
245 move(imm, dataTempRegister);
246 m_assembler.ARM_and(dest, src, dataTempRegister);
250 void and32(RegisterID src, RegisterID dest)
252 and32(dest, src, dest);
255 void and32(TrustedImm32 imm, RegisterID dest)
257 and32(imm, dest, dest);
260 void countLeadingZeros32(RegisterID src, RegisterID dest)
262 m_assembler.clz(dest, src);
265 void lshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
267 // Clamp the shift to the range 0..31
268 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
269 ASSERT(armImm.isValid());
270 m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm);
272 m_assembler.lsl(dest, src, dataTempRegister);
275 void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
277 m_assembler.lsl(dest, src, imm.m_value & 0x1f);
280 void lshift32(RegisterID shiftAmount, RegisterID dest)
282 lshift32(dest, shiftAmount, dest);
285 void lshift32(TrustedImm32 imm, RegisterID dest)
287 lshift32(dest, imm, dest);
290 void mul32(RegisterID src, RegisterID dest)
292 m_assembler.smull(dest, dataTempRegister, dest, src);
295 void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
297 move(imm, dataTempRegister);
298 m_assembler.smull(dest, dataTempRegister, src, dataTempRegister);
301 void neg32(RegisterID srcDest)
303 m_assembler.neg(srcDest, srcDest);
306 void not32(RegisterID srcDest)
308 m_assembler.mvn(srcDest, srcDest);
311 void or32(RegisterID src, RegisterID dest)
313 m_assembler.orr(dest, dest, src);
316 void or32(TrustedImm32 imm, RegisterID dest)
318 or32(imm, dest, dest);
321 void or32(RegisterID op1, RegisterID op2, RegisterID dest)
323 m_assembler.orr(dest, op1, op2);
326 void or32(TrustedImm32 imm, RegisterID src, RegisterID dest)
328 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
329 if (armImm.isValid())
330 m_assembler.orr(dest, src, armImm);
332 move(imm, dataTempRegister);
333 m_assembler.orr(dest, src, dataTempRegister);
337 void rshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
339 // Clamp the shift to the range 0..31
340 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
341 ASSERT(armImm.isValid());
342 m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm);
344 m_assembler.asr(dest, src, dataTempRegister);
347 void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
349 m_assembler.asr(dest, src, imm.m_value & 0x1f);
352 void rshift32(RegisterID shiftAmount, RegisterID dest)
354 rshift32(dest, shiftAmount, dest);
357 void rshift32(TrustedImm32 imm, RegisterID dest)
359 rshift32(dest, imm, dest);
362 void urshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
364 // Clamp the shift to the range 0..31
365 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
366 ASSERT(armImm.isValid());
367 m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm);
369 m_assembler.lsr(dest, src, dataTempRegister);
372 void urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
374 m_assembler.lsr(dest, src, imm.m_value & 0x1f);
377 void urshift32(RegisterID shiftAmount, RegisterID dest)
379 urshift32(dest, shiftAmount, dest);
382 void urshift32(TrustedImm32 imm, RegisterID dest)
384 urshift32(dest, imm, dest);
387 void sub32(RegisterID src, RegisterID dest)
389 m_assembler.sub(dest, dest, src);
392 void sub32(TrustedImm32 imm, RegisterID dest)
394 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
395 if (armImm.isValid())
396 m_assembler.sub(dest, dest, armImm);
398 move(imm, dataTempRegister);
399 m_assembler.sub(dest, dest, dataTempRegister);
403 void sub32(TrustedImm32 imm, Address address)
405 load32(address, dataTempRegister);
407 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
408 if (armImm.isValid())
409 m_assembler.sub(dataTempRegister, dataTempRegister, armImm);
411 // Hrrrm, since dataTempRegister holds the data loaded,
412 // use addressTempRegister to hold the immediate.
413 move(imm, addressTempRegister);
414 m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister);
417 store32(dataTempRegister, address);
420 void sub32(Address src, RegisterID dest)
422 load32(src, dataTempRegister);
423 sub32(dataTempRegister, dest);
426 void sub32(TrustedImm32 imm, AbsoluteAddress address)
428 load32(address.m_ptr, dataTempRegister);
430 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
431 if (armImm.isValid())
432 m_assembler.sub(dataTempRegister, dataTempRegister, armImm);
434 // Hrrrm, since dataTempRegister holds the data loaded,
435 // use addressTempRegister to hold the immediate.
436 move(imm, addressTempRegister);
437 m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister);
440 store32(dataTempRegister, address.m_ptr);
443 void xor32(RegisterID op1, RegisterID op2, RegisterID dest)
445 m_assembler.eor(dest, op1, op2);
448 void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest)
450 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
451 if (armImm.isValid())
452 m_assembler.eor(dest, src, armImm);
454 move(imm, dataTempRegister);
455 m_assembler.eor(dest, src, dataTempRegister);
459 void xor32(RegisterID src, RegisterID dest)
461 xor32(dest, src, dest);
464 void xor32(TrustedImm32 imm, RegisterID dest)
466 xor32(imm, dest, dest);
470 // Memory access operations:
472 // Loads are of the form load(address, destination) and stores of the form
473 // store(source, address). The source for a store may be an TrustedImm32. Address
474 // operand objects to loads and store will be implicitly constructed if a
475 // register is passed.
478 void load32(ArmAddress address, RegisterID dest)
480 if (address.type == ArmAddress::HasIndex)
481 m_assembler.ldr(dest, address.base, address.u.index, address.u.scale);
482 else if (address.u.offset >= 0) {
483 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
484 ASSERT(armImm.isValid());
485 m_assembler.ldr(dest, address.base, armImm);
487 ASSERT(address.u.offset >= -255);
488 m_assembler.ldr(dest, address.base, address.u.offset, true, false);
492 void load16(ArmAddress address, RegisterID dest)
494 if (address.type == ArmAddress::HasIndex)
495 m_assembler.ldrh(dest, address.base, address.u.index, address.u.scale);
496 else if (address.u.offset >= 0) {
497 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
498 ASSERT(armImm.isValid());
499 m_assembler.ldrh(dest, address.base, armImm);
501 ASSERT(address.u.offset >= -255);
502 m_assembler.ldrh(dest, address.base, address.u.offset, true, false);
506 void load8(ArmAddress address, RegisterID dest)
508 if (address.type == ArmAddress::HasIndex)
509 m_assembler.ldrb(dest, address.base, address.u.index, address.u.scale);
510 else if (address.u.offset >= 0) {
511 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
512 ASSERT(armImm.isValid());
513 m_assembler.ldrb(dest, address.base, armImm);
515 ASSERT(address.u.offset >= -255);
516 m_assembler.ldrb(dest, address.base, address.u.offset, true, false);
520 void store32(RegisterID src, ArmAddress address)
522 if (address.type == ArmAddress::HasIndex)
523 m_assembler.str(src, address.base, address.u.index, address.u.scale);
524 else if (address.u.offset >= 0) {
525 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
526 ASSERT(armImm.isValid());
527 m_assembler.str(src, address.base, armImm);
529 ASSERT(address.u.offset >= -255);
530 m_assembler.str(src, address.base, address.u.offset, true, false);
534 void store8(RegisterID src, ArmAddress address)
536 if (address.type == ArmAddress::HasIndex)
537 m_assembler.strb(src, address.base, address.u.index, address.u.scale);
538 else if (address.u.offset >= 0) {
539 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
540 ASSERT(armImm.isValid());
541 m_assembler.strb(src, address.base, armImm);
543 ASSERT(address.u.offset >= -255);
544 m_assembler.strb(src, address.base, address.u.offset, true, false);
549 void load32(ImplicitAddress address, RegisterID dest)
551 load32(setupArmAddress(address), dest);
554 void load32(BaseIndex address, RegisterID dest)
556 load32(setupArmAddress(address), dest);
559 void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
561 load32(setupArmAddress(address), dest);
564 void load32(const void* address, RegisterID dest)
566 move(TrustedImmPtr(address), addressTempRegister);
567 m_assembler.ldr(dest, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
570 void load8(ImplicitAddress address, RegisterID dest)
572 load8(setupArmAddress(address), dest);
575 void load8(BaseIndex address, RegisterID dest)
577 load8(setupArmAddress(address), dest);
580 DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
582 DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
583 load32(ArmAddress(address.base, dataTempRegister), dest);
587 // FIXME: we should be able to plant a compact load relative to/from any base/dest register.
588 DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
590 RegisterID base = address.base;
592 if (base >= ARMRegisters::r8) {
593 move(base, addressTempRegister);
594 base = addressTempRegister;
597 DataLabelCompact label(this);
598 ASSERT(address.offset >= 0);
599 ASSERT(address.offset <= MaximumCompactPtrAlignedAddressOffset);
600 ASSERT(ARMThumbImmediate::makeUInt12(address.offset).isUInt7());
602 if (dest >= ARMRegisters::r8) {
603 m_assembler.ldrCompact(addressTempRegister, base, ARMThumbImmediate::makeUInt12(address.offset));
604 move(addressTempRegister, dest);
606 m_assembler.ldrCompact(dest, base, ARMThumbImmediate::makeUInt12(address.offset));
610 void load16(BaseIndex address, RegisterID dest)
612 m_assembler.ldrh(dest, makeBaseIndexBase(address), address.index, address.scale);
615 void load16(ImplicitAddress address, RegisterID dest)
617 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.offset);
618 if (armImm.isValid())
619 m_assembler.ldrh(dest, address.base, armImm);
621 move(TrustedImm32(address.offset), dataTempRegister);
622 m_assembler.ldrh(dest, address.base, dataTempRegister);
626 DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
628 DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
629 store32(src, ArmAddress(address.base, dataTempRegister));
633 void store32(RegisterID src, ImplicitAddress address)
635 store32(src, setupArmAddress(address));
638 void store32(RegisterID src, BaseIndex address)
640 store32(src, setupArmAddress(address));
643 void store32(TrustedImm32 imm, ImplicitAddress address)
645 move(imm, dataTempRegister);
646 store32(dataTempRegister, setupArmAddress(address));
649 void store32(TrustedImm32 imm, BaseIndex address)
651 move(imm, dataTempRegister);
652 store32(dataTempRegister, setupArmAddress(address));
655 void store32(RegisterID src, const void* address)
657 move(TrustedImmPtr(address), addressTempRegister);
658 m_assembler.str(src, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
661 void store32(TrustedImm32 imm, const void* address)
663 move(imm, dataTempRegister);
664 store32(dataTempRegister, address);
667 void store8(RegisterID src, BaseIndex address)
669 store8(src, setupArmAddress(address));
673 // Floating-point operations:
675 static bool supportsFloatingPoint() { return true; }
676 static bool supportsFloatingPointTruncate() { return true; }
677 static bool supportsFloatingPointSqrt() { return true; }
678 static bool supportsFloatingPointAbs() { return true; }
680 void loadDouble(ImplicitAddress address, FPRegisterID dest)
682 RegisterID base = address.base;
683 int32_t offset = address.offset;
685 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
686 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
687 add32(TrustedImm32(offset), base, addressTempRegister);
688 base = addressTempRegister;
692 m_assembler.vldr(dest, base, offset);
695 void moveDouble(FPRegisterID src, FPRegisterID dest)
698 m_assembler.vmov(dest, src);
701 void loadDouble(const void* address, FPRegisterID dest)
703 move(TrustedImmPtr(address), addressTempRegister);
704 m_assembler.vldr(dest, addressTempRegister, 0);
707 void storeDouble(FPRegisterID src, ImplicitAddress address)
709 RegisterID base = address.base;
710 int32_t offset = address.offset;
712 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
713 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
714 add32(TrustedImm32(offset), base, addressTempRegister);
715 base = addressTempRegister;
719 m_assembler.vstr(src, base, offset);
722 void storeDouble(FPRegisterID src, const void* address)
724 move(ImmPtr(address), addressTempRegister);
725 storeDouble(src, addressTempRegister);
728 void addDouble(FPRegisterID src, FPRegisterID dest)
730 m_assembler.vadd(dest, dest, src);
733 void addDouble(Address src, FPRegisterID dest)
735 loadDouble(src, fpTempRegister);
736 addDouble(fpTempRegister, dest);
739 void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
741 m_assembler.vadd(dest, op1, op2);
744 void addDouble(AbsoluteAddress address, FPRegisterID dest)
746 loadDouble(address.m_ptr, fpTempRegister);
747 m_assembler.vadd(dest, dest, fpTempRegister);
750 void divDouble(FPRegisterID src, FPRegisterID dest)
752 m_assembler.vdiv(dest, dest, src);
755 void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
757 m_assembler.vdiv(dest, op1, op2);
760 void subDouble(FPRegisterID src, FPRegisterID dest)
762 m_assembler.vsub(dest, dest, src);
765 void subDouble(Address src, FPRegisterID dest)
767 loadDouble(src, fpTempRegister);
768 subDouble(fpTempRegister, dest);
771 void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
773 m_assembler.vsub(dest, op1, op2);
776 void mulDouble(FPRegisterID src, FPRegisterID dest)
778 m_assembler.vmul(dest, dest, src);
781 void mulDouble(Address src, FPRegisterID dest)
783 loadDouble(src, fpTempRegister);
784 mulDouble(fpTempRegister, dest);
787 void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
789 m_assembler.vmul(dest, op1, op2);
792 void sqrtDouble(FPRegisterID src, FPRegisterID dest)
794 m_assembler.vsqrt(dest, src);
797 void absDouble(FPRegisterID src, FPRegisterID dest)
799 m_assembler.vabs(dest, src);
802 void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
804 m_assembler.vmov(fpTempRegisterAsSingle(), src);
805 m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
808 void convertInt32ToDouble(Address address, FPRegisterID dest)
810 // Fixme: load directly into the fpr!
811 load32(address, dataTempRegister);
812 m_assembler.vmov(fpTempRegisterAsSingle(), dataTempRegister);
813 m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
816 void convertInt32ToDouble(AbsoluteAddress address, FPRegisterID dest)
818 // Fixme: load directly into the fpr!
819 load32(address.m_ptr, dataTempRegister);
820 m_assembler.vmov(fpTempRegisterAsSingle(), dataTempRegister);
821 m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
824 Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
826 m_assembler.vcmp(left, right);
829 if (cond == DoubleNotEqual) {
830 // ConditionNE jumps if NotEqual *or* unordered - force the unordered cases not to jump.
831 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
832 Jump result = makeBranch(ARMv7Assembler::ConditionNE);
833 unordered.link(this);
836 if (cond == DoubleEqualOrUnordered) {
837 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
838 Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
839 unordered.link(this);
840 // We get here if either unordered or equal.
841 Jump result = jump();
845 return makeBranch(cond);
848 enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful };
849 Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
851 // Convert into dest.
852 m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
853 m_assembler.vmov(dest, fpTempRegisterAsSingle());
855 // Calculate 2x dest. If the value potentially underflowed, it will have
856 // clamped to 0x80000000, so 2x dest is zero in this case. In the case of
857 // overflow the result will be equal to -2.
858 Jump underflow = branchAdd32(Zero, dest, dest, dataTempRegister);
859 Jump noOverflow = branch32(NotEqual, dataTempRegister, Imm32(-2));
861 // For BranchIfTruncateSuccessful, we branch if 'noOverflow' jumps.
862 underflow.link(this);
863 if (branchType == BranchIfTruncateSuccessful)
866 // We'll reach the current point in the code on failure, so plant a
867 // jump here & link the success case.
868 Jump failure = jump();
869 noOverflow.link(this);
873 // Result is undefined if the value is outside of the integer range.
874 void truncateDoubleToInt32(FPRegisterID src, RegisterID dest)
876 m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
877 m_assembler.vmov(dest, fpTempRegisterAsSingle());
880 // Convert 'src' to an integer, and places the resulting 'dest'.
881 // If the result is not representable as a 32 bit value, branch.
882 // May also branch for some values that are representable in 32 bits
883 // (specifically, in this case, 0).
884 void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID)
886 m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
887 m_assembler.vmov(dest, fpTempRegisterAsSingle());
889 // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
890 m_assembler.vcvt_signedToFloatingPoint(fpTempRegister, fpTempRegisterAsSingle());
891 failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, fpTempRegister));
893 // If the result is zero, it might have been -0.0, and the double comparison won't catch this!
894 failureCases.append(branchTest32(Zero, dest));
897 Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID)
899 m_assembler.vcmpz(reg);
901 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
902 Jump result = makeBranch(ARMv7Assembler::ConditionNE);
903 unordered.link(this);
907 Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID)
909 m_assembler.vcmpz(reg);
911 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
912 Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
913 unordered.link(this);
914 // We get here if either unordered or equal.
915 Jump result = jump();
920 // Stack manipulation operations:
922 // The ABI is assumed to provide a stack abstraction to memory,
923 // containing machine word sized units of data. Push and pop
924 // operations add and remove a single register sized unit of data
925 // to or from the stack. Peek and poke operations read or write
926 // values on the stack, without moving the current stack position.
928 void pop(RegisterID dest)
930 // store postindexed with writeback
931 m_assembler.ldr(dest, ARMRegisters::sp, sizeof(void*), false, true);
934 void push(RegisterID src)
936 // store preindexed with writeback
937 m_assembler.str(src, ARMRegisters::sp, -sizeof(void*), true, true);
940 void push(Address address)
942 load32(address, dataTempRegister);
943 push(dataTempRegister);
946 void push(TrustedImm32 imm)
948 move(imm, dataTempRegister);
949 push(dataTempRegister);
952 // Register move operations:
954 // Move values in registers.
956 void move(TrustedImm32 imm, RegisterID dest)
958 uint32_t value = imm.m_value;
961 moveFixedWidthEncoding(imm, dest);
963 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(value);
965 if (armImm.isValid())
966 m_assembler.mov(dest, armImm);
967 else if ((armImm = ARMThumbImmediate::makeEncodedImm(~value)).isValid())
968 m_assembler.mvn(dest, armImm);
970 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(value));
971 if (value & 0xffff0000)
972 m_assembler.movt(dest, ARMThumbImmediate::makeUInt16(value >> 16));
977 void move(RegisterID src, RegisterID dest)
980 m_assembler.mov(dest, src);
983 void move(TrustedImmPtr imm, RegisterID dest)
985 move(TrustedImm32(imm), dest);
988 void swap(RegisterID reg1, RegisterID reg2)
990 move(reg1, dataTempRegister);
992 move(dataTempRegister, reg2);
995 void signExtend32ToPtr(RegisterID src, RegisterID dest)
1000 void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
1005 // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc.
1006 static RelationalCondition invert(RelationalCondition cond)
1008 return static_cast<RelationalCondition>(cond ^ 1);
1016 // Forwards / external control flow operations:
1018 // This set of jump and conditional branch operations return a Jump
1019 // object which may linked at a later point, allow forwards jump,
1020 // or jumps that will require external linkage (after the code has been
1023 // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
1024 // respecitvely, for unsigned comparisons the names b, a, be, and ae are
1025 // used (representing the names 'below' and 'above').
1027 // Operands to the comparision are provided in the expected order, e.g.
1028 // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
1029 // treated as a signed 32bit value, is less than or equal to 5.
1031 // jz and jnz test whether the first operand is equal to zero, and take
1032 // an optional second operand of a mask under which to perform the test.
1035 // Should we be using TEQ for equal/not-equal?
1036 void compare32(RegisterID left, TrustedImm32 right)
1038 int32_t imm = right.m_value;
1040 m_assembler.tst(left, left);
1042 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
1043 if (armImm.isValid())
1044 m_assembler.cmp(left, armImm);
1045 else if ((armImm = ARMThumbImmediate::makeEncodedImm(-imm)).isValid())
1046 m_assembler.cmn(left, armImm);
1048 move(TrustedImm32(imm), dataTempRegister);
1049 m_assembler.cmp(left, dataTempRegister);
1054 void test32(RegisterID reg, TrustedImm32 mask)
1056 int32_t imm = mask.m_value;
1059 m_assembler.tst(reg, reg);
1061 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
1062 if (armImm.isValid())
1063 m_assembler.tst(reg, armImm);
1065 move(mask, dataTempRegister);
1066 m_assembler.tst(reg, dataTempRegister);
1072 Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
1074 m_assembler.cmp(left, right);
1075 return Jump(makeBranch(cond));
1078 Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1080 compare32(left, right);
1081 return Jump(makeBranch(cond));
1084 Jump branch32(RelationalCondition cond, RegisterID left, Address right)
1086 load32(right, dataTempRegister);
1087 return branch32(cond, left, dataTempRegister);
1090 Jump branch32(RelationalCondition cond, Address left, RegisterID right)
1092 load32(left, dataTempRegister);
1093 return branch32(cond, dataTempRegister, right);
1096 Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
1098 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1099 load32(left, addressTempRegister);
1100 return branch32(cond, addressTempRegister, right);
1103 Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1105 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1106 load32(left, addressTempRegister);
1107 return branch32(cond, addressTempRegister, right);
1110 Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1112 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1113 load32WithUnalignedHalfWords(left, addressTempRegister);
1114 return branch32(cond, addressTempRegister, right);
1117 Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
1119 load32(left.m_ptr, dataTempRegister);
1120 return branch32(cond, dataTempRegister, right);
1123 Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
1125 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1126 load32(left.m_ptr, addressTempRegister);
1127 return branch32(cond, addressTempRegister, right);
1130 Jump branch8(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1132 compare32(left, right);
1133 return Jump(makeBranch(cond));
1136 Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
1138 ASSERT(!(0xffffff00 & right.m_value));
1139 // use addressTempRegister incase the branch8 we call uses dataTempRegister. :-/
1140 load8(left, addressTempRegister);
1141 return branch8(cond, addressTempRegister, right);
1144 Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1146 ASSERT(!(0xffffff00 & right.m_value));
1147 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1148 load8(left, addressTempRegister);
1149 return branch32(cond, addressTempRegister, right);
1152 Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
1154 m_assembler.tst(reg, mask);
1155 return Jump(makeBranch(cond));
1158 Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1161 return Jump(makeBranch(cond));
1164 Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1166 // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
1167 load32(address, addressTempRegister);
1168 return branchTest32(cond, addressTempRegister, mask);
1171 Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
1173 // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
1174 load32(address, addressTempRegister);
1175 return branchTest32(cond, addressTempRegister, mask);
1178 Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1180 // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
1181 load8(address, addressTempRegister);
1182 return branchTest32(cond, addressTempRegister, mask);
1185 void jump(RegisterID target)
1187 m_assembler.bx(target);
1190 // Address is a memory location containing the address to jump to
1191 void jump(Address address)
1193 load32(address, dataTempRegister);
1194 m_assembler.bx(dataTempRegister);
1197 void jump(AbsoluteAddress address)
1199 move(TrustedImmPtr(address.m_ptr), dataTempRegister);
1200 load32(Address(dataTempRegister), dataTempRegister);
1201 m_assembler.bx(dataTempRegister);
1205 // Arithmetic control flow operations:
1207 // This set of conditional branch operations branch based
1208 // on the result of an arithmetic operation. The operation
1209 // is performed as normal, storing the result.
1211 // * jz operations branch if the result is zero.
1212 // * jo operations branch if the (signed) arithmetic
1213 // operation caused an overflow to occur.
1215 Jump branchAdd32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
1217 m_assembler.add_S(dest, op1, op2);
1218 return Jump(makeBranch(cond));
1221 Jump branchAdd32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
1223 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1224 if (armImm.isValid())
1225 m_assembler.add_S(dest, op1, armImm);
1227 move(imm, dataTempRegister);
1228 m_assembler.add_S(dest, op1, dataTempRegister);
1230 return Jump(makeBranch(cond));
1233 Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
1235 return branchAdd32(cond, dest, src, dest);
1238 Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1240 return branchAdd32(cond, dest, imm, dest);
1243 Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest)
1245 // Move the high bits of the address into addressTempRegister,
1246 // and load the value into dataTempRegister.
1247 move(ImmPtr(dest.m_ptr), addressTempRegister);
1248 m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
1251 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1252 if (armImm.isValid())
1253 m_assembler.add_S(dataTempRegister, dataTempRegister, armImm);
1255 // If the operand does not fit into an immediate then load it temporarily
1256 // into addressTempRegister; since we're overwriting addressTempRegister
1257 // we'll need to reload it with the high bits of the address afterwards.
1258 move(imm, addressTempRegister);
1259 m_assembler.add_S(dataTempRegister, dataTempRegister, addressTempRegister);
1260 move(ImmPtr(dest.m_ptr), addressTempRegister);
1263 // Store the result.
1264 m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
1266 return Jump(makeBranch(cond));
1269 Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
1271 m_assembler.smull(dest, dataTempRegister, src1, src2);
1273 if (cond == Overflow) {
1274 m_assembler.asr(addressTempRegister, dest, 31);
1275 return branch32(NotEqual, addressTempRegister, dataTempRegister);
1278 return branchTest32(cond, dest);
1281 Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
1283 return branchMul32(cond, src, dest, dest);
1286 Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
1288 move(imm, dataTempRegister);
1289 return branchMul32(cond, dataTempRegister, src, dest);
1292 Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
1294 m_assembler.orr_S(dest, dest, src);
1295 return Jump(makeBranch(cond));
1298 Jump branchSub32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
1300 m_assembler.sub_S(dest, op1, op2);
1301 return Jump(makeBranch(cond));
1304 Jump branchSub32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
1306 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1307 if (armImm.isValid())
1308 m_assembler.sub_S(dest, op1, armImm);
1310 move(imm, dataTempRegister);
1311 m_assembler.sub_S(dest, op1, dataTempRegister);
1313 return Jump(makeBranch(cond));
1316 Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
1318 return branchSub32(cond, dest, src, dest);
1321 Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1323 return branchSub32(cond, dest, imm, dest);
1326 void relativeTableJump(RegisterID index, int scale)
1328 ASSERT(scale >= 0 && scale <= 31);
1330 // dataTempRegister will point after the jump if index register contains zero
1331 move(ARMRegisters::pc, dataTempRegister);
1332 m_assembler.add(dataTempRegister, dataTempRegister, ARMThumbImmediate::makeEncodedImm(9));
1334 ShiftTypeAndAmount shift(SRType_LSL, scale);
1335 m_assembler.add(dataTempRegister, dataTempRegister, index, shift);
1336 jump(dataTempRegister);
1339 // Miscellaneous operations:
1341 void breakpoint(uint8_t imm = 0)
1343 m_assembler.bkpt(imm);
1346 ALWAYS_INLINE Call nearCall()
1348 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1349 return Call(m_assembler.blx(dataTempRegister), Call::LinkableNear);
1352 ALWAYS_INLINE Call call()
1354 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1355 return Call(m_assembler.blx(dataTempRegister), Call::Linkable);
1358 ALWAYS_INLINE Call call(RegisterID target)
1360 return Call(m_assembler.blx(target), Call::None);
1363 ALWAYS_INLINE Call call(Address address)
1365 load32(address, dataTempRegister);
1366 return Call(m_assembler.blx(dataTempRegister), Call::None);
1369 ALWAYS_INLINE void ret()
1371 m_assembler.bx(linkRegister);
1374 void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
1376 m_assembler.cmp(left, right);
1377 m_assembler.it(armV7Condition(cond), false);
1378 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1379 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1382 void compare32(RelationalCondition cond, Address left, RegisterID right, RegisterID dest)
1384 load32(left, dataTempRegister);
1385 compare32(cond, dataTempRegister, right, dest);
1388 void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
1390 compare32(left, right);
1391 m_assembler.it(armV7Condition(cond), false);
1392 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1393 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1397 // The mask should be optional... paerhaps the argument order should be
1398 // dest-src, operations always have a dest? ... possibly not true, considering
1399 // asm ops like test, or pseudo ops like pop().
1400 void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1402 load32(address, dataTempRegister);
1403 test32(dataTempRegister, mask);
1404 m_assembler.it(armV7Condition(cond), false);
1405 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1406 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1409 void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1411 load8(address, dataTempRegister);
1412 test32(dataTempRegister, mask);
1413 m_assembler.it(armV7Condition(cond), false);
1414 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1415 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1418 ALWAYS_INLINE DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dst)
1420 moveFixedWidthEncoding(imm, dst);
1421 return DataLabel32(this);
1424 ALWAYS_INLINE DataLabelPtr moveWithPatch(TrustedImmPtr imm, RegisterID dst)
1426 moveFixedWidthEncoding(TrustedImm32(imm), dst);
1427 return DataLabelPtr(this);
1430 ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1432 dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1433 return branch32(cond, left, dataTempRegister);
1436 ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1438 load32(left, addressTempRegister);
1439 dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1440 return branch32(cond, addressTempRegister, dataTempRegister);
1443 ALWAYS_INLINE DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
1445 DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister);
1446 store32(dataTempRegister, address);
1449 ALWAYS_INLINE DataLabelPtr storePtrWithPatch(ImplicitAddress address) { return storePtrWithPatch(TrustedImmPtr(0), address); }
1452 ALWAYS_INLINE Call tailRecursiveCall()
1454 // Like a normal call, but don't link.
1455 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1456 return Call(m_assembler.bx(dataTempRegister), Call::Linkable);
1459 ALWAYS_INLINE Call makeTailRecursiveCall(Jump oldJump)
1462 return tailRecursiveCall();
1466 int executableOffsetFor(int location)
1468 return m_assembler.executableOffsetFor(location);
1471 static FunctionPtr readCallTarget(CodeLocationCall call)
1473 return FunctionPtr(reinterpret_cast<void(*)()>(ARMv7Assembler::readCallTarget(call.dataLocation())));
1477 bool inUninterruptedSequence()
1479 return m_inUninterruptedSequence;
1482 ALWAYS_INLINE Jump jump()
1484 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1485 return Jump(m_assembler.bx(dataTempRegister), inUninterruptedSequence() ? ARMv7Assembler::JumpNoConditionFixedSize : ARMv7Assembler::JumpNoCondition);
1488 ALWAYS_INLINE Jump makeBranch(ARMv7Assembler::Condition cond)
1490 m_assembler.it(cond, true, true);
1491 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1492 return Jump(m_assembler.bx(dataTempRegister), inUninterruptedSequence() ? ARMv7Assembler::JumpConditionFixedSize : ARMv7Assembler::JumpCondition, cond);
1494 ALWAYS_INLINE Jump makeBranch(RelationalCondition cond) { return makeBranch(armV7Condition(cond)); }
1495 ALWAYS_INLINE Jump makeBranch(ResultCondition cond) { return makeBranch(armV7Condition(cond)); }
1496 ALWAYS_INLINE Jump makeBranch(DoubleCondition cond) { return makeBranch(armV7Condition(cond)); }
1498 ArmAddress setupArmAddress(BaseIndex address)
1500 if (address.offset) {
1501 ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
1503 m_assembler.add(addressTempRegister, address.base, imm);
1505 move(TrustedImm32(address.offset), addressTempRegister);
1506 m_assembler.add(addressTempRegister, addressTempRegister, address.base);
1509 return ArmAddress(addressTempRegister, address.index, address.scale);
1511 return ArmAddress(address.base, address.index, address.scale);
1514 ArmAddress setupArmAddress(Address address)
1516 if ((address.offset >= -0xff) && (address.offset <= 0xfff))
1517 return ArmAddress(address.base, address.offset);
1519 move(TrustedImm32(address.offset), addressTempRegister);
1520 return ArmAddress(address.base, addressTempRegister);
1523 ArmAddress setupArmAddress(ImplicitAddress address)
1525 if ((address.offset >= -0xff) && (address.offset <= 0xfff))
1526 return ArmAddress(address.base, address.offset);
1528 move(TrustedImm32(address.offset), addressTempRegister);
1529 return ArmAddress(address.base, addressTempRegister);
1532 RegisterID makeBaseIndexBase(BaseIndex address)
1534 if (!address.offset)
1535 return address.base;
1537 ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
1539 m_assembler.add(addressTempRegister, address.base, imm);
1541 move(TrustedImm32(address.offset), addressTempRegister);
1542 m_assembler.add(addressTempRegister, addressTempRegister, address.base);
1545 return addressTempRegister;
1548 void moveFixedWidthEncoding(TrustedImm32 imm, RegisterID dst)
1550 uint32_t value = imm.m_value;
1551 m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff));
1552 m_assembler.movt(dst, ARMThumbImmediate::makeUInt16(value >> 16));
1555 ARMv7Assembler::Condition armV7Condition(RelationalCondition cond)
1557 return static_cast<ARMv7Assembler::Condition>(cond);
1560 ARMv7Assembler::Condition armV7Condition(ResultCondition cond)
1562 return static_cast<ARMv7Assembler::Condition>(cond);
1565 ARMv7Assembler::Condition armV7Condition(DoubleCondition cond)
1567 return static_cast<ARMv7Assembler::Condition>(cond);
1571 friend class LinkBuffer;
1572 friend class RepatchBuffer;
1574 static void linkCall(void* code, Call call, FunctionPtr function)
1576 ARMv7Assembler::linkCall(code, call.m_label, function.value());
1579 static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
1581 ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
1584 static void repatchCall(CodeLocationCall call, FunctionPtr destination)
1586 ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
1589 bool m_inUninterruptedSequence;
1594 #endif // ENABLE(ASSEMBLER)
1596 #endif // MacroAssemblerARMv7_h