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>& 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(AbsoluteAddress src, RegisterID dest)
165 load32(src.m_ptr, dataTempRegister);
166 add32(dataTempRegister, dest);
169 void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
171 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
172 if (armImm.isValid())
173 m_assembler.add(dest, src, armImm);
175 move(imm, dataTempRegister);
176 m_assembler.add(dest, src, dataTempRegister);
180 void add32(TrustedImm32 imm, Address address)
182 load32(address, dataTempRegister);
184 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
185 if (armImm.isValid())
186 m_assembler.add(dataTempRegister, dataTempRegister, armImm);
188 // Hrrrm, since dataTempRegister holds the data loaded,
189 // use addressTempRegister to hold the immediate.
190 move(imm, addressTempRegister);
191 m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister);
194 store32(dataTempRegister, address);
197 void add32(Address src, RegisterID dest)
199 load32(src, dataTempRegister);
200 add32(dataTempRegister, dest);
203 void add32(TrustedImm32 imm, AbsoluteAddress address)
205 load32(address.m_ptr, dataTempRegister);
207 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
208 if (armImm.isValid())
209 m_assembler.add(dataTempRegister, dataTempRegister, armImm);
211 // Hrrrm, since dataTempRegister holds the data loaded,
212 // use addressTempRegister to hold the immediate.
213 move(imm, addressTempRegister);
214 m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister);
217 store32(dataTempRegister, address.m_ptr);
220 void add64(TrustedImm32 imm, AbsoluteAddress address)
222 move(TrustedImmPtr(address.m_ptr), addressTempRegister);
224 m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(0));
225 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
226 if (armImm.isValid())
227 m_assembler.add_S(dataTempRegister, dataTempRegister, armImm);
229 move(imm, addressTempRegister);
230 m_assembler.add_S(dataTempRegister, dataTempRegister, addressTempRegister);
231 move(TrustedImmPtr(address.m_ptr), addressTempRegister);
233 m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(0));
235 m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(4));
236 m_assembler.adc(dataTempRegister, dataTempRegister, ARMThumbImmediate::makeEncodedImm(imm.m_value >> 31));
237 m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(4));
240 void and32(RegisterID op1, RegisterID op2, RegisterID dest)
242 m_assembler.ARM_and(dest, op1, op2);
245 void and32(TrustedImm32 imm, RegisterID src, RegisterID dest)
247 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
248 if (armImm.isValid())
249 m_assembler.ARM_and(dest, src, armImm);
251 move(imm, dataTempRegister);
252 m_assembler.ARM_and(dest, src, dataTempRegister);
256 void and32(RegisterID src, RegisterID dest)
258 and32(dest, src, dest);
261 void and32(TrustedImm32 imm, RegisterID dest)
263 and32(imm, dest, dest);
266 void countLeadingZeros32(RegisterID src, RegisterID dest)
268 m_assembler.clz(dest, src);
271 void lshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
273 // Clamp the shift to the range 0..31
274 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
275 ASSERT(armImm.isValid());
276 m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm);
278 m_assembler.lsl(dest, src, dataTempRegister);
281 void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
283 m_assembler.lsl(dest, src, imm.m_value & 0x1f);
286 void lshift32(RegisterID shiftAmount, RegisterID dest)
288 lshift32(dest, shiftAmount, dest);
291 void lshift32(TrustedImm32 imm, RegisterID dest)
293 lshift32(dest, imm, dest);
296 void mul32(RegisterID src, RegisterID dest)
298 m_assembler.smull(dest, dataTempRegister, dest, src);
301 void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
303 move(imm, dataTempRegister);
304 m_assembler.smull(dest, dataTempRegister, src, dataTempRegister);
307 void neg32(RegisterID srcDest)
309 m_assembler.neg(srcDest, srcDest);
312 void or32(RegisterID src, RegisterID dest)
314 m_assembler.orr(dest, dest, src);
317 void or32(TrustedImm32 imm, RegisterID dest)
319 or32(imm, dest, dest);
322 void or32(RegisterID op1, RegisterID op2, RegisterID dest)
324 m_assembler.orr(dest, op1, op2);
327 void or32(TrustedImm32 imm, RegisterID src, RegisterID dest)
329 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
330 if (armImm.isValid())
331 m_assembler.orr(dest, src, armImm);
333 move(imm, dataTempRegister);
334 m_assembler.orr(dest, src, dataTempRegister);
338 void rshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
340 // Clamp the shift to the range 0..31
341 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
342 ASSERT(armImm.isValid());
343 m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm);
345 m_assembler.asr(dest, src, dataTempRegister);
348 void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
350 m_assembler.asr(dest, src, imm.m_value & 0x1f);
353 void rshift32(RegisterID shiftAmount, RegisterID dest)
355 rshift32(dest, shiftAmount, dest);
358 void rshift32(TrustedImm32 imm, RegisterID dest)
360 rshift32(dest, imm, dest);
363 void urshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
365 // Clamp the shift to the range 0..31
366 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
367 ASSERT(armImm.isValid());
368 m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm);
370 m_assembler.lsr(dest, src, dataTempRegister);
373 void urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
375 m_assembler.lsr(dest, src, imm.m_value & 0x1f);
378 void urshift32(RegisterID shiftAmount, RegisterID dest)
380 urshift32(dest, shiftAmount, dest);
383 void urshift32(TrustedImm32 imm, RegisterID dest)
385 urshift32(dest, imm, dest);
388 void sub32(RegisterID src, RegisterID dest)
390 m_assembler.sub(dest, dest, src);
393 void sub32(TrustedImm32 imm, RegisterID dest)
395 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
396 if (armImm.isValid())
397 m_assembler.sub(dest, dest, armImm);
399 move(imm, dataTempRegister);
400 m_assembler.sub(dest, dest, dataTempRegister);
404 void sub32(TrustedImm32 imm, Address address)
406 load32(address, dataTempRegister);
408 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
409 if (armImm.isValid())
410 m_assembler.sub(dataTempRegister, dataTempRegister, armImm);
412 // Hrrrm, since dataTempRegister holds the data loaded,
413 // use addressTempRegister to hold the immediate.
414 move(imm, addressTempRegister);
415 m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister);
418 store32(dataTempRegister, address);
421 void sub32(Address src, RegisterID dest)
423 load32(src, dataTempRegister);
424 sub32(dataTempRegister, dest);
427 void sub32(TrustedImm32 imm, AbsoluteAddress address)
429 load32(address.m_ptr, dataTempRegister);
431 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
432 if (armImm.isValid())
433 m_assembler.sub(dataTempRegister, dataTempRegister, armImm);
435 // Hrrrm, since dataTempRegister holds the data loaded,
436 // use addressTempRegister to hold the immediate.
437 move(imm, addressTempRegister);
438 m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister);
441 store32(dataTempRegister, address.m_ptr);
444 void xor32(RegisterID op1, RegisterID op2, RegisterID dest)
446 m_assembler.eor(dest, op1, op2);
449 void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest)
451 if (imm.m_value == -1) {
452 m_assembler.mvn(dest, src);
456 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
457 if (armImm.isValid())
458 m_assembler.eor(dest, src, armImm);
460 move(imm, dataTempRegister);
461 m_assembler.eor(dest, src, dataTempRegister);
465 void xor32(RegisterID src, RegisterID dest)
467 xor32(dest, src, dest);
470 void xor32(TrustedImm32 imm, RegisterID dest)
472 if (imm.m_value == -1)
473 m_assembler.mvn(dest, dest);
475 xor32(imm, dest, dest);
479 // Memory access operations:
481 // Loads are of the form load(address, destination) and stores of the form
482 // store(source, address). The source for a store may be an TrustedImm32. Address
483 // operand objects to loads and store will be implicitly constructed if a
484 // register is passed.
487 void load32(ArmAddress address, RegisterID dest)
489 if (address.type == ArmAddress::HasIndex)
490 m_assembler.ldr(dest, address.base, address.u.index, address.u.scale);
491 else if (address.u.offset >= 0) {
492 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
493 ASSERT(armImm.isValid());
494 m_assembler.ldr(dest, address.base, armImm);
496 ASSERT(address.u.offset >= -255);
497 m_assembler.ldr(dest, address.base, address.u.offset, true, false);
501 void load16(ArmAddress address, RegisterID dest)
503 if (address.type == ArmAddress::HasIndex)
504 m_assembler.ldrh(dest, address.base, address.u.index, address.u.scale);
505 else if (address.u.offset >= 0) {
506 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
507 ASSERT(armImm.isValid());
508 m_assembler.ldrh(dest, address.base, armImm);
510 ASSERT(address.u.offset >= -255);
511 m_assembler.ldrh(dest, address.base, address.u.offset, true, false);
515 void load16Signed(ArmAddress address, RegisterID dest)
517 ASSERT(address.type == ArmAddress::HasIndex);
518 m_assembler.ldrsh(dest, address.base, address.u.index, address.u.scale);
521 void load8(ArmAddress address, RegisterID dest)
523 if (address.type == ArmAddress::HasIndex)
524 m_assembler.ldrb(dest, address.base, address.u.index, address.u.scale);
525 else if (address.u.offset >= 0) {
526 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
527 ASSERT(armImm.isValid());
528 m_assembler.ldrb(dest, address.base, armImm);
530 ASSERT(address.u.offset >= -255);
531 m_assembler.ldrb(dest, address.base, address.u.offset, true, false);
535 void load8Signed(ArmAddress address, RegisterID dest)
537 ASSERT(address.type == ArmAddress::HasIndex);
538 m_assembler.ldrsb(dest, address.base, address.u.index, address.u.scale);
542 void store32(RegisterID src, ArmAddress address)
544 if (address.type == ArmAddress::HasIndex)
545 m_assembler.str(src, address.base, address.u.index, address.u.scale);
546 else if (address.u.offset >= 0) {
547 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
548 ASSERT(armImm.isValid());
549 m_assembler.str(src, address.base, armImm);
551 ASSERT(address.u.offset >= -255);
552 m_assembler.str(src, address.base, address.u.offset, true, false);
557 void store8(RegisterID src, ArmAddress address)
559 if (address.type == ArmAddress::HasIndex)
560 m_assembler.strb(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.strb(src, address.base, armImm);
566 ASSERT(address.u.offset >= -255);
567 m_assembler.strb(src, address.base, address.u.offset, true, false);
571 void store16(RegisterID src, ArmAddress address)
573 if (address.type == ArmAddress::HasIndex)
574 m_assembler.strh(src, address.base, address.u.index, address.u.scale);
575 else if (address.u.offset >= 0) {
576 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
577 ASSERT(armImm.isValid());
578 m_assembler.strh(src, address.base, armImm);
580 ASSERT(address.u.offset >= -255);
581 m_assembler.strh(src, address.base, address.u.offset, true, false);
586 void load32(ImplicitAddress address, RegisterID dest)
588 load32(setupArmAddress(address), dest);
591 void load32(BaseIndex address, RegisterID dest)
593 load32(setupArmAddress(address), dest);
596 void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
598 load32(setupArmAddress(address), dest);
601 void load16Unaligned(BaseIndex address, RegisterID dest)
603 load16(setupArmAddress(address), dest);
606 void load32(const void* address, RegisterID dest)
608 move(TrustedImmPtr(address), addressTempRegister);
609 m_assembler.ldr(dest, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
612 ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest)
614 ConvertibleLoadLabel result(this);
615 ASSERT(address.offset >= 0 && address.offset <= 255);
616 m_assembler.ldrWide8BitImmediate(dest, address.base, address.offset);
620 void load8(ImplicitAddress address, RegisterID dest)
622 load8(setupArmAddress(address), dest);
625 void load8Signed(ImplicitAddress, RegisterID)
627 UNREACHABLE_FOR_PLATFORM();
630 void load8(BaseIndex address, RegisterID dest)
632 load8(setupArmAddress(address), dest);
635 void load8Signed(BaseIndex address, RegisterID dest)
637 load8Signed(setupArmAddress(address), dest);
640 DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
642 DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
643 load32(ArmAddress(address.base, dataTempRegister), dest);
647 DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
649 RegisterID base = address.base;
651 DataLabelCompact label(this);
652 ASSERT(isCompactPtrAlignedAddressOffset(address.offset));
654 m_assembler.ldr(dest, base, address.offset, true, false);
658 void load16(BaseIndex address, RegisterID dest)
660 m_assembler.ldrh(dest, makeBaseIndexBase(address), address.index, address.scale);
663 void load16Signed(BaseIndex address, RegisterID dest)
665 load16Signed(setupArmAddress(address), dest);
668 void load16(ImplicitAddress address, RegisterID dest)
670 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.offset);
671 if (armImm.isValid())
672 m_assembler.ldrh(dest, address.base, armImm);
674 move(TrustedImm32(address.offset), dataTempRegister);
675 m_assembler.ldrh(dest, address.base, dataTempRegister);
679 void load16Signed(ImplicitAddress, RegisterID)
681 UNREACHABLE_FOR_PLATFORM();
684 DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
686 DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
687 store32(src, ArmAddress(address.base, dataTempRegister));
691 void store32(RegisterID src, ImplicitAddress address)
693 store32(src, setupArmAddress(address));
696 void store32(RegisterID src, BaseIndex address)
698 store32(src, setupArmAddress(address));
701 void store32(TrustedImm32 imm, ImplicitAddress address)
703 move(imm, dataTempRegister);
704 store32(dataTempRegister, setupArmAddress(address));
707 void store32(TrustedImm32 imm, BaseIndex address)
709 move(imm, dataTempRegister);
710 store32(dataTempRegister, setupArmAddress(address));
713 void store32(RegisterID src, const void* address)
715 move(TrustedImmPtr(address), addressTempRegister);
716 m_assembler.str(src, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
719 void store32(TrustedImm32 imm, const void* address)
721 move(imm, dataTempRegister);
722 store32(dataTempRegister, address);
725 void store8(RegisterID src, BaseIndex address)
727 store8(src, setupArmAddress(address));
730 void store16(RegisterID src, BaseIndex address)
732 store16(src, setupArmAddress(address));
735 #if ENABLE(JIT_CONSTANT_BLINDING)
736 static bool shouldBlindForSpecificArch(uint32_t value)
738 ARMThumbImmediate immediate = ARMThumbImmediate::makeEncodedImm(value);
740 // Couldn't be encoded as an immediate, so assume it's untrusted.
741 if (!immediate.isValid())
744 // If we can encode the immediate, we have less than 16 attacker
746 if (immediate.isEncodedImm())
749 // Don't let any more than 12 bits of an instruction word
750 // be controlled by an attacker.
751 return !immediate.isUInt12();
755 // Floating-point operations:
757 static bool supportsFloatingPoint() { return true; }
758 static bool supportsFloatingPointTruncate() { return true; }
759 static bool supportsFloatingPointSqrt() { return true; }
760 static bool supportsFloatingPointAbs() { return true; }
762 void loadDouble(ImplicitAddress address, FPRegisterID dest)
764 RegisterID base = address.base;
765 int32_t offset = address.offset;
767 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
768 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
769 add32(TrustedImm32(offset), base, addressTempRegister);
770 base = addressTempRegister;
774 m_assembler.vldr(dest, base, offset);
777 void loadFloat(ImplicitAddress address, FPRegisterID dest)
779 RegisterID base = address.base;
780 int32_t offset = address.offset;
782 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
783 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
784 add32(TrustedImm32(offset), base, addressTempRegister);
785 base = addressTempRegister;
789 m_assembler.flds(ARMRegisters::asSingle(dest), base, offset);
792 void loadDouble(BaseIndex address, FPRegisterID dest)
794 move(address.index, addressTempRegister);
795 lshift32(TrustedImm32(address.scale), addressTempRegister);
796 add32(address.base, addressTempRegister);
797 loadDouble(Address(addressTempRegister, address.offset), dest);
800 void loadFloat(BaseIndex address, FPRegisterID dest)
802 move(address.index, addressTempRegister);
803 lshift32(TrustedImm32(address.scale), addressTempRegister);
804 add32(address.base, addressTempRegister);
805 loadFloat(Address(addressTempRegister, address.offset), dest);
808 void moveDouble(FPRegisterID src, FPRegisterID dest)
811 m_assembler.vmov(dest, src);
814 void loadDouble(const void* address, FPRegisterID dest)
816 move(TrustedImmPtr(address), addressTempRegister);
817 m_assembler.vldr(dest, addressTempRegister, 0);
820 void storeDouble(FPRegisterID src, ImplicitAddress address)
822 RegisterID base = address.base;
823 int32_t offset = address.offset;
825 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
826 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
827 add32(TrustedImm32(offset), base, addressTempRegister);
828 base = addressTempRegister;
832 m_assembler.vstr(src, base, offset);
835 void storeFloat(FPRegisterID src, ImplicitAddress address)
837 RegisterID base = address.base;
838 int32_t offset = address.offset;
840 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
841 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
842 add32(TrustedImm32(offset), base, addressTempRegister);
843 base = addressTempRegister;
847 m_assembler.fsts(ARMRegisters::asSingle(src), base, offset);
850 void storeDouble(FPRegisterID src, const void* address)
852 move(TrustedImmPtr(address), addressTempRegister);
853 storeDouble(src, addressTempRegister);
856 void storeDouble(FPRegisterID src, BaseIndex address)
858 move(address.index, addressTempRegister);
859 lshift32(TrustedImm32(address.scale), addressTempRegister);
860 add32(address.base, addressTempRegister);
861 storeDouble(src, Address(addressTempRegister, address.offset));
864 void storeFloat(FPRegisterID src, BaseIndex address)
866 move(address.index, addressTempRegister);
867 lshift32(TrustedImm32(address.scale), addressTempRegister);
868 add32(address.base, addressTempRegister);
869 storeFloat(src, Address(addressTempRegister, address.offset));
872 void addDouble(FPRegisterID src, FPRegisterID dest)
874 m_assembler.vadd(dest, dest, src);
877 void addDouble(Address src, FPRegisterID dest)
879 loadDouble(src, fpTempRegister);
880 addDouble(fpTempRegister, dest);
883 void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
885 m_assembler.vadd(dest, op1, op2);
888 void addDouble(AbsoluteAddress address, FPRegisterID dest)
890 loadDouble(address.m_ptr, fpTempRegister);
891 m_assembler.vadd(dest, dest, fpTempRegister);
894 void divDouble(FPRegisterID src, FPRegisterID dest)
896 m_assembler.vdiv(dest, dest, src);
899 void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
901 m_assembler.vdiv(dest, op1, op2);
904 void subDouble(FPRegisterID src, FPRegisterID dest)
906 m_assembler.vsub(dest, dest, src);
909 void subDouble(Address src, FPRegisterID dest)
911 loadDouble(src, fpTempRegister);
912 subDouble(fpTempRegister, dest);
915 void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
917 m_assembler.vsub(dest, op1, op2);
920 void mulDouble(FPRegisterID src, FPRegisterID dest)
922 m_assembler.vmul(dest, dest, src);
925 void mulDouble(Address src, FPRegisterID dest)
927 loadDouble(src, fpTempRegister);
928 mulDouble(fpTempRegister, dest);
931 void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
933 m_assembler.vmul(dest, op1, op2);
936 void sqrtDouble(FPRegisterID src, FPRegisterID dest)
938 m_assembler.vsqrt(dest, src);
941 void absDouble(FPRegisterID src, FPRegisterID dest)
943 m_assembler.vabs(dest, src);
946 void negateDouble(FPRegisterID src, FPRegisterID dest)
948 m_assembler.vneg(dest, src);
951 void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
953 m_assembler.vmov(fpTempRegister, src, src);
954 m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
957 void convertInt32ToDouble(Address address, FPRegisterID dest)
959 // Fixme: load directly into the fpr!
960 load32(address, dataTempRegister);
961 m_assembler.vmov(fpTempRegister, dataTempRegister, dataTempRegister);
962 m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
965 void convertInt32ToDouble(AbsoluteAddress address, FPRegisterID dest)
967 // Fixme: load directly into the fpr!
968 load32(address.m_ptr, dataTempRegister);
969 m_assembler.vmov(fpTempRegister, dataTempRegister, dataTempRegister);
970 m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
973 void convertFloatToDouble(FPRegisterID src, FPRegisterID dst)
975 m_assembler.vcvtds(dst, ARMRegisters::asSingle(src));
978 void convertDoubleToFloat(FPRegisterID src, FPRegisterID dst)
980 m_assembler.vcvtsd(ARMRegisters::asSingle(dst), src);
983 Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
985 m_assembler.vcmp(left, right);
988 if (cond == DoubleNotEqual) {
989 // ConditionNE jumps if NotEqual *or* unordered - force the unordered cases not to jump.
990 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
991 Jump result = makeBranch(ARMv7Assembler::ConditionNE);
992 unordered.link(this);
995 if (cond == DoubleEqualOrUnordered) {
996 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
997 Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
998 unordered.link(this);
999 // We get here if either unordered or equal.
1000 Jump result = jump();
1001 notEqual.link(this);
1004 return makeBranch(cond);
1007 enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful };
1008 Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
1010 // Convert into dest.
1011 m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1012 m_assembler.vmov(dest, fpTempRegisterAsSingle());
1014 // Calculate 2x dest. If the value potentially underflowed, it will have
1015 // clamped to 0x80000000, so 2x dest is zero in this case. In the case of
1016 // overflow the result will be equal to -2.
1017 Jump underflow = branchAdd32(Zero, dest, dest, dataTempRegister);
1018 Jump noOverflow = branch32(NotEqual, dataTempRegister, TrustedImm32(-2));
1020 // For BranchIfTruncateSuccessful, we branch if 'noOverflow' jumps.
1021 underflow.link(this);
1022 if (branchType == BranchIfTruncateSuccessful)
1025 // We'll reach the current point in the code on failure, so plant a
1026 // jump here & link the success case.
1027 Jump failure = jump();
1028 noOverflow.link(this);
1032 Jump branchTruncateDoubleToUint32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
1034 m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1035 m_assembler.vmov(dest, fpTempRegisterAsSingle());
1037 Jump overflow = branch32(Equal, dest, TrustedImm32(0x7fffffff));
1038 Jump success = branch32(GreaterThanOrEqual, dest, TrustedImm32(0));
1039 overflow.link(this);
1041 if (branchType == BranchIfTruncateSuccessful)
1044 Jump failure = jump();
1049 // Result is undefined if the value is outside of the integer range.
1050 void truncateDoubleToInt32(FPRegisterID src, RegisterID dest)
1052 m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1053 m_assembler.vmov(dest, fpTempRegisterAsSingle());
1056 void truncateDoubleToUint32(FPRegisterID src, RegisterID dest)
1058 m_assembler.vcvt_floatingPointToUnsigned(fpTempRegisterAsSingle(), src);
1059 m_assembler.vmov(dest, fpTempRegisterAsSingle());
1062 // Convert 'src' to an integer, and places the resulting 'dest'.
1063 // If the result is not representable as a 32 bit value, branch.
1064 // May also branch for some values that are representable in 32 bits
1065 // (specifically, in this case, 0).
1066 void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID)
1068 m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1069 m_assembler.vmov(dest, fpTempRegisterAsSingle());
1071 // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
1072 m_assembler.vcvt_signedToFloatingPoint(fpTempRegister, fpTempRegisterAsSingle());
1073 failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, fpTempRegister));
1075 // If the result is zero, it might have been -0.0, and the double comparison won't catch this!
1076 failureCases.append(branchTest32(Zero, dest));
1079 Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID)
1081 m_assembler.vcmpz(reg);
1083 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1084 Jump result = makeBranch(ARMv7Assembler::ConditionNE);
1085 unordered.link(this);
1089 Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID)
1091 m_assembler.vcmpz(reg);
1093 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1094 Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
1095 unordered.link(this);
1096 // We get here if either unordered or equal.
1097 Jump result = jump();
1098 notEqual.link(this);
1102 // Stack manipulation operations:
1104 // The ABI is assumed to provide a stack abstraction to memory,
1105 // containing machine word sized units of data. Push and pop
1106 // operations add and remove a single register sized unit of data
1107 // to or from the stack. Peek and poke operations read or write
1108 // values on the stack, without moving the current stack position.
1110 void pop(RegisterID dest)
1112 // store postindexed with writeback
1113 m_assembler.ldr(dest, ARMRegisters::sp, sizeof(void*), false, true);
1116 void push(RegisterID src)
1118 // store preindexed with writeback
1119 m_assembler.str(src, ARMRegisters::sp, -sizeof(void*), true, true);
1122 void push(Address address)
1124 load32(address, dataTempRegister);
1125 push(dataTempRegister);
1128 void push(TrustedImm32 imm)
1130 move(imm, dataTempRegister);
1131 push(dataTempRegister);
1134 // Register move operations:
1136 // Move values in registers.
1138 void move(TrustedImm32 imm, RegisterID dest)
1140 uint32_t value = imm.m_value;
1142 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(value);
1144 if (armImm.isValid())
1145 m_assembler.mov(dest, armImm);
1146 else if ((armImm = ARMThumbImmediate::makeEncodedImm(~value)).isValid())
1147 m_assembler.mvn(dest, armImm);
1149 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(value));
1150 if (value & 0xffff0000)
1151 m_assembler.movt(dest, ARMThumbImmediate::makeUInt16(value >> 16));
1155 void move(RegisterID src, RegisterID dest)
1158 m_assembler.mov(dest, src);
1161 void move(TrustedImmPtr imm, RegisterID dest)
1163 move(TrustedImm32(imm), dest);
1166 void swap(RegisterID reg1, RegisterID reg2)
1168 move(reg1, dataTempRegister);
1170 move(dataTempRegister, reg2);
1173 void signExtend32ToPtr(RegisterID src, RegisterID dest)
1178 void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
1183 // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc.
1184 static RelationalCondition invert(RelationalCondition cond)
1186 return static_cast<RelationalCondition>(cond ^ 1);
1194 static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
1196 ARMv7Assembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation());
1199 static ptrdiff_t maxJumpReplacementSize()
1201 return ARMv7Assembler::maxJumpReplacementSize();
1204 // Forwards / external control flow operations:
1206 // This set of jump and conditional branch operations return a Jump
1207 // object which may linked at a later point, allow forwards jump,
1208 // or jumps that will require external linkage (after the code has been
1211 // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
1212 // respecitvely, for unsigned comparisons the names b, a, be, and ae are
1213 // used (representing the names 'below' and 'above').
1215 // Operands to the comparision are provided in the expected order, e.g.
1216 // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
1217 // treated as a signed 32bit value, is less than or equal to 5.
1219 // jz and jnz test whether the first operand is equal to zero, and take
1220 // an optional second operand of a mask under which to perform the test.
1223 // Should we be using TEQ for equal/not-equal?
1224 void compare32(RegisterID left, TrustedImm32 right)
1226 int32_t imm = right.m_value;
1228 m_assembler.tst(left, left);
1230 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
1231 if (armImm.isValid())
1232 m_assembler.cmp(left, armImm);
1233 else if ((armImm = ARMThumbImmediate::makeEncodedImm(-imm)).isValid())
1234 m_assembler.cmn(left, armImm);
1236 move(TrustedImm32(imm), dataTempRegister);
1237 m_assembler.cmp(left, dataTempRegister);
1242 void test32(RegisterID reg, TrustedImm32 mask)
1244 int32_t imm = mask.m_value;
1247 m_assembler.tst(reg, reg);
1249 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
1250 if (armImm.isValid())
1251 m_assembler.tst(reg, armImm);
1253 move(mask, dataTempRegister);
1254 m_assembler.tst(reg, dataTempRegister);
1260 Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
1262 m_assembler.cmp(left, right);
1263 return Jump(makeBranch(cond));
1266 Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1268 compare32(left, right);
1269 return Jump(makeBranch(cond));
1272 Jump branch32(RelationalCondition cond, RegisterID left, Address right)
1274 load32(right, dataTempRegister);
1275 return branch32(cond, left, dataTempRegister);
1278 Jump branch32(RelationalCondition cond, Address left, RegisterID right)
1280 load32(left, dataTempRegister);
1281 return branch32(cond, dataTempRegister, right);
1284 Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
1286 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1287 load32(left, addressTempRegister);
1288 return branch32(cond, addressTempRegister, right);
1291 Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1293 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1294 load32(left, addressTempRegister);
1295 return branch32(cond, addressTempRegister, right);
1298 Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1300 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1301 load32WithUnalignedHalfWords(left, addressTempRegister);
1302 return branch32(cond, addressTempRegister, right);
1305 Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
1307 load32(left.m_ptr, dataTempRegister);
1308 return branch32(cond, dataTempRegister, right);
1311 Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
1313 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1314 load32(left.m_ptr, addressTempRegister);
1315 return branch32(cond, addressTempRegister, right);
1318 Jump branch8(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1320 compare32(left, right);
1321 return Jump(makeBranch(cond));
1324 Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
1326 ASSERT(!(0xffffff00 & right.m_value));
1327 // use addressTempRegister incase the branch8 we call uses dataTempRegister. :-/
1328 load8(left, addressTempRegister);
1329 return branch8(cond, addressTempRegister, right);
1332 Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1334 ASSERT(!(0xffffff00 & right.m_value));
1335 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1336 load8(left, addressTempRegister);
1337 return branch32(cond, addressTempRegister, right);
1340 Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
1342 m_assembler.tst(reg, mask);
1343 return Jump(makeBranch(cond));
1346 Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1349 return Jump(makeBranch(cond));
1352 Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1354 // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
1355 load32(address, addressTempRegister);
1356 return branchTest32(cond, addressTempRegister, mask);
1359 Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
1361 // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
1362 load32(address, addressTempRegister);
1363 return branchTest32(cond, addressTempRegister, mask);
1366 Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1368 // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
1369 load8(address, addressTempRegister);
1370 return branchTest32(cond, addressTempRegister, mask);
1373 Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
1375 // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
1376 move(TrustedImmPtr(address.m_ptr), addressTempRegister);
1377 load8(Address(addressTempRegister), addressTempRegister);
1378 return branchTest32(cond, addressTempRegister, mask);
1381 void jump(RegisterID target)
1383 m_assembler.bx(target);
1386 // Address is a memory location containing the address to jump to
1387 void jump(Address address)
1389 load32(address, dataTempRegister);
1390 m_assembler.bx(dataTempRegister);
1393 void jump(AbsoluteAddress address)
1395 move(TrustedImmPtr(address.m_ptr), dataTempRegister);
1396 load32(Address(dataTempRegister), dataTempRegister);
1397 m_assembler.bx(dataTempRegister);
1401 // Arithmetic control flow operations:
1403 // This set of conditional branch operations branch based
1404 // on the result of an arithmetic operation. The operation
1405 // is performed as normal, storing the result.
1407 // * jz operations branch if the result is zero.
1408 // * jo operations branch if the (signed) arithmetic
1409 // operation caused an overflow to occur.
1411 Jump branchAdd32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
1413 m_assembler.add_S(dest, op1, op2);
1414 return Jump(makeBranch(cond));
1417 Jump branchAdd32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
1419 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1420 if (armImm.isValid())
1421 m_assembler.add_S(dest, op1, armImm);
1423 move(imm, dataTempRegister);
1424 m_assembler.add_S(dest, op1, dataTempRegister);
1426 return Jump(makeBranch(cond));
1429 Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
1431 return branchAdd32(cond, dest, src, dest);
1434 Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1436 return branchAdd32(cond, dest, imm, dest);
1439 Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest)
1441 // Move the high bits of the address into addressTempRegister,
1442 // and load the value into dataTempRegister.
1443 move(TrustedImmPtr(dest.m_ptr), addressTempRegister);
1444 m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
1447 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1448 if (armImm.isValid())
1449 m_assembler.add_S(dataTempRegister, dataTempRegister, armImm);
1451 // If the operand does not fit into an immediate then load it temporarily
1452 // into addressTempRegister; since we're overwriting addressTempRegister
1453 // we'll need to reload it with the high bits of the address afterwards.
1454 move(imm, addressTempRegister);
1455 m_assembler.add_S(dataTempRegister, dataTempRegister, addressTempRegister);
1456 move(TrustedImmPtr(dest.m_ptr), addressTempRegister);
1459 // Store the result.
1460 m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
1462 return Jump(makeBranch(cond));
1465 Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
1467 m_assembler.smull(dest, dataTempRegister, src1, src2);
1469 if (cond == Overflow) {
1470 m_assembler.asr(addressTempRegister, dest, 31);
1471 return branch32(NotEqual, addressTempRegister, dataTempRegister);
1474 return branchTest32(cond, dest);
1477 Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
1479 return branchMul32(cond, src, dest, dest);
1482 Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
1484 move(imm, dataTempRegister);
1485 return branchMul32(cond, dataTempRegister, src, dest);
1488 Jump branchNeg32(ResultCondition cond, RegisterID srcDest)
1490 ARMThumbImmediate zero = ARMThumbImmediate::makeUInt12(0);
1491 m_assembler.sub_S(srcDest, zero, srcDest);
1492 return Jump(makeBranch(cond));
1495 Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
1497 m_assembler.orr_S(dest, dest, src);
1498 return Jump(makeBranch(cond));
1501 Jump branchSub32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
1503 m_assembler.sub_S(dest, op1, op2);
1504 return Jump(makeBranch(cond));
1507 Jump branchSub32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
1509 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1510 if (armImm.isValid())
1511 m_assembler.sub_S(dest, op1, armImm);
1513 move(imm, dataTempRegister);
1514 m_assembler.sub_S(dest, op1, dataTempRegister);
1516 return Jump(makeBranch(cond));
1519 Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
1521 return branchSub32(cond, dest, src, dest);
1524 Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1526 return branchSub32(cond, dest, imm, dest);
1529 void relativeTableJump(RegisterID index, int scale)
1531 ASSERT(scale >= 0 && scale <= 31);
1533 // dataTempRegister will point after the jump if index register contains zero
1534 move(ARMRegisters::pc, dataTempRegister);
1535 m_assembler.add(dataTempRegister, dataTempRegister, ARMThumbImmediate::makeEncodedImm(9));
1537 ShiftTypeAndAmount shift(SRType_LSL, scale);
1538 m_assembler.add(dataTempRegister, dataTempRegister, index, shift);
1539 jump(dataTempRegister);
1542 // Miscellaneous operations:
1544 void breakpoint(uint8_t imm = 0)
1546 m_assembler.bkpt(imm);
1549 ALWAYS_INLINE Call nearCall()
1551 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1552 return Call(m_assembler.blx(dataTempRegister), Call::LinkableNear);
1555 ALWAYS_INLINE Call call()
1557 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1558 return Call(m_assembler.blx(dataTempRegister), Call::Linkable);
1561 ALWAYS_INLINE Call call(RegisterID target)
1563 return Call(m_assembler.blx(target), Call::None);
1566 ALWAYS_INLINE Call call(Address address)
1568 load32(address, dataTempRegister);
1569 return Call(m_assembler.blx(dataTempRegister), Call::None);
1572 ALWAYS_INLINE void ret()
1574 m_assembler.bx(linkRegister);
1577 void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
1579 m_assembler.cmp(left, right);
1580 m_assembler.it(armV7Condition(cond), false);
1581 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1582 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1585 void compare32(RelationalCondition cond, Address left, RegisterID right, RegisterID dest)
1587 load32(left, dataTempRegister);
1588 compare32(cond, dataTempRegister, right, dest);
1591 void compare8(RelationalCondition cond, Address left, TrustedImm32 right, RegisterID dest)
1593 load8(left, addressTempRegister);
1594 compare32(cond, addressTempRegister, right, dest);
1597 void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
1599 compare32(left, right);
1600 m_assembler.it(armV7Condition(cond), false);
1601 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1602 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1606 // The mask should be optional... paerhaps the argument order should be
1607 // dest-src, operations always have a dest? ... possibly not true, considering
1608 // asm ops like test, or pseudo ops like pop().
1609 void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1611 load32(address, dataTempRegister);
1612 test32(dataTempRegister, mask);
1613 m_assembler.it(armV7Condition(cond), false);
1614 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1615 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1618 void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1620 load8(address, dataTempRegister);
1621 test32(dataTempRegister, mask);
1622 m_assembler.it(armV7Condition(cond), false);
1623 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1624 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1627 ALWAYS_INLINE DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dst)
1629 moveFixedWidthEncoding(imm, dst);
1630 return DataLabel32(this);
1633 ALWAYS_INLINE DataLabelPtr moveWithPatch(TrustedImmPtr imm, RegisterID dst)
1635 moveFixedWidthEncoding(TrustedImm32(imm), dst);
1636 return DataLabelPtr(this);
1639 ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1641 dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1642 return branch32(cond, left, dataTempRegister);
1645 ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1647 load32(left, addressTempRegister);
1648 dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1649 return branch32(cond, addressTempRegister, dataTempRegister);
1652 PatchableJump patchableBranchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1654 m_makeJumpPatchable = true;
1655 Jump result = branchPtrWithPatch(cond, left, dataLabel, initialRightValue);
1656 m_makeJumpPatchable = false;
1657 return PatchableJump(result);
1660 PatchableJump patchableJump()
1662 m_makeJumpPatchable = true;
1663 Jump result = jump();
1664 m_makeJumpPatchable = false;
1665 return PatchableJump(result);
1668 ALWAYS_INLINE DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
1670 DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister);
1671 store32(dataTempRegister, address);
1674 ALWAYS_INLINE DataLabelPtr storePtrWithPatch(ImplicitAddress address) { return storePtrWithPatch(TrustedImmPtr(0), address); }
1677 ALWAYS_INLINE Call tailRecursiveCall()
1679 // Like a normal call, but don't link.
1680 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1681 return Call(m_assembler.bx(dataTempRegister), Call::Linkable);
1684 ALWAYS_INLINE Call makeTailRecursiveCall(Jump oldJump)
1687 return tailRecursiveCall();
1691 int executableOffsetFor(int location)
1693 return m_assembler.executableOffsetFor(location);
1696 static FunctionPtr readCallTarget(CodeLocationCall call)
1698 return FunctionPtr(reinterpret_cast<void(*)()>(ARMv7Assembler::readCallTarget(call.dataLocation())));
1702 ALWAYS_INLINE Jump jump()
1704 m_assembler.label(); // Force nop-padding if we're in the middle of a watchpoint.
1705 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1706 return Jump(m_assembler.bx(dataTempRegister), m_makeJumpPatchable ? ARMv7Assembler::JumpNoConditionFixedSize : ARMv7Assembler::JumpNoCondition);
1709 ALWAYS_INLINE Jump makeBranch(ARMv7Assembler::Condition cond)
1711 m_assembler.label(); // Force nop-padding if we're in the middle of a watchpoint.
1712 m_assembler.it(cond, true, true);
1713 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1714 return Jump(m_assembler.bx(dataTempRegister), m_makeJumpPatchable ? ARMv7Assembler::JumpConditionFixedSize : ARMv7Assembler::JumpCondition, cond);
1716 ALWAYS_INLINE Jump makeBranch(RelationalCondition cond) { return makeBranch(armV7Condition(cond)); }
1717 ALWAYS_INLINE Jump makeBranch(ResultCondition cond) { return makeBranch(armV7Condition(cond)); }
1718 ALWAYS_INLINE Jump makeBranch(DoubleCondition cond) { return makeBranch(armV7Condition(cond)); }
1720 ArmAddress setupArmAddress(BaseIndex address)
1722 if (address.offset) {
1723 ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
1725 m_assembler.add(addressTempRegister, address.base, imm);
1727 move(TrustedImm32(address.offset), addressTempRegister);
1728 m_assembler.add(addressTempRegister, addressTempRegister, address.base);
1731 return ArmAddress(addressTempRegister, address.index, address.scale);
1733 return ArmAddress(address.base, address.index, address.scale);
1736 ArmAddress setupArmAddress(Address address)
1738 if ((address.offset >= -0xff) && (address.offset <= 0xfff))
1739 return ArmAddress(address.base, address.offset);
1741 move(TrustedImm32(address.offset), addressTempRegister);
1742 return ArmAddress(address.base, addressTempRegister);
1745 ArmAddress setupArmAddress(ImplicitAddress address)
1747 if ((address.offset >= -0xff) && (address.offset <= 0xfff))
1748 return ArmAddress(address.base, address.offset);
1750 move(TrustedImm32(address.offset), addressTempRegister);
1751 return ArmAddress(address.base, addressTempRegister);
1754 RegisterID makeBaseIndexBase(BaseIndex address)
1756 if (!address.offset)
1757 return address.base;
1759 ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
1761 m_assembler.add(addressTempRegister, address.base, imm);
1763 move(TrustedImm32(address.offset), addressTempRegister);
1764 m_assembler.add(addressTempRegister, addressTempRegister, address.base);
1767 return addressTempRegister;
1770 void moveFixedWidthEncoding(TrustedImm32 imm, RegisterID dst)
1772 uint32_t value = imm.m_value;
1773 m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff));
1774 m_assembler.movt(dst, ARMThumbImmediate::makeUInt16(value >> 16));
1777 ARMv7Assembler::Condition armV7Condition(RelationalCondition cond)
1779 return static_cast<ARMv7Assembler::Condition>(cond);
1782 ARMv7Assembler::Condition armV7Condition(ResultCondition cond)
1784 return static_cast<ARMv7Assembler::Condition>(cond);
1787 ARMv7Assembler::Condition armV7Condition(DoubleCondition cond)
1789 return static_cast<ARMv7Assembler::Condition>(cond);
1793 friend class LinkBuffer;
1794 friend class RepatchBuffer;
1796 static void linkCall(void* code, Call call, FunctionPtr function)
1798 ARMv7Assembler::linkCall(code, call.m_label, function.value());
1801 static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
1803 ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
1806 static void repatchCall(CodeLocationCall call, FunctionPtr destination)
1808 ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
1811 bool m_makeJumpPatchable;
1816 #endif // ENABLE(ASSEMBLER)
1818 #endif // MacroAssemblerARMv7_h