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); }
49 : m_makeJumpPatchable(false)
53 typedef ARMv7Assembler::LinkRecord LinkRecord;
54 typedef ARMv7Assembler::JumpType JumpType;
55 typedef ARMv7Assembler::JumpLinkType JumpLinkType;
57 static bool isCompactPtrAlignedAddressOffset(ptrdiff_t value)
59 return value >= -255 && value <= 255;
62 Vector<LinkRecord, 0, UnsafeVectorOverflow>& 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 PositiveOrZero = ARMv7Assembler::ConditionPL,
123 Zero = ARMv7Assembler::ConditionEQ,
124 NonZero = ARMv7Assembler::ConditionNE
127 enum DoubleCondition {
128 // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
129 DoubleEqual = ARMv7Assembler::ConditionEQ,
130 DoubleNotEqual = ARMv7Assembler::ConditionVC, // Not the right flag! check for this & handle differently.
131 DoubleGreaterThan = ARMv7Assembler::ConditionGT,
132 DoubleGreaterThanOrEqual = ARMv7Assembler::ConditionGE,
133 DoubleLessThan = ARMv7Assembler::ConditionLO,
134 DoubleLessThanOrEqual = ARMv7Assembler::ConditionLS,
135 // If either operand is NaN, these conditions always evaluate to true.
136 DoubleEqualOrUnordered = ARMv7Assembler::ConditionVS, // Not the right flag! check for this & handle differently.
137 DoubleNotEqualOrUnordered = ARMv7Assembler::ConditionNE,
138 DoubleGreaterThanOrUnordered = ARMv7Assembler::ConditionHI,
139 DoubleGreaterThanOrEqualOrUnordered = ARMv7Assembler::ConditionHS,
140 DoubleLessThanOrUnordered = ARMv7Assembler::ConditionLT,
141 DoubleLessThanOrEqualOrUnordered = ARMv7Assembler::ConditionLE,
144 static const RegisterID stackPointerRegister = ARMRegisters::sp;
145 static const RegisterID linkRegister = ARMRegisters::lr;
147 // Integer arithmetic operations:
149 // Operations are typically two operand - operation(source, srcDst)
150 // For many operations the source may be an TrustedImm32, the srcDst operand
151 // may often be a memory location (explictly described using an Address
154 void add32(RegisterID src, RegisterID dest)
156 m_assembler.add(dest, dest, src);
159 void add32(TrustedImm32 imm, RegisterID dest)
161 add32(imm, dest, dest);
164 void add32(AbsoluteAddress src, RegisterID dest)
166 load32(src.m_ptr, dataTempRegister);
167 add32(dataTempRegister, dest);
170 void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
172 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
173 if (armImm.isValid())
174 m_assembler.add(dest, src, armImm);
176 move(imm, dataTempRegister);
177 m_assembler.add(dest, src, dataTempRegister);
181 void add32(TrustedImm32 imm, Address address)
183 load32(address, dataTempRegister);
185 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
186 if (armImm.isValid())
187 m_assembler.add(dataTempRegister, dataTempRegister, armImm);
189 // Hrrrm, since dataTempRegister holds the data loaded,
190 // use addressTempRegister to hold the immediate.
191 move(imm, addressTempRegister);
192 m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister);
195 store32(dataTempRegister, address);
198 void add32(Address src, RegisterID dest)
200 load32(src, dataTempRegister);
201 add32(dataTempRegister, dest);
204 void add32(TrustedImm32 imm, AbsoluteAddress address)
206 load32(address.m_ptr, dataTempRegister);
208 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
209 if (armImm.isValid())
210 m_assembler.add(dataTempRegister, dataTempRegister, armImm);
212 // Hrrrm, since dataTempRegister holds the data loaded,
213 // use addressTempRegister to hold the immediate.
214 move(imm, addressTempRegister);
215 m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister);
218 store32(dataTempRegister, address.m_ptr);
221 void add64(TrustedImm32 imm, AbsoluteAddress address)
223 move(TrustedImmPtr(address.m_ptr), addressTempRegister);
225 m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(0));
226 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
227 if (armImm.isValid())
228 m_assembler.add_S(dataTempRegister, dataTempRegister, armImm);
230 move(imm, addressTempRegister);
231 m_assembler.add_S(dataTempRegister, dataTempRegister, addressTempRegister);
232 move(TrustedImmPtr(address.m_ptr), addressTempRegister);
234 m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(0));
236 m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(4));
237 m_assembler.adc(dataTempRegister, dataTempRegister, ARMThumbImmediate::makeEncodedImm(imm.m_value >> 31));
238 m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(4));
241 void and32(RegisterID op1, RegisterID op2, RegisterID dest)
243 m_assembler.ARM_and(dest, op1, op2);
246 void and32(TrustedImm32 imm, RegisterID src, RegisterID dest)
248 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
249 if (armImm.isValid())
250 m_assembler.ARM_and(dest, src, armImm);
252 move(imm, dataTempRegister);
253 m_assembler.ARM_and(dest, src, dataTempRegister);
257 void and32(RegisterID src, RegisterID dest)
259 and32(dest, src, dest);
262 void and32(TrustedImm32 imm, RegisterID dest)
264 and32(imm, dest, dest);
267 void and32(Address src, RegisterID dest)
269 load32(src, dataTempRegister);
270 and32(dataTempRegister, dest);
273 void countLeadingZeros32(RegisterID src, RegisterID dest)
275 m_assembler.clz(dest, src);
278 void lshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
280 // Clamp the shift to the range 0..31
281 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
282 ASSERT(armImm.isValid());
283 m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm);
285 m_assembler.lsl(dest, src, dataTempRegister);
288 void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
290 m_assembler.lsl(dest, src, imm.m_value & 0x1f);
293 void lshift32(RegisterID shiftAmount, RegisterID dest)
295 lshift32(dest, shiftAmount, dest);
298 void lshift32(TrustedImm32 imm, RegisterID dest)
300 lshift32(dest, imm, dest);
303 void mul32(RegisterID src, RegisterID dest)
305 m_assembler.smull(dest, dataTempRegister, dest, src);
308 void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
310 move(imm, dataTempRegister);
311 m_assembler.smull(dest, dataTempRegister, src, dataTempRegister);
314 void neg32(RegisterID srcDest)
316 m_assembler.neg(srcDest, srcDest);
319 void or32(RegisterID src, RegisterID dest)
321 m_assembler.orr(dest, dest, src);
324 void or32(RegisterID src, AbsoluteAddress dest)
326 move(TrustedImmPtr(dest.m_ptr), addressTempRegister);
327 load32(addressTempRegister, dataTempRegister);
328 or32(src, dataTempRegister);
329 store32(dataTempRegister, addressTempRegister);
332 void or32(TrustedImm32 imm, RegisterID dest)
334 or32(imm, dest, dest);
337 void or32(RegisterID op1, RegisterID op2, RegisterID dest)
339 m_assembler.orr(dest, op1, op2);
342 void or32(TrustedImm32 imm, RegisterID src, RegisterID dest)
344 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
345 if (armImm.isValid())
346 m_assembler.orr(dest, src, armImm);
348 move(imm, dataTempRegister);
349 m_assembler.orr(dest, src, dataTempRegister);
353 void rshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
355 // Clamp the shift to the range 0..31
356 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
357 ASSERT(armImm.isValid());
358 m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm);
360 m_assembler.asr(dest, src, dataTempRegister);
363 void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
365 m_assembler.asr(dest, src, imm.m_value & 0x1f);
368 void rshift32(RegisterID shiftAmount, RegisterID dest)
370 rshift32(dest, shiftAmount, dest);
373 void rshift32(TrustedImm32 imm, RegisterID dest)
375 rshift32(dest, imm, dest);
378 void urshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
380 // Clamp the shift to the range 0..31
381 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
382 ASSERT(armImm.isValid());
383 m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm);
385 m_assembler.lsr(dest, src, dataTempRegister);
388 void urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
390 m_assembler.lsr(dest, src, imm.m_value & 0x1f);
393 void urshift32(RegisterID shiftAmount, RegisterID dest)
395 urshift32(dest, shiftAmount, dest);
398 void urshift32(TrustedImm32 imm, RegisterID dest)
400 urshift32(dest, imm, dest);
403 void sub32(RegisterID src, RegisterID dest)
405 m_assembler.sub(dest, dest, src);
408 void sub32(TrustedImm32 imm, RegisterID dest)
410 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
411 if (armImm.isValid())
412 m_assembler.sub(dest, dest, armImm);
414 move(imm, dataTempRegister);
415 m_assembler.sub(dest, dest, dataTempRegister);
419 void sub32(TrustedImm32 imm, Address address)
421 load32(address, dataTempRegister);
423 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
424 if (armImm.isValid())
425 m_assembler.sub(dataTempRegister, dataTempRegister, armImm);
427 // Hrrrm, since dataTempRegister holds the data loaded,
428 // use addressTempRegister to hold the immediate.
429 move(imm, addressTempRegister);
430 m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister);
433 store32(dataTempRegister, address);
436 void sub32(Address src, RegisterID dest)
438 load32(src, dataTempRegister);
439 sub32(dataTempRegister, dest);
442 void sub32(TrustedImm32 imm, AbsoluteAddress address)
444 load32(address.m_ptr, dataTempRegister);
446 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
447 if (armImm.isValid())
448 m_assembler.sub(dataTempRegister, dataTempRegister, armImm);
450 // Hrrrm, since dataTempRegister holds the data loaded,
451 // use addressTempRegister to hold the immediate.
452 move(imm, addressTempRegister);
453 m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister);
456 store32(dataTempRegister, address.m_ptr);
459 void xor32(RegisterID op1, RegisterID op2, RegisterID dest)
461 m_assembler.eor(dest, op1, op2);
464 void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest)
466 if (imm.m_value == -1) {
467 m_assembler.mvn(dest, src);
471 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
472 if (armImm.isValid())
473 m_assembler.eor(dest, src, armImm);
475 move(imm, dataTempRegister);
476 m_assembler.eor(dest, src, dataTempRegister);
480 void xor32(RegisterID src, RegisterID dest)
482 xor32(dest, src, dest);
485 void xor32(TrustedImm32 imm, RegisterID dest)
487 if (imm.m_value == -1)
488 m_assembler.mvn(dest, dest);
490 xor32(imm, dest, dest);
494 // Memory access operations:
496 // Loads are of the form load(address, destination) and stores of the form
497 // store(source, address). The source for a store may be an TrustedImm32. Address
498 // operand objects to loads and store will be implicitly constructed if a
499 // register is passed.
502 void load32(ArmAddress address, RegisterID dest)
504 if (address.type == ArmAddress::HasIndex)
505 m_assembler.ldr(dest, address.base, address.u.index, address.u.scale);
506 else if (address.u.offset >= 0) {
507 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
508 ASSERT(armImm.isValid());
509 m_assembler.ldr(dest, address.base, armImm);
511 ASSERT(address.u.offset >= -255);
512 m_assembler.ldr(dest, address.base, address.u.offset, true, false);
516 void load16(ArmAddress address, RegisterID dest)
518 if (address.type == ArmAddress::HasIndex)
519 m_assembler.ldrh(dest, address.base, address.u.index, address.u.scale);
520 else if (address.u.offset >= 0) {
521 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
522 ASSERT(armImm.isValid());
523 m_assembler.ldrh(dest, address.base, armImm);
525 ASSERT(address.u.offset >= -255);
526 m_assembler.ldrh(dest, address.base, address.u.offset, true, false);
530 void load16Signed(ArmAddress address, RegisterID dest)
532 ASSERT(address.type == ArmAddress::HasIndex);
533 m_assembler.ldrsh(dest, address.base, address.u.index, address.u.scale);
536 void load8(ArmAddress address, RegisterID dest)
538 if (address.type == ArmAddress::HasIndex)
539 m_assembler.ldrb(dest, address.base, address.u.index, address.u.scale);
540 else if (address.u.offset >= 0) {
541 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
542 ASSERT(armImm.isValid());
543 m_assembler.ldrb(dest, address.base, armImm);
545 ASSERT(address.u.offset >= -255);
546 m_assembler.ldrb(dest, address.base, address.u.offset, true, false);
550 void load8Signed(ArmAddress address, RegisterID dest)
552 ASSERT(address.type == ArmAddress::HasIndex);
553 m_assembler.ldrsb(dest, address.base, address.u.index, address.u.scale);
557 void store32(RegisterID src, ArmAddress address)
559 if (address.type == ArmAddress::HasIndex)
560 m_assembler.str(src, address.base, address.u.index, address.u.scale);
561 else if (address.u.offset >= 0) {
562 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
563 ASSERT(armImm.isValid());
564 m_assembler.str(src, address.base, armImm);
566 ASSERT(address.u.offset >= -255);
567 m_assembler.str(src, address.base, address.u.offset, true, false);
572 void store8(RegisterID src, ArmAddress address)
574 if (address.type == ArmAddress::HasIndex)
575 m_assembler.strb(src, address.base, address.u.index, address.u.scale);
576 else if (address.u.offset >= 0) {
577 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
578 ASSERT(armImm.isValid());
579 m_assembler.strb(src, address.base, armImm);
581 ASSERT(address.u.offset >= -255);
582 m_assembler.strb(src, address.base, address.u.offset, true, false);
586 void store16(RegisterID src, ArmAddress address)
588 if (address.type == ArmAddress::HasIndex)
589 m_assembler.strh(src, address.base, address.u.index, address.u.scale);
590 else if (address.u.offset >= 0) {
591 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
592 ASSERT(armImm.isValid());
593 m_assembler.strh(src, address.base, armImm);
595 ASSERT(address.u.offset >= -255);
596 m_assembler.strh(src, address.base, address.u.offset, true, false);
601 void load32(ImplicitAddress address, RegisterID dest)
603 load32(setupArmAddress(address), dest);
606 void load32(BaseIndex address, RegisterID dest)
608 load32(setupArmAddress(address), dest);
611 void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
613 load32(setupArmAddress(address), dest);
616 void load16Unaligned(BaseIndex address, RegisterID dest)
618 load16(setupArmAddress(address), dest);
621 void load32(const void* address, RegisterID dest)
623 move(TrustedImmPtr(address), addressTempRegister);
624 m_assembler.ldr(dest, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
627 ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest)
629 ConvertibleLoadLabel result(this);
630 ASSERT(address.offset >= 0 && address.offset <= 255);
631 m_assembler.ldrWide8BitImmediate(dest, address.base, address.offset);
635 void load8(ImplicitAddress address, RegisterID dest)
637 load8(setupArmAddress(address), dest);
640 void load8Signed(ImplicitAddress, RegisterID)
642 UNREACHABLE_FOR_PLATFORM();
645 void load8(BaseIndex address, RegisterID dest)
647 load8(setupArmAddress(address), dest);
650 void load8Signed(BaseIndex address, RegisterID dest)
652 load8Signed(setupArmAddress(address), dest);
655 DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
657 DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
658 load32(ArmAddress(address.base, dataTempRegister), dest);
662 DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
666 RegisterID base = address.base;
668 DataLabelCompact label(this);
669 ASSERT(isCompactPtrAlignedAddressOffset(address.offset));
671 m_assembler.ldr(dest, base, address.offset, true, false);
675 void load16(BaseIndex address, RegisterID dest)
677 m_assembler.ldrh(dest, makeBaseIndexBase(address), address.index, address.scale);
680 void load16Signed(BaseIndex address, RegisterID dest)
682 load16Signed(setupArmAddress(address), dest);
685 void load16(ImplicitAddress address, RegisterID dest)
687 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.offset);
688 if (armImm.isValid())
689 m_assembler.ldrh(dest, address.base, armImm);
691 move(TrustedImm32(address.offset), dataTempRegister);
692 m_assembler.ldrh(dest, address.base, dataTempRegister);
696 void load16Signed(ImplicitAddress, RegisterID)
698 UNREACHABLE_FOR_PLATFORM();
701 DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
703 DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
704 store32(src, ArmAddress(address.base, dataTempRegister));
708 void store32(RegisterID src, ImplicitAddress address)
710 store32(src, setupArmAddress(address));
713 void store32(RegisterID src, BaseIndex address)
715 store32(src, setupArmAddress(address));
718 void store32(TrustedImm32 imm, ImplicitAddress address)
720 move(imm, dataTempRegister);
721 store32(dataTempRegister, setupArmAddress(address));
724 void store32(TrustedImm32 imm, BaseIndex address)
726 move(imm, dataTempRegister);
727 store32(dataTempRegister, setupArmAddress(address));
730 void store32(RegisterID src, const void* address)
732 move(TrustedImmPtr(address), addressTempRegister);
733 m_assembler.str(src, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
736 void store32(TrustedImm32 imm, const void* address)
738 move(imm, dataTempRegister);
739 store32(dataTempRegister, address);
742 void store8(RegisterID src, BaseIndex address)
744 store8(src, setupArmAddress(address));
747 void store8(RegisterID src, void* address)
749 move(TrustedImmPtr(address), addressTempRegister);
750 store8(src, ArmAddress(addressTempRegister, 0));
753 void store8(TrustedImm32 imm, void* address)
755 move(imm, dataTempRegister);
756 store8(dataTempRegister, address);
759 void store16(RegisterID src, BaseIndex address)
761 store16(src, setupArmAddress(address));
764 // Possibly clobbers src, but not on this architecture.
765 void moveDoubleToInts(FPRegisterID src, RegisterID dest1, RegisterID dest2)
767 m_assembler.vmov(dest1, dest2, src);
770 void moveIntsToDouble(RegisterID src1, RegisterID src2, FPRegisterID dest, FPRegisterID scratch)
772 UNUSED_PARAM(scratch);
773 m_assembler.vmov(dest, src1, src2);
776 #if ENABLE(JIT_CONSTANT_BLINDING)
777 static bool shouldBlindForSpecificArch(uint32_t value)
779 ARMThumbImmediate immediate = ARMThumbImmediate::makeEncodedImm(value);
781 // Couldn't be encoded as an immediate, so assume it's untrusted.
782 if (!immediate.isValid())
785 // If we can encode the immediate, we have less than 16 attacker
787 if (immediate.isEncodedImm())
790 // Don't let any more than 12 bits of an instruction word
791 // be controlled by an attacker.
792 return !immediate.isUInt12();
796 // Floating-point operations:
798 static bool supportsFloatingPoint() { return true; }
799 static bool supportsFloatingPointTruncate() { return true; }
800 static bool supportsFloatingPointSqrt() { return true; }
801 static bool supportsFloatingPointAbs() { return true; }
803 void loadDouble(ImplicitAddress address, FPRegisterID dest)
805 RegisterID base = address.base;
806 int32_t offset = address.offset;
808 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
809 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
810 add32(TrustedImm32(offset), base, addressTempRegister);
811 base = addressTempRegister;
815 m_assembler.vldr(dest, base, offset);
818 void loadFloat(ImplicitAddress address, FPRegisterID dest)
820 RegisterID base = address.base;
821 int32_t offset = address.offset;
823 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
824 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
825 add32(TrustedImm32(offset), base, addressTempRegister);
826 base = addressTempRegister;
830 m_assembler.flds(ARMRegisters::asSingle(dest), base, offset);
833 void loadDouble(BaseIndex address, FPRegisterID dest)
835 move(address.index, addressTempRegister);
836 lshift32(TrustedImm32(address.scale), addressTempRegister);
837 add32(address.base, addressTempRegister);
838 loadDouble(Address(addressTempRegister, address.offset), dest);
841 void loadFloat(BaseIndex address, FPRegisterID dest)
843 move(address.index, addressTempRegister);
844 lshift32(TrustedImm32(address.scale), addressTempRegister);
845 add32(address.base, addressTempRegister);
846 loadFloat(Address(addressTempRegister, address.offset), dest);
849 void moveDouble(FPRegisterID src, FPRegisterID dest)
852 m_assembler.vmov(dest, src);
855 void loadDouble(const void* address, FPRegisterID dest)
857 move(TrustedImmPtr(address), addressTempRegister);
858 m_assembler.vldr(dest, addressTempRegister, 0);
861 void storeDouble(FPRegisterID src, ImplicitAddress address)
863 RegisterID base = address.base;
864 int32_t offset = address.offset;
866 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
867 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
868 add32(TrustedImm32(offset), base, addressTempRegister);
869 base = addressTempRegister;
873 m_assembler.vstr(src, base, offset);
876 void storeFloat(FPRegisterID src, ImplicitAddress address)
878 RegisterID base = address.base;
879 int32_t offset = address.offset;
881 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
882 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
883 add32(TrustedImm32(offset), base, addressTempRegister);
884 base = addressTempRegister;
888 m_assembler.fsts(ARMRegisters::asSingle(src), base, offset);
891 void storeDouble(FPRegisterID src, const void* address)
893 move(TrustedImmPtr(address), addressTempRegister);
894 storeDouble(src, addressTempRegister);
897 void storeDouble(FPRegisterID src, BaseIndex address)
899 move(address.index, addressTempRegister);
900 lshift32(TrustedImm32(address.scale), addressTempRegister);
901 add32(address.base, addressTempRegister);
902 storeDouble(src, Address(addressTempRegister, address.offset));
905 void storeFloat(FPRegisterID src, BaseIndex address)
907 move(address.index, addressTempRegister);
908 lshift32(TrustedImm32(address.scale), addressTempRegister);
909 add32(address.base, addressTempRegister);
910 storeFloat(src, Address(addressTempRegister, address.offset));
913 void addDouble(FPRegisterID src, FPRegisterID dest)
915 m_assembler.vadd(dest, dest, src);
918 void addDouble(Address src, FPRegisterID dest)
920 loadDouble(src, fpTempRegister);
921 addDouble(fpTempRegister, dest);
924 void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
926 m_assembler.vadd(dest, op1, op2);
929 void addDouble(AbsoluteAddress address, FPRegisterID dest)
931 loadDouble(address.m_ptr, fpTempRegister);
932 m_assembler.vadd(dest, dest, fpTempRegister);
935 void divDouble(FPRegisterID src, FPRegisterID dest)
937 m_assembler.vdiv(dest, dest, src);
940 void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
942 m_assembler.vdiv(dest, op1, op2);
945 void subDouble(FPRegisterID src, FPRegisterID dest)
947 m_assembler.vsub(dest, dest, src);
950 void subDouble(Address src, FPRegisterID dest)
952 loadDouble(src, fpTempRegister);
953 subDouble(fpTempRegister, dest);
956 void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
958 m_assembler.vsub(dest, op1, op2);
961 void mulDouble(FPRegisterID src, FPRegisterID dest)
963 m_assembler.vmul(dest, dest, src);
966 void mulDouble(Address src, FPRegisterID dest)
968 loadDouble(src, fpTempRegister);
969 mulDouble(fpTempRegister, dest);
972 void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
974 m_assembler.vmul(dest, op1, op2);
977 void sqrtDouble(FPRegisterID src, FPRegisterID dest)
979 m_assembler.vsqrt(dest, src);
982 void absDouble(FPRegisterID src, FPRegisterID dest)
984 m_assembler.vabs(dest, src);
987 void negateDouble(FPRegisterID src, FPRegisterID dest)
989 m_assembler.vneg(dest, src);
992 void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
994 m_assembler.vmov(fpTempRegister, src, src);
995 m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
998 void convertInt32ToDouble(Address address, FPRegisterID dest)
1000 // Fixme: load directly into the fpr!
1001 load32(address, dataTempRegister);
1002 m_assembler.vmov(fpTempRegister, dataTempRegister, dataTempRegister);
1003 m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
1006 void convertInt32ToDouble(AbsoluteAddress address, FPRegisterID dest)
1008 // Fixme: load directly into the fpr!
1009 load32(address.m_ptr, dataTempRegister);
1010 m_assembler.vmov(fpTempRegister, dataTempRegister, dataTempRegister);
1011 m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
1014 void convertFloatToDouble(FPRegisterID src, FPRegisterID dst)
1016 m_assembler.vcvtds(dst, ARMRegisters::asSingle(src));
1019 void convertDoubleToFloat(FPRegisterID src, FPRegisterID dst)
1021 m_assembler.vcvtsd(ARMRegisters::asSingle(dst), src);
1024 Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
1026 m_assembler.vcmp(left, right);
1029 if (cond == DoubleNotEqual) {
1030 // ConditionNE jumps if NotEqual *or* unordered - force the unordered cases not to jump.
1031 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1032 Jump result = makeBranch(ARMv7Assembler::ConditionNE);
1033 unordered.link(this);
1036 if (cond == DoubleEqualOrUnordered) {
1037 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1038 Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
1039 unordered.link(this);
1040 // We get here if either unordered or equal.
1041 Jump result = jump();
1042 notEqual.link(this);
1045 return makeBranch(cond);
1048 enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful };
1049 Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
1051 // Convert into dest.
1052 m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1053 m_assembler.vmov(dest, fpTempRegisterAsSingle());
1055 // Calculate 2x dest. If the value potentially underflowed, it will have
1056 // clamped to 0x80000000, so 2x dest is zero in this case. In the case of
1057 // overflow the result will be equal to -2.
1058 Jump underflow = branchAdd32(Zero, dest, dest, dataTempRegister);
1059 Jump noOverflow = branch32(NotEqual, dataTempRegister, TrustedImm32(-2));
1061 // For BranchIfTruncateSuccessful, we branch if 'noOverflow' jumps.
1062 underflow.link(this);
1063 if (branchType == BranchIfTruncateSuccessful)
1066 // We'll reach the current point in the code on failure, so plant a
1067 // jump here & link the success case.
1068 Jump failure = jump();
1069 noOverflow.link(this);
1073 Jump branchTruncateDoubleToUint32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
1075 m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1076 m_assembler.vmov(dest, fpTempRegisterAsSingle());
1078 Jump overflow = branch32(Equal, dest, TrustedImm32(0x7fffffff));
1079 Jump success = branch32(GreaterThanOrEqual, dest, TrustedImm32(0));
1080 overflow.link(this);
1082 if (branchType == BranchIfTruncateSuccessful)
1085 Jump failure = jump();
1090 // Result is undefined if the value is outside of the integer range.
1091 void truncateDoubleToInt32(FPRegisterID src, RegisterID dest)
1093 m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1094 m_assembler.vmov(dest, fpTempRegisterAsSingle());
1097 void truncateDoubleToUint32(FPRegisterID src, RegisterID dest)
1099 m_assembler.vcvt_floatingPointToUnsigned(fpTempRegisterAsSingle(), src);
1100 m_assembler.vmov(dest, fpTempRegisterAsSingle());
1103 // Convert 'src' to an integer, and places the resulting 'dest'.
1104 // If the result is not representable as a 32 bit value, branch.
1105 // May also branch for some values that are representable in 32 bits
1106 // (specifically, in this case, 0).
1107 void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID, bool negZeroCheck = true)
1109 m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1110 m_assembler.vmov(dest, fpTempRegisterAsSingle());
1112 // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
1113 m_assembler.vcvt_signedToFloatingPoint(fpTempRegister, fpTempRegisterAsSingle());
1114 failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, fpTempRegister));
1116 // If the result is zero, it might have been -0.0, and the double comparison won't catch this!
1118 failureCases.append(branchTest32(Zero, dest));
1121 Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID)
1123 m_assembler.vcmpz(reg);
1125 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1126 Jump result = makeBranch(ARMv7Assembler::ConditionNE);
1127 unordered.link(this);
1131 Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID)
1133 m_assembler.vcmpz(reg);
1135 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1136 Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
1137 unordered.link(this);
1138 // We get here if either unordered or equal.
1139 Jump result = jump();
1140 notEqual.link(this);
1144 // Stack manipulation operations:
1146 // The ABI is assumed to provide a stack abstraction to memory,
1147 // containing machine word sized units of data. Push and pop
1148 // operations add and remove a single register sized unit of data
1149 // to or from the stack. Peek and poke operations read or write
1150 // values on the stack, without moving the current stack position.
1152 void pop(RegisterID dest)
1154 // store postindexed with writeback
1155 m_assembler.ldr(dest, ARMRegisters::sp, sizeof(void*), false, true);
1158 void push(RegisterID src)
1160 // store preindexed with writeback
1161 m_assembler.str(src, ARMRegisters::sp, -sizeof(void*), true, true);
1164 void push(Address address)
1166 load32(address, dataTempRegister);
1167 push(dataTempRegister);
1170 void push(TrustedImm32 imm)
1172 move(imm, dataTempRegister);
1173 push(dataTempRegister);
1176 // Register move operations:
1178 // Move values in registers.
1180 void move(TrustedImm32 imm, RegisterID dest)
1182 uint32_t value = imm.m_value;
1184 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(value);
1186 if (armImm.isValid())
1187 m_assembler.mov(dest, armImm);
1188 else if ((armImm = ARMThumbImmediate::makeEncodedImm(~value)).isValid())
1189 m_assembler.mvn(dest, armImm);
1191 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(value));
1192 if (value & 0xffff0000)
1193 m_assembler.movt(dest, ARMThumbImmediate::makeUInt16(value >> 16));
1197 void move(RegisterID src, RegisterID dest)
1200 m_assembler.mov(dest, src);
1203 void move(TrustedImmPtr imm, RegisterID dest)
1205 move(TrustedImm32(imm), dest);
1208 void swap(RegisterID reg1, RegisterID reg2)
1210 move(reg1, dataTempRegister);
1212 move(dataTempRegister, reg2);
1215 void signExtend32ToPtr(RegisterID src, RegisterID dest)
1220 void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
1225 // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc.
1226 static RelationalCondition invert(RelationalCondition cond)
1228 return static_cast<RelationalCondition>(cond ^ 1);
1236 static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
1238 ARMv7Assembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation());
1241 static ptrdiff_t maxJumpReplacementSize()
1243 return ARMv7Assembler::maxJumpReplacementSize();
1246 // Forwards / external control flow operations:
1248 // This set of jump and conditional branch operations return a Jump
1249 // object which may linked at a later point, allow forwards jump,
1250 // or jumps that will require external linkage (after the code has been
1253 // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
1254 // respecitvely, for unsigned comparisons the names b, a, be, and ae are
1255 // used (representing the names 'below' and 'above').
1257 // Operands to the comparision are provided in the expected order, e.g.
1258 // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
1259 // treated as a signed 32bit value, is less than or equal to 5.
1261 // jz and jnz test whether the first operand is equal to zero, and take
1262 // an optional second operand of a mask under which to perform the test.
1265 // Should we be using TEQ for equal/not-equal?
1266 void compare32(RegisterID left, TrustedImm32 right)
1268 int32_t imm = right.m_value;
1270 m_assembler.tst(left, left);
1272 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
1273 if (armImm.isValid())
1274 m_assembler.cmp(left, armImm);
1275 else if ((armImm = ARMThumbImmediate::makeEncodedImm(-imm)).isValid())
1276 m_assembler.cmn(left, armImm);
1278 move(TrustedImm32(imm), dataTempRegister);
1279 m_assembler.cmp(left, dataTempRegister);
1284 void test32(RegisterID reg, TrustedImm32 mask)
1286 int32_t imm = mask.m_value;
1289 m_assembler.tst(reg, reg);
1291 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
1292 if (armImm.isValid())
1293 m_assembler.tst(reg, armImm);
1295 move(mask, dataTempRegister);
1296 m_assembler.tst(reg, dataTempRegister);
1302 Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
1304 m_assembler.cmp(left, right);
1305 return Jump(makeBranch(cond));
1308 Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1310 compare32(left, right);
1311 return Jump(makeBranch(cond));
1314 Jump branch32(RelationalCondition cond, RegisterID left, Address right)
1316 load32(right, dataTempRegister);
1317 return branch32(cond, left, dataTempRegister);
1320 Jump branch32(RelationalCondition cond, Address left, RegisterID right)
1322 load32(left, dataTempRegister);
1323 return branch32(cond, dataTempRegister, right);
1326 Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
1328 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1329 load32(left, addressTempRegister);
1330 return branch32(cond, addressTempRegister, right);
1333 Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1335 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1336 load32(left, addressTempRegister);
1337 return branch32(cond, addressTempRegister, right);
1340 Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1342 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1343 load32WithUnalignedHalfWords(left, addressTempRegister);
1344 return branch32(cond, addressTempRegister, right);
1347 Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
1349 load32(left.m_ptr, dataTempRegister);
1350 return branch32(cond, dataTempRegister, right);
1353 Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
1355 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1356 load32(left.m_ptr, addressTempRegister);
1357 return branch32(cond, addressTempRegister, right);
1360 Jump branch8(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1362 compare32(left, right);
1363 return Jump(makeBranch(cond));
1366 Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
1368 ASSERT(!(0xffffff00 & right.m_value));
1369 // use addressTempRegister incase the branch8 we call uses dataTempRegister. :-/
1370 load8(left, addressTempRegister);
1371 return branch8(cond, addressTempRegister, right);
1374 Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1376 ASSERT(!(0xffffff00 & right.m_value));
1377 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1378 load8(left, addressTempRegister);
1379 return branch32(cond, addressTempRegister, right);
1382 Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
1384 m_assembler.tst(reg, mask);
1385 return Jump(makeBranch(cond));
1388 Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1391 return Jump(makeBranch(cond));
1394 Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1396 // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
1397 load32(address, addressTempRegister);
1398 return branchTest32(cond, addressTempRegister, mask);
1401 Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
1403 // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
1404 load32(address, addressTempRegister);
1405 return branchTest32(cond, addressTempRegister, mask);
1408 Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1410 // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
1411 load8(address, addressTempRegister);
1412 return branchTest32(cond, addressTempRegister, mask);
1415 Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
1417 // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
1418 move(TrustedImmPtr(address.m_ptr), addressTempRegister);
1419 load8(Address(addressTempRegister), addressTempRegister);
1420 return branchTest32(cond, addressTempRegister, mask);
1423 void jump(RegisterID target)
1425 m_assembler.bx(target);
1428 // Address is a memory location containing the address to jump to
1429 void jump(Address address)
1431 load32(address, dataTempRegister);
1432 m_assembler.bx(dataTempRegister);
1435 void jump(AbsoluteAddress address)
1437 move(TrustedImmPtr(address.m_ptr), dataTempRegister);
1438 load32(Address(dataTempRegister), dataTempRegister);
1439 m_assembler.bx(dataTempRegister);
1443 // Arithmetic control flow operations:
1445 // This set of conditional branch operations branch based
1446 // on the result of an arithmetic operation. The operation
1447 // is performed as normal, storing the result.
1449 // * jz operations branch if the result is zero.
1450 // * jo operations branch if the (signed) arithmetic
1451 // operation caused an overflow to occur.
1453 Jump branchAdd32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
1455 m_assembler.add_S(dest, op1, op2);
1456 return Jump(makeBranch(cond));
1459 Jump branchAdd32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
1461 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1462 if (armImm.isValid())
1463 m_assembler.add_S(dest, op1, armImm);
1465 move(imm, dataTempRegister);
1466 m_assembler.add_S(dest, op1, dataTempRegister);
1468 return Jump(makeBranch(cond));
1471 Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
1473 return branchAdd32(cond, dest, src, dest);
1476 Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1478 return branchAdd32(cond, dest, imm, dest);
1481 Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest)
1483 // Move the high bits of the address into addressTempRegister,
1484 // and load the value into dataTempRegister.
1485 move(TrustedImmPtr(dest.m_ptr), addressTempRegister);
1486 m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
1489 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1490 if (armImm.isValid())
1491 m_assembler.add_S(dataTempRegister, dataTempRegister, armImm);
1493 // If the operand does not fit into an immediate then load it temporarily
1494 // into addressTempRegister; since we're overwriting addressTempRegister
1495 // we'll need to reload it with the high bits of the address afterwards.
1496 move(imm, addressTempRegister);
1497 m_assembler.add_S(dataTempRegister, dataTempRegister, addressTempRegister);
1498 move(TrustedImmPtr(dest.m_ptr), addressTempRegister);
1501 // Store the result.
1502 m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
1504 return Jump(makeBranch(cond));
1507 Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
1509 m_assembler.smull(dest, dataTempRegister, src1, src2);
1511 if (cond == Overflow) {
1512 m_assembler.asr(addressTempRegister, dest, 31);
1513 return branch32(NotEqual, addressTempRegister, dataTempRegister);
1516 return branchTest32(cond, dest);
1519 Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
1521 return branchMul32(cond, src, dest, dest);
1524 Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
1526 move(imm, dataTempRegister);
1527 return branchMul32(cond, dataTempRegister, src, dest);
1530 Jump branchNeg32(ResultCondition cond, RegisterID srcDest)
1532 ARMThumbImmediate zero = ARMThumbImmediate::makeUInt12(0);
1533 m_assembler.sub_S(srcDest, zero, srcDest);
1534 return Jump(makeBranch(cond));
1537 Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
1539 m_assembler.orr_S(dest, dest, src);
1540 return Jump(makeBranch(cond));
1543 Jump branchSub32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
1545 m_assembler.sub_S(dest, op1, op2);
1546 return Jump(makeBranch(cond));
1549 Jump branchSub32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
1551 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1552 if (armImm.isValid())
1553 m_assembler.sub_S(dest, op1, armImm);
1555 move(imm, dataTempRegister);
1556 m_assembler.sub_S(dest, op1, dataTempRegister);
1558 return Jump(makeBranch(cond));
1561 Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
1563 return branchSub32(cond, dest, src, dest);
1566 Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1568 return branchSub32(cond, dest, imm, dest);
1571 void relativeTableJump(RegisterID index, int scale)
1573 ASSERT(scale >= 0 && scale <= 31);
1575 // dataTempRegister will point after the jump if index register contains zero
1576 move(ARMRegisters::pc, dataTempRegister);
1577 m_assembler.add(dataTempRegister, dataTempRegister, ARMThumbImmediate::makeEncodedImm(9));
1579 ShiftTypeAndAmount shift(SRType_LSL, scale);
1580 m_assembler.add(dataTempRegister, dataTempRegister, index, shift);
1581 jump(dataTempRegister);
1584 // Miscellaneous operations:
1586 void breakpoint(uint8_t imm = 0)
1588 m_assembler.bkpt(imm);
1591 ALWAYS_INLINE Call nearCall()
1593 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1594 return Call(m_assembler.blx(dataTempRegister), Call::LinkableNear);
1597 ALWAYS_INLINE Call call()
1599 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1600 return Call(m_assembler.blx(dataTempRegister), Call::Linkable);
1603 ALWAYS_INLINE Call call(RegisterID target)
1605 return Call(m_assembler.blx(target), Call::None);
1608 ALWAYS_INLINE Call call(Address address)
1610 load32(address, dataTempRegister);
1611 return Call(m_assembler.blx(dataTempRegister), Call::None);
1614 ALWAYS_INLINE void ret()
1616 m_assembler.bx(linkRegister);
1619 void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
1621 m_assembler.cmp(left, right);
1622 m_assembler.it(armV7Condition(cond), false);
1623 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1624 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1627 void compare32(RelationalCondition cond, Address left, RegisterID right, RegisterID dest)
1629 load32(left, dataTempRegister);
1630 compare32(cond, dataTempRegister, right, dest);
1633 void compare8(RelationalCondition cond, Address left, TrustedImm32 right, RegisterID dest)
1635 load8(left, addressTempRegister);
1636 compare32(cond, addressTempRegister, right, dest);
1639 void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
1641 compare32(left, right);
1642 m_assembler.it(armV7Condition(cond), false);
1643 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1644 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1648 // The mask should be optional... paerhaps the argument order should be
1649 // dest-src, operations always have a dest? ... possibly not true, considering
1650 // asm ops like test, or pseudo ops like pop().
1651 void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1653 load32(address, dataTempRegister);
1654 test32(dataTempRegister, mask);
1655 m_assembler.it(armV7Condition(cond), false);
1656 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1657 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1660 void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1662 load8(address, dataTempRegister);
1663 test32(dataTempRegister, mask);
1664 m_assembler.it(armV7Condition(cond), false);
1665 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1666 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1669 ALWAYS_INLINE DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dst)
1672 moveFixedWidthEncoding(imm, dst);
1673 return DataLabel32(this);
1676 ALWAYS_INLINE DataLabelPtr moveWithPatch(TrustedImmPtr imm, RegisterID dst)
1679 moveFixedWidthEncoding(TrustedImm32(imm), dst);
1680 return DataLabelPtr(this);
1683 ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1685 dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1686 return branch32(cond, left, dataTempRegister);
1689 ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1691 load32(left, addressTempRegister);
1692 dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1693 return branch32(cond, addressTempRegister, dataTempRegister);
1696 PatchableJump patchableBranchPtr(RelationalCondition cond, Address left, TrustedImmPtr right = TrustedImmPtr(0))
1698 m_makeJumpPatchable = true;
1699 Jump result = branch32(cond, left, TrustedImm32(right));
1700 m_makeJumpPatchable = false;
1701 return PatchableJump(result);
1704 PatchableJump patchableBranchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1706 m_makeJumpPatchable = true;
1707 Jump result = branchTest32(cond, reg, mask);
1708 m_makeJumpPatchable = false;
1709 return PatchableJump(result);
1712 PatchableJump patchableBranch32(RelationalCondition cond, RegisterID reg, TrustedImm32 imm)
1714 m_makeJumpPatchable = true;
1715 Jump result = branch32(cond, reg, imm);
1716 m_makeJumpPatchable = false;
1717 return PatchableJump(result);
1720 PatchableJump patchableBranchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1722 m_makeJumpPatchable = true;
1723 Jump result = branchPtrWithPatch(cond, left, dataLabel, initialRightValue);
1724 m_makeJumpPatchable = false;
1725 return PatchableJump(result);
1728 PatchableJump patchableJump()
1731 m_makeJumpPatchable = true;
1732 Jump result = jump();
1733 m_makeJumpPatchable = false;
1734 return PatchableJump(result);
1737 ALWAYS_INLINE DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
1739 DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister);
1740 store32(dataTempRegister, address);
1743 ALWAYS_INLINE DataLabelPtr storePtrWithPatch(ImplicitAddress address) { return storePtrWithPatch(TrustedImmPtr(0), address); }
1746 ALWAYS_INLINE Call tailRecursiveCall()
1748 // Like a normal call, but don't link.
1749 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1750 return Call(m_assembler.bx(dataTempRegister), Call::Linkable);
1753 ALWAYS_INLINE Call makeTailRecursiveCall(Jump oldJump)
1756 return tailRecursiveCall();
1760 int executableOffsetFor(int location)
1762 return m_assembler.executableOffsetFor(location);
1765 static FunctionPtr readCallTarget(CodeLocationCall call)
1767 return FunctionPtr(reinterpret_cast<void(*)()>(ARMv7Assembler::readCallTarget(call.dataLocation())));
1770 static bool canJumpReplacePatchableBranchPtrWithPatch() { return false; }
1772 static CodeLocationLabel startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label)
1774 const unsigned twoWordOpSize = 4;
1775 return label.labelAtOffset(-twoWordOpSize * 2);
1778 static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID rd, void* initialValue)
1780 #if OS(LINUX) || OS(QNX)
1781 ARMv7Assembler::revertJumpTo_movT3movtcmpT2(instructionStart.dataLocation(), rd, dataTempRegister, reinterpret_cast<uintptr_t>(initialValue));
1784 ARMv7Assembler::revertJumpTo_movT3(instructionStart.dataLocation(), dataTempRegister, ARMThumbImmediate::makeUInt16(reinterpret_cast<uintptr_t>(initialValue) & 0xffff));
1788 static CodeLocationLabel startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr)
1790 UNREACHABLE_FOR_PLATFORM();
1791 return CodeLocationLabel();
1794 static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel, Address, void*)
1796 UNREACHABLE_FOR_PLATFORM();
1800 ALWAYS_INLINE Jump jump()
1802 m_assembler.label(); // Force nop-padding if we're in the middle of a watchpoint.
1803 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1804 return Jump(m_assembler.bx(dataTempRegister), m_makeJumpPatchable ? ARMv7Assembler::JumpNoConditionFixedSize : ARMv7Assembler::JumpNoCondition);
1807 ALWAYS_INLINE Jump makeBranch(ARMv7Assembler::Condition cond)
1809 m_assembler.label(); // Force nop-padding if we're in the middle of a watchpoint.
1810 m_assembler.it(cond, true, true);
1811 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1812 return Jump(m_assembler.bx(dataTempRegister), m_makeJumpPatchable ? ARMv7Assembler::JumpConditionFixedSize : ARMv7Assembler::JumpCondition, cond);
1814 ALWAYS_INLINE Jump makeBranch(RelationalCondition cond) { return makeBranch(armV7Condition(cond)); }
1815 ALWAYS_INLINE Jump makeBranch(ResultCondition cond) { return makeBranch(armV7Condition(cond)); }
1816 ALWAYS_INLINE Jump makeBranch(DoubleCondition cond) { return makeBranch(armV7Condition(cond)); }
1818 ArmAddress setupArmAddress(BaseIndex address)
1820 if (address.offset) {
1821 ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
1823 m_assembler.add(addressTempRegister, address.base, imm);
1825 move(TrustedImm32(address.offset), addressTempRegister);
1826 m_assembler.add(addressTempRegister, addressTempRegister, address.base);
1829 return ArmAddress(addressTempRegister, address.index, address.scale);
1831 return ArmAddress(address.base, address.index, address.scale);
1834 ArmAddress setupArmAddress(Address address)
1836 if ((address.offset >= -0xff) && (address.offset <= 0xfff))
1837 return ArmAddress(address.base, address.offset);
1839 move(TrustedImm32(address.offset), addressTempRegister);
1840 return ArmAddress(address.base, addressTempRegister);
1843 ArmAddress setupArmAddress(ImplicitAddress address)
1845 if ((address.offset >= -0xff) && (address.offset <= 0xfff))
1846 return ArmAddress(address.base, address.offset);
1848 move(TrustedImm32(address.offset), addressTempRegister);
1849 return ArmAddress(address.base, addressTempRegister);
1852 RegisterID makeBaseIndexBase(BaseIndex address)
1854 if (!address.offset)
1855 return address.base;
1857 ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
1859 m_assembler.add(addressTempRegister, address.base, imm);
1861 move(TrustedImm32(address.offset), addressTempRegister);
1862 m_assembler.add(addressTempRegister, addressTempRegister, address.base);
1865 return addressTempRegister;
1868 void moveFixedWidthEncoding(TrustedImm32 imm, RegisterID dst)
1870 uint32_t value = imm.m_value;
1871 m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff));
1872 m_assembler.movt(dst, ARMThumbImmediate::makeUInt16(value >> 16));
1875 ARMv7Assembler::Condition armV7Condition(RelationalCondition cond)
1877 return static_cast<ARMv7Assembler::Condition>(cond);
1880 ARMv7Assembler::Condition armV7Condition(ResultCondition cond)
1882 return static_cast<ARMv7Assembler::Condition>(cond);
1885 ARMv7Assembler::Condition armV7Condition(DoubleCondition cond)
1887 return static_cast<ARMv7Assembler::Condition>(cond);
1891 friend class LinkBuffer;
1892 friend class RepatchBuffer;
1894 static void linkCall(void* code, Call call, FunctionPtr function)
1896 ARMv7Assembler::linkCall(code, call.m_label, function.value());
1899 static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
1901 ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
1904 static void repatchCall(CodeLocationCall call, FunctionPtr destination)
1906 ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
1909 bool m_makeJumpPatchable;
1914 #endif // ENABLE(ASSEMBLER)
1916 #endif // MacroAssemblerARMv7_h