2 * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
3 * Copyright (C) 2010 University of Szeged
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #ifndef MacroAssemblerARMv7_h
28 #define MacroAssemblerARMv7_h
32 #include "ARMv7Assembler.h"
33 #include "AbstractMacroAssembler.h"
37 class MacroAssemblerARMv7
: public AbstractMacroAssembler
<ARMv7Assembler
> {
38 // FIXME: switch dataTempRegister & addressTempRegister, or possibly use r7?
39 // - dTR is likely used more than aTR, and we'll get better instruction
40 // encoding if it's in the low 8 registers.
41 static const RegisterID dataTempRegister
= ARMRegisters::ip
;
42 static const RegisterID addressTempRegister
= ARMRegisters::r3
;
44 static const ARMRegisters::FPDoubleRegisterID fpTempRegister
= ARMRegisters::d7
;
45 inline ARMRegisters::FPSingleRegisterID
fpTempRegisterAsSingle() { return ARMRegisters::asSingle(fpTempRegister
); }
48 typedef ARMv7Assembler::LinkRecord LinkRecord
;
49 typedef ARMv7Assembler::JumpType JumpType
;
50 typedef ARMv7Assembler::JumpLinkType JumpLinkType
;
51 // Magic number is the biggest useful offset we can get on ARMv7 with
52 // a LDR_imm_T2 encoding
53 static const int MaximumCompactPtrAlignedAddressOffset
= 124;
56 : m_inUninterruptedSequence(false)
60 void beginUninterruptedSequence() { m_inUninterruptedSequence
= true; }
61 void endUninterruptedSequence() { m_inUninterruptedSequence
= false; }
62 Vector
<LinkRecord
>& jumpsToLink() { return m_assembler
.jumpsToLink(); }
63 void* unlinkedCode() { return m_assembler
.unlinkedCode(); }
64 bool canCompact(JumpType jumpType
) { return m_assembler
.canCompact(jumpType
); }
65 JumpLinkType
computeJumpType(JumpType jumpType
, const uint8_t* from
, const uint8_t* to
) { return m_assembler
.computeJumpType(jumpType
, from
, to
); }
66 JumpLinkType
computeJumpType(LinkRecord
& record
, const uint8_t* from
, const uint8_t* to
) { return m_assembler
.computeJumpType(record
, from
, to
); }
67 void recordLinkOffsets(int32_t regionStart
, int32_t regionEnd
, int32_t offset
) {return m_assembler
.recordLinkOffsets(regionStart
, regionEnd
, offset
); }
68 int jumpSizeDelta(JumpType jumpType
, JumpLinkType jumpLinkType
) { return m_assembler
.jumpSizeDelta(jumpType
, jumpLinkType
); }
69 void link(LinkRecord
& record
, uint8_t* from
, uint8_t* to
) { return m_assembler
.link(record
, from
, to
); }
85 explicit ArmAddress(RegisterID base
, int32_t offset
= 0)
92 explicit ArmAddress(RegisterID base
, RegisterID index
, Scale scale
= TimesOne
)
102 typedef ARMRegisters::FPDoubleRegisterID FPRegisterID
;
104 static const Scale ScalePtr
= TimesFour
;
106 enum RelationalCondition
{
107 Equal
= ARMv7Assembler::ConditionEQ
,
108 NotEqual
= ARMv7Assembler::ConditionNE
,
109 Above
= ARMv7Assembler::ConditionHI
,
110 AboveOrEqual
= ARMv7Assembler::ConditionHS
,
111 Below
= ARMv7Assembler::ConditionLO
,
112 BelowOrEqual
= ARMv7Assembler::ConditionLS
,
113 GreaterThan
= ARMv7Assembler::ConditionGT
,
114 GreaterThanOrEqual
= ARMv7Assembler::ConditionGE
,
115 LessThan
= ARMv7Assembler::ConditionLT
,
116 LessThanOrEqual
= ARMv7Assembler::ConditionLE
119 enum ResultCondition
{
120 Overflow
= ARMv7Assembler::ConditionVS
,
121 Signed
= ARMv7Assembler::ConditionMI
,
122 Zero
= ARMv7Assembler::ConditionEQ
,
123 NonZero
= ARMv7Assembler::ConditionNE
126 enum DoubleCondition
{
127 // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
128 DoubleEqual
= ARMv7Assembler::ConditionEQ
,
129 DoubleNotEqual
= ARMv7Assembler::ConditionVC
, // Not the right flag! check for this & handle differently.
130 DoubleGreaterThan
= ARMv7Assembler::ConditionGT
,
131 DoubleGreaterThanOrEqual
= ARMv7Assembler::ConditionGE
,
132 DoubleLessThan
= ARMv7Assembler::ConditionLO
,
133 DoubleLessThanOrEqual
= ARMv7Assembler::ConditionLS
,
134 // If either operand is NaN, these conditions always evaluate to true.
135 DoubleEqualOrUnordered
= ARMv7Assembler::ConditionVS
, // Not the right flag! check for this & handle differently.
136 DoubleNotEqualOrUnordered
= ARMv7Assembler::ConditionNE
,
137 DoubleGreaterThanOrUnordered
= ARMv7Assembler::ConditionHI
,
138 DoubleGreaterThanOrEqualOrUnordered
= ARMv7Assembler::ConditionHS
,
139 DoubleLessThanOrUnordered
= ARMv7Assembler::ConditionLT
,
140 DoubleLessThanOrEqualOrUnordered
= ARMv7Assembler::ConditionLE
,
143 static const RegisterID stackPointerRegister
= ARMRegisters::sp
;
144 static const RegisterID linkRegister
= ARMRegisters::lr
;
146 // Integer arithmetic operations:
148 // Operations are typically two operand - operation(source, srcDst)
149 // For many operations the source may be an TrustedImm32, the srcDst operand
150 // may often be a memory location (explictly described using an Address
153 void add32(RegisterID src
, RegisterID dest
)
155 m_assembler
.add(dest
, dest
, src
);
158 void add32(TrustedImm32 imm
, RegisterID dest
)
160 add32(imm
, dest
, dest
);
163 void add32(TrustedImm32 imm
, RegisterID src
, RegisterID dest
)
165 ARMThumbImmediate armImm
= ARMThumbImmediate::makeUInt12OrEncodedImm(imm
.m_value
);
166 if (armImm
.isValid())
167 m_assembler
.add(dest
, src
, armImm
);
169 move(imm
, dataTempRegister
);
170 m_assembler
.add(dest
, src
, dataTempRegister
);
174 void add32(TrustedImm32 imm
, Address address
)
176 load32(address
, dataTempRegister
);
178 ARMThumbImmediate armImm
= ARMThumbImmediate::makeUInt12OrEncodedImm(imm
.m_value
);
179 if (armImm
.isValid())
180 m_assembler
.add(dataTempRegister
, dataTempRegister
, armImm
);
182 // Hrrrm, since dataTempRegister holds the data loaded,
183 // use addressTempRegister to hold the immediate.
184 move(imm
, addressTempRegister
);
185 m_assembler
.add(dataTempRegister
, dataTempRegister
, addressTempRegister
);
188 store32(dataTempRegister
, address
);
191 void add32(Address src
, RegisterID dest
)
193 load32(src
, dataTempRegister
);
194 add32(dataTempRegister
, dest
);
197 void add32(TrustedImm32 imm
, AbsoluteAddress address
)
199 load32(address
.m_ptr
, dataTempRegister
);
201 ARMThumbImmediate armImm
= ARMThumbImmediate::makeUInt12OrEncodedImm(imm
.m_value
);
202 if (armImm
.isValid())
203 m_assembler
.add(dataTempRegister
, dataTempRegister
, armImm
);
205 // Hrrrm, since dataTempRegister holds the data loaded,
206 // use addressTempRegister to hold the immediate.
207 move(imm
, addressTempRegister
);
208 m_assembler
.add(dataTempRegister
, dataTempRegister
, addressTempRegister
);
211 store32(dataTempRegister
, address
.m_ptr
);
214 void and32(RegisterID src
, RegisterID dest
)
216 m_assembler
.ARM_and(dest
, dest
, src
);
219 void and32(TrustedImm32 imm
, RegisterID dest
)
221 ARMThumbImmediate armImm
= ARMThumbImmediate::makeEncodedImm(imm
.m_value
);
222 if (armImm
.isValid())
223 m_assembler
.ARM_and(dest
, dest
, armImm
);
225 move(imm
, dataTempRegister
);
226 m_assembler
.ARM_and(dest
, dest
, dataTempRegister
);
230 void countLeadingZeros32(RegisterID src
, RegisterID dest
)
232 m_assembler
.clz(dest
, src
);
235 void lshift32(RegisterID shift_amount
, RegisterID dest
)
237 // Clamp the shift to the range 0..31
238 ARMThumbImmediate armImm
= ARMThumbImmediate::makeEncodedImm(0x1f);
239 ASSERT(armImm
.isValid());
240 m_assembler
.ARM_and(dataTempRegister
, shift_amount
, armImm
);
242 m_assembler
.lsl(dest
, dest
, dataTempRegister
);
245 void lshift32(TrustedImm32 imm
, RegisterID dest
)
247 m_assembler
.lsl(dest
, dest
, imm
.m_value
& 0x1f);
250 void mul32(RegisterID src
, RegisterID dest
)
252 m_assembler
.smull(dest
, dataTempRegister
, dest
, src
);
255 void mul32(TrustedImm32 imm
, RegisterID src
, RegisterID dest
)
257 move(imm
, dataTempRegister
);
258 m_assembler
.smull(dest
, dataTempRegister
, src
, dataTempRegister
);
261 void neg32(RegisterID srcDest
)
263 m_assembler
.neg(srcDest
, srcDest
);
266 void not32(RegisterID srcDest
)
268 m_assembler
.mvn(srcDest
, srcDest
);
271 void or32(RegisterID src
, RegisterID dest
)
273 m_assembler
.orr(dest
, dest
, src
);
276 void or32(TrustedImm32 imm
, RegisterID dest
)
278 ARMThumbImmediate armImm
= ARMThumbImmediate::makeEncodedImm(imm
.m_value
);
279 if (armImm
.isValid())
280 m_assembler
.orr(dest
, dest
, armImm
);
282 move(imm
, dataTempRegister
);
283 m_assembler
.orr(dest
, dest
, dataTempRegister
);
287 void rshift32(RegisterID shift_amount
, RegisterID dest
)
289 // Clamp the shift to the range 0..31
290 ARMThumbImmediate armImm
= ARMThumbImmediate::makeEncodedImm(0x1f);
291 ASSERT(armImm
.isValid());
292 m_assembler
.ARM_and(dataTempRegister
, shift_amount
, armImm
);
294 m_assembler
.asr(dest
, dest
, dataTempRegister
);
297 void rshift32(TrustedImm32 imm
, RegisterID dest
)
299 m_assembler
.asr(dest
, dest
, imm
.m_value
& 0x1f);
302 void urshift32(RegisterID shift_amount
, RegisterID dest
)
304 // Clamp the shift to the range 0..31
305 ARMThumbImmediate armImm
= ARMThumbImmediate::makeEncodedImm(0x1f);
306 ASSERT(armImm
.isValid());
307 m_assembler
.ARM_and(dataTempRegister
, shift_amount
, armImm
);
309 m_assembler
.lsr(dest
, dest
, dataTempRegister
);
312 void urshift32(TrustedImm32 imm
, RegisterID dest
)
314 m_assembler
.lsr(dest
, dest
, imm
.m_value
& 0x1f);
317 void sub32(RegisterID src
, RegisterID dest
)
319 m_assembler
.sub(dest
, dest
, src
);
322 void sub32(TrustedImm32 imm
, RegisterID dest
)
324 ARMThumbImmediate armImm
= ARMThumbImmediate::makeUInt12OrEncodedImm(imm
.m_value
);
325 if (armImm
.isValid())
326 m_assembler
.sub(dest
, dest
, armImm
);
328 move(imm
, dataTempRegister
);
329 m_assembler
.sub(dest
, dest
, dataTempRegister
);
333 void sub32(TrustedImm32 imm
, Address address
)
335 load32(address
, dataTempRegister
);
337 ARMThumbImmediate armImm
= ARMThumbImmediate::makeUInt12OrEncodedImm(imm
.m_value
);
338 if (armImm
.isValid())
339 m_assembler
.sub(dataTempRegister
, dataTempRegister
, armImm
);
341 // Hrrrm, since dataTempRegister holds the data loaded,
342 // use addressTempRegister to hold the immediate.
343 move(imm
, addressTempRegister
);
344 m_assembler
.sub(dataTempRegister
, dataTempRegister
, addressTempRegister
);
347 store32(dataTempRegister
, address
);
350 void sub32(Address src
, RegisterID dest
)
352 load32(src
, dataTempRegister
);
353 sub32(dataTempRegister
, dest
);
356 void sub32(TrustedImm32 imm
, AbsoluteAddress address
)
358 load32(address
.m_ptr
, dataTempRegister
);
360 ARMThumbImmediate armImm
= ARMThumbImmediate::makeUInt12OrEncodedImm(imm
.m_value
);
361 if (armImm
.isValid())
362 m_assembler
.sub(dataTempRegister
, dataTempRegister
, armImm
);
364 // Hrrrm, since dataTempRegister holds the data loaded,
365 // use addressTempRegister to hold the immediate.
366 move(imm
, addressTempRegister
);
367 m_assembler
.sub(dataTempRegister
, dataTempRegister
, addressTempRegister
);
370 store32(dataTempRegister
, address
.m_ptr
);
373 void xor32(RegisterID src
, RegisterID dest
)
375 m_assembler
.eor(dest
, dest
, src
);
378 void xor32(TrustedImm32 imm
, RegisterID dest
)
380 ARMThumbImmediate armImm
= ARMThumbImmediate::makeEncodedImm(imm
.m_value
);
381 if (armImm
.isValid())
382 m_assembler
.eor(dest
, dest
, armImm
);
384 move(imm
, dataTempRegister
);
385 m_assembler
.eor(dest
, dest
, dataTempRegister
);
390 // Memory access operations:
392 // Loads are of the form load(address, destination) and stores of the form
393 // store(source, address). The source for a store may be an TrustedImm32. Address
394 // operand objects to loads and store will be implicitly constructed if a
395 // register is passed.
398 void load32(ArmAddress address
, RegisterID dest
)
400 if (address
.type
== ArmAddress::HasIndex
)
401 m_assembler
.ldr(dest
, address
.base
, address
.u
.index
, address
.u
.scale
);
402 else if (address
.u
.offset
>= 0) {
403 ARMThumbImmediate armImm
= ARMThumbImmediate::makeUInt12(address
.u
.offset
);
404 ASSERT(armImm
.isValid());
405 m_assembler
.ldr(dest
, address
.base
, armImm
);
407 ASSERT(address
.u
.offset
>= -255);
408 m_assembler
.ldr(dest
, address
.base
, address
.u
.offset
, true, false);
412 void load16(ArmAddress address
, RegisterID dest
)
414 if (address
.type
== ArmAddress::HasIndex
)
415 m_assembler
.ldrh(dest
, address
.base
, address
.u
.index
, address
.u
.scale
);
416 else if (address
.u
.offset
>= 0) {
417 ARMThumbImmediate armImm
= ARMThumbImmediate::makeUInt12(address
.u
.offset
);
418 ASSERT(armImm
.isValid());
419 m_assembler
.ldrh(dest
, address
.base
, armImm
);
421 ASSERT(address
.u
.offset
>= -255);
422 m_assembler
.ldrh(dest
, address
.base
, address
.u
.offset
, true, false);
426 void load8(ArmAddress address
, RegisterID dest
)
428 if (address
.type
== ArmAddress::HasIndex
)
429 m_assembler
.ldrb(dest
, address
.base
, address
.u
.index
, address
.u
.scale
);
430 else if (address
.u
.offset
>= 0) {
431 ARMThumbImmediate armImm
= ARMThumbImmediate::makeUInt12(address
.u
.offset
);
432 ASSERT(armImm
.isValid());
433 m_assembler
.ldrb(dest
, address
.base
, armImm
);
435 ASSERT(address
.u
.offset
>= -255);
436 m_assembler
.ldrb(dest
, address
.base
, address
.u
.offset
, true, false);
440 void store32(RegisterID src
, ArmAddress address
)
442 if (address
.type
== ArmAddress::HasIndex
)
443 m_assembler
.str(src
, address
.base
, address
.u
.index
, address
.u
.scale
);
444 else if (address
.u
.offset
>= 0) {
445 ARMThumbImmediate armImm
= ARMThumbImmediate::makeUInt12(address
.u
.offset
);
446 ASSERT(armImm
.isValid());
447 m_assembler
.str(src
, address
.base
, armImm
);
449 ASSERT(address
.u
.offset
>= -255);
450 m_assembler
.str(src
, address
.base
, address
.u
.offset
, true, false);
455 void load32(ImplicitAddress address
, RegisterID dest
)
457 load32(setupArmAddress(address
), dest
);
460 void load32(BaseIndex address
, RegisterID dest
)
462 load32(setupArmAddress(address
), dest
);
465 void load32WithUnalignedHalfWords(BaseIndex address
, RegisterID dest
)
467 load32(setupArmAddress(address
), dest
);
470 void load32(const void* address
, RegisterID dest
)
472 move(TrustedImmPtr(address
), addressTempRegister
);
473 m_assembler
.ldr(dest
, addressTempRegister
, ARMThumbImmediate::makeUInt16(0));
476 void load8(ImplicitAddress address
, RegisterID dest
)
478 load8(setupArmAddress(address
), dest
);
481 DataLabel32
load32WithAddressOffsetPatch(Address address
, RegisterID dest
)
483 DataLabel32 label
= moveWithPatch(TrustedImm32(address
.offset
), dataTempRegister
);
484 load32(ArmAddress(address
.base
, dataTempRegister
), dest
);
488 DataLabelCompact
load32WithCompactAddressOffsetPatch(Address address
, RegisterID dest
)
490 DataLabelCompact
label(this);
491 ASSERT(address
.offset
>= 0);
492 ASSERT(address
.offset
<= MaximumCompactPtrAlignedAddressOffset
);
493 ASSERT(ARMThumbImmediate::makeUInt12(address
.offset
).isUInt7());
494 m_assembler
.ldrCompact(dest
, address
.base
, ARMThumbImmediate::makeUInt12(address
.offset
));
498 void load16(BaseIndex address
, RegisterID dest
)
500 m_assembler
.ldrh(dest
, makeBaseIndexBase(address
), address
.index
, address
.scale
);
503 void load16(ImplicitAddress address
, RegisterID dest
)
505 ARMThumbImmediate armImm
= ARMThumbImmediate::makeUInt12(address
.offset
);
506 if (armImm
.isValid())
507 m_assembler
.ldrh(dest
, address
.base
, armImm
);
509 move(TrustedImm32(address
.offset
), dataTempRegister
);
510 m_assembler
.ldrh(dest
, address
.base
, dataTempRegister
);
514 DataLabel32
store32WithAddressOffsetPatch(RegisterID src
, Address address
)
516 DataLabel32 label
= moveWithPatch(TrustedImm32(address
.offset
), dataTempRegister
);
517 store32(src
, ArmAddress(address
.base
, dataTempRegister
));
521 void store32(RegisterID src
, ImplicitAddress address
)
523 store32(src
, setupArmAddress(address
));
526 void store32(RegisterID src
, BaseIndex address
)
528 store32(src
, setupArmAddress(address
));
531 void store32(TrustedImm32 imm
, ImplicitAddress address
)
533 move(imm
, dataTempRegister
);
534 store32(dataTempRegister
, setupArmAddress(address
));
537 void store32(RegisterID src
, const void* address
)
539 move(TrustedImmPtr(address
), addressTempRegister
);
540 m_assembler
.str(src
, addressTempRegister
, ARMThumbImmediate::makeUInt16(0));
543 void store32(TrustedImm32 imm
, const void* address
)
545 move(imm
, dataTempRegister
);
546 store32(dataTempRegister
, address
);
550 // Floating-point operations:
552 bool supportsFloatingPoint() const { return true; }
553 // On x86(_64) the MacroAssembler provides an interface to truncate a double to an integer.
554 // If a value is not representable as an integer, and possibly for some values that are,
555 // (on x86 INT_MIN, since this is indistinguishable from results for out-of-range/NaN input)
556 // a branch will be taken. It is not clear whether this interface will be well suited to
557 // other platforms. On ARMv7 the hardware truncation operation produces multiple possible
558 // failure values (saturates to INT_MIN & INT_MAX, NaN reulsts in a value of 0). This is a
559 // temporary solution while we work out what this interface should be. Either we need to
560 // decide to make this interface work on all platforms, rework the interface to make it more
561 // generic, or decide that the MacroAssembler cannot practically be used to abstracted these
562 // operations, and make clients go directly to the m_assembler to plant truncation instructions.
564 bool supportsFloatingPointTruncate() const { return false; }
566 bool supportsFloatingPointSqrt() const
571 void loadDouble(ImplicitAddress address
, FPRegisterID dest
)
573 RegisterID base
= address
.base
;
574 int32_t offset
= address
.offset
;
576 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
577 if ((offset
& 3) || (offset
> (255 * 4)) || (offset
< -(255 * 4))) {
578 add32(TrustedImm32(offset
), base
, addressTempRegister
);
579 base
= addressTempRegister
;
583 m_assembler
.vldr(dest
, base
, offset
);
586 void loadDouble(const void* address
, FPRegisterID dest
)
588 move(TrustedImmPtr(address
), addressTempRegister
);
589 m_assembler
.vldr(dest
, addressTempRegister
, 0);
592 void storeDouble(FPRegisterID src
, ImplicitAddress address
)
594 RegisterID base
= address
.base
;
595 int32_t offset
= address
.offset
;
597 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
598 if ((offset
& 3) || (offset
> (255 * 4)) || (offset
< -(255 * 4))) {
599 add32(TrustedImm32(offset
), base
, addressTempRegister
);
600 base
= addressTempRegister
;
604 m_assembler
.vstr(src
, base
, offset
);
607 void addDouble(FPRegisterID src
, FPRegisterID dest
)
609 m_assembler
.vadd_F64(dest
, dest
, src
);
612 void addDouble(Address src
, FPRegisterID dest
)
614 loadDouble(src
, fpTempRegister
);
615 addDouble(fpTempRegister
, dest
);
618 void divDouble(FPRegisterID src
, FPRegisterID dest
)
620 m_assembler
.vdiv_F64(dest
, dest
, src
);
623 void subDouble(FPRegisterID src
, FPRegisterID dest
)
625 m_assembler
.vsub_F64(dest
, dest
, src
);
628 void subDouble(Address src
, FPRegisterID dest
)
630 loadDouble(src
, fpTempRegister
);
631 subDouble(fpTempRegister
, dest
);
634 void mulDouble(FPRegisterID src
, FPRegisterID dest
)
636 m_assembler
.vmul_F64(dest
, dest
, src
);
639 void mulDouble(Address src
, FPRegisterID dest
)
641 loadDouble(src
, fpTempRegister
);
642 mulDouble(fpTempRegister
, dest
);
645 void sqrtDouble(FPRegisterID
, FPRegisterID
)
647 ASSERT_NOT_REACHED();
650 void convertInt32ToDouble(RegisterID src
, FPRegisterID dest
)
652 m_assembler
.vmov(fpTempRegisterAsSingle(), src
);
653 m_assembler
.vcvt_F64_S32(dest
, fpTempRegisterAsSingle());
656 void convertInt32ToDouble(Address address
, FPRegisterID dest
)
658 // Fixme: load directly into the fpr!
659 load32(address
, dataTempRegister
);
660 m_assembler
.vmov(fpTempRegisterAsSingle(), dataTempRegister
);
661 m_assembler
.vcvt_F64_S32(dest
, fpTempRegisterAsSingle());
664 void convertInt32ToDouble(AbsoluteAddress address
, FPRegisterID dest
)
666 // Fixme: load directly into the fpr!
667 load32(address
.m_ptr
, dataTempRegister
);
668 m_assembler
.vmov(fpTempRegisterAsSingle(), dataTempRegister
);
669 m_assembler
.vcvt_F64_S32(dest
, fpTempRegisterAsSingle());
672 Jump
branchDouble(DoubleCondition cond
, FPRegisterID left
, FPRegisterID right
)
674 m_assembler
.vcmp_F64(left
, right
);
677 if (cond
== DoubleNotEqual
) {
678 // ConditionNE jumps if NotEqual *or* unordered - force the unordered cases not to jump.
679 Jump unordered
= makeBranch(ARMv7Assembler::ConditionVS
);
680 Jump result
= makeBranch(ARMv7Assembler::ConditionNE
);
681 unordered
.link(this);
684 if (cond
== DoubleEqualOrUnordered
) {
685 Jump unordered
= makeBranch(ARMv7Assembler::ConditionVS
);
686 Jump notEqual
= makeBranch(ARMv7Assembler::ConditionNE
);
687 unordered
.link(this);
688 // We get here if either unordered or equal.
689 Jump result
= jump();
693 return makeBranch(cond
);
696 Jump
branchTruncateDoubleToInt32(FPRegisterID
, RegisterID
)
698 ASSERT_NOT_REACHED();
702 // Convert 'src' to an integer, and places the resulting 'dest'.
703 // If the result is not representable as a 32 bit value, branch.
704 // May also branch for some values that are representable in 32 bits
705 // (specifically, in this case, 0).
706 void branchConvertDoubleToInt32(FPRegisterID src
, RegisterID dest
, JumpList
& failureCases
, FPRegisterID
)
708 m_assembler
.vcvtr_S32_F64(fpTempRegisterAsSingle(), src
);
709 m_assembler
.vmov(dest
, fpTempRegisterAsSingle());
711 // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
712 m_assembler
.vcvt_F64_S32(fpTempRegister
, fpTempRegisterAsSingle());
713 failureCases
.append(branchDouble(DoubleNotEqualOrUnordered
, src
, fpTempRegister
));
715 // If the result is zero, it might have been -0.0, and the double comparison won't catch this!
716 failureCases
.append(branchTest32(Zero
, dest
));
719 Jump
branchDoubleNonZero(FPRegisterID reg
, FPRegisterID
)
721 m_assembler
.vcmpz_F64(reg
);
723 Jump unordered
= makeBranch(ARMv7Assembler::ConditionVS
);
724 Jump result
= makeBranch(ARMv7Assembler::ConditionNE
);
725 unordered
.link(this);
729 Jump
branchDoubleZeroOrNaN(FPRegisterID reg
, FPRegisterID
)
731 m_assembler
.vcmpz_F64(reg
);
733 Jump unordered
= makeBranch(ARMv7Assembler::ConditionVS
);
734 Jump notEqual
= makeBranch(ARMv7Assembler::ConditionNE
);
735 unordered
.link(this);
736 // We get here if either unordered or equal.
737 Jump result
= jump();
742 // Stack manipulation operations:
744 // The ABI is assumed to provide a stack abstraction to memory,
745 // containing machine word sized units of data. Push and pop
746 // operations add and remove a single register sized unit of data
747 // to or from the stack. Peek and poke operations read or write
748 // values on the stack, without moving the current stack position.
750 void pop(RegisterID dest
)
752 // store postindexed with writeback
753 m_assembler
.ldr(dest
, ARMRegisters::sp
, sizeof(void*), false, true);
756 void push(RegisterID src
)
758 // store preindexed with writeback
759 m_assembler
.str(src
, ARMRegisters::sp
, -sizeof(void*), true, true);
762 void push(Address address
)
764 load32(address
, dataTempRegister
);
765 push(dataTempRegister
);
768 void push(TrustedImm32 imm
)
770 move(imm
, dataTempRegister
);
771 push(dataTempRegister
);
774 // Register move operations:
776 // Move values in registers.
778 void move(TrustedImm32 imm
, RegisterID dest
)
780 uint32_t value
= imm
.m_value
;
783 moveFixedWidthEncoding(imm
, dest
);
785 ARMThumbImmediate armImm
= ARMThumbImmediate::makeEncodedImm(value
);
787 if (armImm
.isValid())
788 m_assembler
.mov(dest
, armImm
);
789 else if ((armImm
= ARMThumbImmediate::makeEncodedImm(~value
)).isValid())
790 m_assembler
.mvn(dest
, armImm
);
792 m_assembler
.mov(dest
, ARMThumbImmediate::makeUInt16(value
));
793 if (value
& 0xffff0000)
794 m_assembler
.movt(dest
, ARMThumbImmediate::makeUInt16(value
>> 16));
799 void move(RegisterID src
, RegisterID dest
)
801 m_assembler
.mov(dest
, src
);
804 void move(TrustedImmPtr imm
, RegisterID dest
)
806 move(TrustedImm32(imm
), dest
);
809 void swap(RegisterID reg1
, RegisterID reg2
)
811 move(reg1
, dataTempRegister
);
813 move(dataTempRegister
, reg2
);
816 void signExtend32ToPtr(RegisterID src
, RegisterID dest
)
822 void zeroExtend32ToPtr(RegisterID src
, RegisterID dest
)
833 // Forwards / external control flow operations:
835 // This set of jump and conditional branch operations return a Jump
836 // object which may linked at a later point, allow forwards jump,
837 // or jumps that will require external linkage (after the code has been
840 // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
841 // respecitvely, for unsigned comparisons the names b, a, be, and ae are
842 // used (representing the names 'below' and 'above').
844 // Operands to the comparision are provided in the expected order, e.g.
845 // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
846 // treated as a signed 32bit value, is less than or equal to 5.
848 // jz and jnz test whether the first operand is equal to zero, and take
849 // an optional second operand of a mask under which to perform the test.
852 // Should we be using TEQ for equal/not-equal?
853 void compare32(RegisterID left
, TrustedImm32 right
)
855 int32_t imm
= right
.m_value
;
857 m_assembler
.tst(left
, left
);
859 ARMThumbImmediate armImm
= ARMThumbImmediate::makeEncodedImm(imm
);
860 if (armImm
.isValid())
861 m_assembler
.cmp(left
, armImm
);
862 else if ((armImm
= ARMThumbImmediate::makeEncodedImm(-imm
)).isValid())
863 m_assembler
.cmn(left
, armImm
);
865 move(TrustedImm32(imm
), dataTempRegister
);
866 m_assembler
.cmp(left
, dataTempRegister
);
871 void test32(RegisterID reg
, TrustedImm32 mask
)
873 int32_t imm
= mask
.m_value
;
876 m_assembler
.tst(reg
, reg
);
878 ARMThumbImmediate armImm
= ARMThumbImmediate::makeEncodedImm(imm
);
879 if (armImm
.isValid())
880 m_assembler
.tst(reg
, armImm
);
882 move(mask
, dataTempRegister
);
883 m_assembler
.tst(reg
, dataTempRegister
);
889 Jump
branch32(RelationalCondition cond
, RegisterID left
, RegisterID right
)
891 m_assembler
.cmp(left
, right
);
892 return Jump(makeBranch(cond
));
895 Jump
branch32(RelationalCondition cond
, RegisterID left
, TrustedImm32 right
)
897 compare32(left
, right
);
898 return Jump(makeBranch(cond
));
901 Jump
branch32(RelationalCondition cond
, RegisterID left
, Address right
)
903 load32(right
, dataTempRegister
);
904 return branch32(cond
, left
, dataTempRegister
);
907 Jump
branch32(RelationalCondition cond
, Address left
, RegisterID right
)
909 load32(left
, dataTempRegister
);
910 return branch32(cond
, dataTempRegister
, right
);
913 Jump
branch32(RelationalCondition cond
, Address left
, TrustedImm32 right
)
915 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
916 load32(left
, addressTempRegister
);
917 return branch32(cond
, addressTempRegister
, right
);
920 Jump
branch32(RelationalCondition cond
, BaseIndex left
, TrustedImm32 right
)
922 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
923 load32(left
, addressTempRegister
);
924 return branch32(cond
, addressTempRegister
, right
);
927 Jump
branch32WithUnalignedHalfWords(RelationalCondition cond
, BaseIndex left
, TrustedImm32 right
)
929 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
930 load32WithUnalignedHalfWords(left
, addressTempRegister
);
931 return branch32(cond
, addressTempRegister
, right
);
934 Jump
branch32(RelationalCondition cond
, AbsoluteAddress left
, RegisterID right
)
936 load32(left
.m_ptr
, dataTempRegister
);
937 return branch32(cond
, dataTempRegister
, right
);
940 Jump
branch32(RelationalCondition cond
, AbsoluteAddress left
, TrustedImm32 right
)
942 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
943 load32(left
.m_ptr
, addressTempRegister
);
944 return branch32(cond
, addressTempRegister
, right
);
947 Jump
branch16(RelationalCondition cond
, BaseIndex left
, RegisterID right
)
949 load16(left
, dataTempRegister
);
950 m_assembler
.lsl(addressTempRegister
, right
, 16);
951 m_assembler
.lsl(dataTempRegister
, dataTempRegister
, 16);
952 return branch32(cond
, dataTempRegister
, addressTempRegister
);
955 Jump
branch16(RelationalCondition cond
, BaseIndex left
, TrustedImm32 right
)
957 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
958 load16(left
, addressTempRegister
);
959 m_assembler
.lsl(addressTempRegister
, addressTempRegister
, 16);
960 return branch32(cond
, addressTempRegister
, TrustedImm32(right
.m_value
<< 16));
963 Jump
branch8(RelationalCondition cond
, RegisterID left
, TrustedImm32 right
)
965 compare32(left
, right
);
966 return Jump(makeBranch(cond
));
969 Jump
branch8(RelationalCondition cond
, Address left
, TrustedImm32 right
)
971 // use addressTempRegister incase the branch8 we call uses dataTempRegister. :-/
972 load8(left
, addressTempRegister
);
973 return branch8(cond
, addressTempRegister
, right
);
976 Jump
branchTest32(ResultCondition cond
, RegisterID reg
, RegisterID mask
)
978 m_assembler
.tst(reg
, mask
);
979 return Jump(makeBranch(cond
));
982 Jump
branchTest32(ResultCondition cond
, RegisterID reg
, TrustedImm32 mask
= TrustedImm32(-1))
985 return Jump(makeBranch(cond
));
988 Jump
branchTest32(ResultCondition cond
, Address address
, TrustedImm32 mask
= TrustedImm32(-1))
990 // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
991 load32(address
, addressTempRegister
);
992 return branchTest32(cond
, addressTempRegister
, mask
);
995 Jump
branchTest32(ResultCondition cond
, BaseIndex address
, TrustedImm32 mask
= TrustedImm32(-1))
997 // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
998 load32(address
, addressTempRegister
);
999 return branchTest32(cond
, addressTempRegister
, mask
);
1002 Jump
branchTest8(ResultCondition cond
, RegisterID reg
, TrustedImm32 mask
= TrustedImm32(-1))
1005 return Jump(makeBranch(cond
));
1008 Jump
branchTest8(ResultCondition cond
, Address address
, TrustedImm32 mask
= TrustedImm32(-1))
1010 // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
1011 load8(address
, addressTempRegister
);
1012 return branchTest8(cond
, addressTempRegister
, mask
);
1015 void jump(RegisterID target
)
1017 m_assembler
.bx(target
);
1020 // Address is a memory location containing the address to jump to
1021 void jump(Address address
)
1023 load32(address
, dataTempRegister
);
1024 m_assembler
.bx(dataTempRegister
);
1028 // Arithmetic control flow operations:
1030 // This set of conditional branch operations branch based
1031 // on the result of an arithmetic operation. The operation
1032 // is performed as normal, storing the result.
1034 // * jz operations branch if the result is zero.
1035 // * jo operations branch if the (signed) arithmetic
1036 // operation caused an overflow to occur.
1038 Jump
branchAdd32(ResultCondition cond
, RegisterID src
, RegisterID dest
)
1040 m_assembler
.add_S(dest
, dest
, src
);
1041 return Jump(makeBranch(cond
));
1044 Jump
branchAdd32(ResultCondition cond
, TrustedImm32 imm
, RegisterID dest
)
1046 ARMThumbImmediate armImm
= ARMThumbImmediate::makeEncodedImm(imm
.m_value
);
1047 if (armImm
.isValid())
1048 m_assembler
.add_S(dest
, dest
, armImm
);
1050 move(imm
, dataTempRegister
);
1051 m_assembler
.add_S(dest
, dest
, dataTempRegister
);
1053 return Jump(makeBranch(cond
));
1056 Jump
branchMul32(ResultCondition cond
, RegisterID src1
, RegisterID src2
, RegisterID dest
)
1058 m_assembler
.smull(dest
, dataTempRegister
, src1
, src2
);
1060 if (cond
== Overflow
) {
1061 m_assembler
.asr(addressTempRegister
, dest
, 31);
1062 return branch32(NotEqual
, addressTempRegister
, dataTempRegister
);
1065 return branchTest32(cond
, dest
);
1068 Jump
branchMul32(ResultCondition cond
, RegisterID src
, RegisterID dest
)
1070 return branchMul32(cond
, src
, dest
, dest
);
1073 Jump
branchMul32(ResultCondition cond
, TrustedImm32 imm
, RegisterID src
, RegisterID dest
)
1075 move(imm
, dataTempRegister
);
1076 return branchMul32(cond
, dataTempRegister
, src
, dest
);
1079 Jump
branchOr32(ResultCondition cond
, RegisterID src
, RegisterID dest
)
1081 m_assembler
.orr_S(dest
, dest
, src
);
1082 return Jump(makeBranch(cond
));
1085 Jump
branchSub32(ResultCondition cond
, RegisterID src
, RegisterID dest
)
1087 m_assembler
.sub_S(dest
, dest
, src
);
1088 return Jump(makeBranch(cond
));
1091 Jump
branchSub32(ResultCondition cond
, TrustedImm32 imm
, RegisterID dest
)
1093 ARMThumbImmediate armImm
= ARMThumbImmediate::makeEncodedImm(imm
.m_value
);
1094 if (armImm
.isValid())
1095 m_assembler
.sub_S(dest
, dest
, armImm
);
1097 move(imm
, dataTempRegister
);
1098 m_assembler
.sub_S(dest
, dest
, dataTempRegister
);
1100 return Jump(makeBranch(cond
));
1103 void relativeTableJump(RegisterID index
, int scale
)
1105 ASSERT(scale
>= 0 && scale
<= 31);
1107 // dataTempRegister will point after the jump if index register contains zero
1108 move(ARMRegisters::pc
, dataTempRegister
);
1109 m_assembler
.add(dataTempRegister
, dataTempRegister
, ARMThumbImmediate::makeEncodedImm(9));
1111 ShiftTypeAndAmount
shift(SRType_LSL
, scale
);
1112 m_assembler
.add(dataTempRegister
, dataTempRegister
, index
, shift
);
1113 jump(dataTempRegister
);
1116 // Miscellaneous operations:
1120 m_assembler
.bkpt(0);
1123 ALWAYS_INLINE Call
nearCall()
1125 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister
);
1126 return Call(m_assembler
.blx(dataTempRegister
), Call::LinkableNear
);
1129 ALWAYS_INLINE Call
call()
1131 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister
);
1132 return Call(m_assembler
.blx(dataTempRegister
), Call::Linkable
);
1135 ALWAYS_INLINE Call
call(RegisterID target
)
1137 return Call(m_assembler
.blx(target
), Call::None
);
1140 ALWAYS_INLINE Call
call(Address address
)
1142 load32(address
, dataTempRegister
);
1143 return Call(m_assembler
.blx(dataTempRegister
), Call::None
);
1146 ALWAYS_INLINE
void ret()
1148 m_assembler
.bx(linkRegister
);
1151 void compare32(RelationalCondition cond
, RegisterID left
, RegisterID right
, RegisterID dest
)
1153 m_assembler
.cmp(left
, right
);
1154 m_assembler
.it(armV7Condition(cond
), false);
1155 m_assembler
.mov(dest
, ARMThumbImmediate::makeUInt16(1));
1156 m_assembler
.mov(dest
, ARMThumbImmediate::makeUInt16(0));
1159 void compare32(RelationalCondition cond
, Address left
, RegisterID right
, RegisterID dest
)
1161 load32(left
, dataTempRegister
);
1162 compare32(cond
, dataTempRegister
, right
, dest
);
1165 void compare32(RelationalCondition cond
, RegisterID left
, TrustedImm32 right
, RegisterID dest
)
1167 compare32(left
, right
);
1168 m_assembler
.it(armV7Condition(cond
), false);
1169 m_assembler
.mov(dest
, ARMThumbImmediate::makeUInt16(1));
1170 m_assembler
.mov(dest
, ARMThumbImmediate::makeUInt16(0));
1174 // The mask should be optional... paerhaps the argument order should be
1175 // dest-src, operations always have a dest? ... possibly not true, considering
1176 // asm ops like test, or pseudo ops like pop().
1177 void test32(ResultCondition cond
, Address address
, TrustedImm32 mask
, RegisterID dest
)
1179 load32(address
, dataTempRegister
);
1180 test32(dataTempRegister
, mask
);
1181 m_assembler
.it(armV7Condition(cond
), false);
1182 m_assembler
.mov(dest
, ARMThumbImmediate::makeUInt16(1));
1183 m_assembler
.mov(dest
, ARMThumbImmediate::makeUInt16(0));
1186 void test8(ResultCondition cond
, Address address
, TrustedImm32 mask
, RegisterID dest
)
1188 load8(address
, dataTempRegister
);
1189 test32(dataTempRegister
, mask
);
1190 m_assembler
.it(armV7Condition(cond
), false);
1191 m_assembler
.mov(dest
, ARMThumbImmediate::makeUInt16(1));
1192 m_assembler
.mov(dest
, ARMThumbImmediate::makeUInt16(0));
1195 ALWAYS_INLINE DataLabel32
moveWithPatch(TrustedImm32 imm
, RegisterID dst
)
1197 moveFixedWidthEncoding(imm
, dst
);
1198 return DataLabel32(this);
1201 ALWAYS_INLINE DataLabelPtr
moveWithPatch(TrustedImmPtr imm
, RegisterID dst
)
1203 moveFixedWidthEncoding(TrustedImm32(imm
), dst
);
1204 return DataLabelPtr(this);
1207 ALWAYS_INLINE Jump
branchPtrWithPatch(RelationalCondition cond
, RegisterID left
, DataLabelPtr
& dataLabel
, TrustedImmPtr initialRightValue
= TrustedImmPtr(0))
1209 dataLabel
= moveWithPatch(initialRightValue
, dataTempRegister
);
1210 return branch32(cond
, left
, dataTempRegister
);
1213 ALWAYS_INLINE Jump
branchPtrWithPatch(RelationalCondition cond
, Address left
, DataLabelPtr
& dataLabel
, TrustedImmPtr initialRightValue
= TrustedImmPtr(0))
1215 load32(left
, addressTempRegister
);
1216 dataLabel
= moveWithPatch(initialRightValue
, dataTempRegister
);
1217 return branch32(cond
, addressTempRegister
, dataTempRegister
);
1220 ALWAYS_INLINE DataLabelPtr
storePtrWithPatch(TrustedImmPtr initialValue
, ImplicitAddress address
)
1222 DataLabelPtr label
= moveWithPatch(initialValue
, dataTempRegister
);
1223 store32(dataTempRegister
, address
);
1226 ALWAYS_INLINE DataLabelPtr
storePtrWithPatch(ImplicitAddress address
) { return storePtrWithPatch(TrustedImmPtr(0), address
); }
1229 ALWAYS_INLINE Call
tailRecursiveCall()
1231 // Like a normal call, but don't link.
1232 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister
);
1233 return Call(m_assembler
.bx(dataTempRegister
), Call::Linkable
);
1236 ALWAYS_INLINE Call
makeTailRecursiveCall(Jump oldJump
)
1239 return tailRecursiveCall();
1243 int executableOffsetFor(int location
)
1245 return m_assembler
.executableOffsetFor(location
);
1249 bool inUninterruptedSequence()
1251 return m_inUninterruptedSequence
;
1254 ALWAYS_INLINE Jump
jump()
1256 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister
);
1257 return Jump(m_assembler
.bx(dataTempRegister
), inUninterruptedSequence() ? ARMv7Assembler::JumpNoConditionFixedSize
: ARMv7Assembler::JumpNoCondition
);
1260 ALWAYS_INLINE Jump
makeBranch(ARMv7Assembler::Condition cond
)
1262 m_assembler
.it(cond
, true, true);
1263 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister
);
1264 return Jump(m_assembler
.bx(dataTempRegister
), inUninterruptedSequence() ? ARMv7Assembler::JumpConditionFixedSize
: ARMv7Assembler::JumpCondition
, cond
);
1266 ALWAYS_INLINE Jump
makeBranch(RelationalCondition cond
) { return makeBranch(armV7Condition(cond
)); }
1267 ALWAYS_INLINE Jump
makeBranch(ResultCondition cond
) { return makeBranch(armV7Condition(cond
)); }
1268 ALWAYS_INLINE Jump
makeBranch(DoubleCondition cond
) { return makeBranch(armV7Condition(cond
)); }
1270 ArmAddress
setupArmAddress(BaseIndex address
)
1272 if (address
.offset
) {
1273 ARMThumbImmediate imm
= ARMThumbImmediate::makeUInt12OrEncodedImm(address
.offset
);
1275 m_assembler
.add(addressTempRegister
, address
.base
, imm
);
1277 move(TrustedImm32(address
.offset
), addressTempRegister
);
1278 m_assembler
.add(addressTempRegister
, addressTempRegister
, address
.base
);
1281 return ArmAddress(addressTempRegister
, address
.index
, address
.scale
);
1283 return ArmAddress(address
.base
, address
.index
, address
.scale
);
1286 ArmAddress
setupArmAddress(Address address
)
1288 if ((address
.offset
>= -0xff) && (address
.offset
<= 0xfff))
1289 return ArmAddress(address
.base
, address
.offset
);
1291 move(TrustedImm32(address
.offset
), addressTempRegister
);
1292 return ArmAddress(address
.base
, addressTempRegister
);
1295 ArmAddress
setupArmAddress(ImplicitAddress address
)
1297 if ((address
.offset
>= -0xff) && (address
.offset
<= 0xfff))
1298 return ArmAddress(address
.base
, address
.offset
);
1300 move(TrustedImm32(address
.offset
), addressTempRegister
);
1301 return ArmAddress(address
.base
, addressTempRegister
);
1304 RegisterID
makeBaseIndexBase(BaseIndex address
)
1306 if (!address
.offset
)
1307 return address
.base
;
1309 ARMThumbImmediate imm
= ARMThumbImmediate::makeUInt12OrEncodedImm(address
.offset
);
1311 m_assembler
.add(addressTempRegister
, address
.base
, imm
);
1313 move(TrustedImm32(address
.offset
), addressTempRegister
);
1314 m_assembler
.add(addressTempRegister
, addressTempRegister
, address
.base
);
1317 return addressTempRegister
;
1320 void moveFixedWidthEncoding(TrustedImm32 imm
, RegisterID dst
)
1322 uint32_t value
= imm
.m_value
;
1323 m_assembler
.movT3(dst
, ARMThumbImmediate::makeUInt16(value
& 0xffff));
1324 m_assembler
.movt(dst
, ARMThumbImmediate::makeUInt16(value
>> 16));
1327 ARMv7Assembler::Condition
armV7Condition(RelationalCondition cond
)
1329 return static_cast<ARMv7Assembler::Condition
>(cond
);
1332 ARMv7Assembler::Condition
armV7Condition(ResultCondition cond
)
1334 return static_cast<ARMv7Assembler::Condition
>(cond
);
1337 ARMv7Assembler::Condition
armV7Condition(DoubleCondition cond
)
1339 return static_cast<ARMv7Assembler::Condition
>(cond
);
1343 friend class LinkBuffer
;
1344 friend class RepatchBuffer
;
1346 static void linkCall(void* code
, Call call
, FunctionPtr function
)
1348 ARMv7Assembler::linkCall(code
, call
.m_jmp
, function
.value());
1351 static void repatchCall(CodeLocationCall call
, CodeLocationLabel destination
)
1353 ARMv7Assembler::relinkCall(call
.dataLocation(), destination
.executableAddress());
1356 static void repatchCall(CodeLocationCall call
, FunctionPtr destination
)
1358 ARMv7Assembler::relinkCall(call
.dataLocation(), destination
.executableAddress());
1361 bool m_inUninterruptedSequence
;
1366 #endif // ENABLE(ASSEMBLER)
1368 #endif // MacroAssemblerARMv7_h