2 * Copyright (C) 2008, 2013 Apple Inc.
3 * Copyright (C) 2009, 2010 University of Szeged
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #ifndef MacroAssemblerARM_h
29 #define MacroAssemblerARM_h
31 #if ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
33 #include "ARMAssembler.h"
34 #include "AbstractMacroAssembler.h"
38 class MacroAssemblerARM
: public AbstractMacroAssembler
<ARMAssembler
> {
39 static const int DoubleConditionMask
= 0x0f;
40 static const int DoubleConditionBitSpecial
= 0x10;
41 COMPILE_ASSERT(!(DoubleConditionBitSpecial
& DoubleConditionMask
), DoubleConditionBitSpecial_should_not_interfere_with_ARMAssembler_Condition_codes
);
43 typedef ARMRegisters::FPRegisterID FPRegisterID
;
45 enum RelationalCondition
{
46 Equal
= ARMAssembler::EQ
,
47 NotEqual
= ARMAssembler::NE
,
48 Above
= ARMAssembler::HI
,
49 AboveOrEqual
= ARMAssembler::CS
,
50 Below
= ARMAssembler::CC
,
51 BelowOrEqual
= ARMAssembler::LS
,
52 GreaterThan
= ARMAssembler::GT
,
53 GreaterThanOrEqual
= ARMAssembler::GE
,
54 LessThan
= ARMAssembler::LT
,
55 LessThanOrEqual
= ARMAssembler::LE
58 enum ResultCondition
{
59 Overflow
= ARMAssembler::VS
,
60 Signed
= ARMAssembler::MI
,
61 PositiveOrZero
= ARMAssembler::PL
,
62 Zero
= ARMAssembler::EQ
,
63 NonZero
= ARMAssembler::NE
66 enum DoubleCondition
{
67 // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
68 DoubleEqual
= ARMAssembler::EQ
,
69 DoubleNotEqual
= ARMAssembler::NE
| DoubleConditionBitSpecial
,
70 DoubleGreaterThan
= ARMAssembler::GT
,
71 DoubleGreaterThanOrEqual
= ARMAssembler::GE
,
72 DoubleLessThan
= ARMAssembler::CC
,
73 DoubleLessThanOrEqual
= ARMAssembler::LS
,
74 // If either operand is NaN, these conditions always evaluate to true.
75 DoubleEqualOrUnordered
= ARMAssembler::EQ
| DoubleConditionBitSpecial
,
76 DoubleNotEqualOrUnordered
= ARMAssembler::NE
,
77 DoubleGreaterThanOrUnordered
= ARMAssembler::HI
,
78 DoubleGreaterThanOrEqualOrUnordered
= ARMAssembler::CS
,
79 DoubleLessThanOrUnordered
= ARMAssembler::LT
,
80 DoubleLessThanOrEqualOrUnordered
= ARMAssembler::LE
,
83 static const RegisterID stackPointerRegister
= ARMRegisters::sp
;
84 static const RegisterID framePointerRegister
= ARMRegisters::fp
;
85 static const RegisterID linkRegister
= ARMRegisters::lr
;
87 static const Scale ScalePtr
= TimesFour
;
89 void add32(RegisterID src
, RegisterID dest
)
91 m_assembler
.adds(dest
, dest
, src
);
94 void add32(RegisterID op1
, RegisterID op2
, RegisterID dest
)
96 m_assembler
.adds(dest
, op1
, op2
);
99 void add32(TrustedImm32 imm
, Address address
)
101 load32(address
, ARMRegisters::S1
);
102 add32(imm
, ARMRegisters::S1
);
103 store32(ARMRegisters::S1
, address
);
106 void add32(TrustedImm32 imm
, RegisterID dest
)
108 m_assembler
.adds(dest
, dest
, m_assembler
.getImm(imm
.m_value
, ARMRegisters::S0
));
111 void add32(AbsoluteAddress src
, RegisterID dest
)
113 move(TrustedImmPtr(src
.m_ptr
), ARMRegisters::S1
);
114 m_assembler
.dtrUp(ARMAssembler::LoadUint32
, ARMRegisters::S1
, ARMRegisters::S1
, 0);
115 add32(ARMRegisters::S1
, dest
);
118 void add32(Address src
, RegisterID dest
)
120 load32(src
, ARMRegisters::S1
);
121 add32(ARMRegisters::S1
, dest
);
124 void add32(RegisterID src
, TrustedImm32 imm
, RegisterID dest
)
126 m_assembler
.adds(dest
, src
, m_assembler
.getImm(imm
.m_value
, ARMRegisters::S0
));
129 void and32(RegisterID src
, RegisterID dest
)
131 m_assembler
.bitAnds(dest
, dest
, src
);
134 void and32(RegisterID op1
, RegisterID op2
, RegisterID dest
)
136 m_assembler
.bitAnds(dest
, op1
, op2
);
139 void and32(TrustedImm32 imm
, RegisterID dest
)
141 ARMWord w
= m_assembler
.getImm(imm
.m_value
, ARMRegisters::S0
, true);
142 if (w
& ARMAssembler::Op2InvertedImmediate
)
143 m_assembler
.bics(dest
, dest
, w
& ~ARMAssembler::Op2InvertedImmediate
);
145 m_assembler
.bitAnds(dest
, dest
, w
);
148 void and32(TrustedImm32 imm
, RegisterID src
, RegisterID dest
)
150 ARMWord w
= m_assembler
.getImm(imm
.m_value
, ARMRegisters::S0
, true);
151 if (w
& ARMAssembler::Op2InvertedImmediate
)
152 m_assembler
.bics(dest
, src
, w
& ~ARMAssembler::Op2InvertedImmediate
);
154 m_assembler
.bitAnds(dest
, src
, w
);
157 void and32(Address src
, RegisterID dest
)
159 load32(src
, ARMRegisters::S1
);
160 and32(ARMRegisters::S1
, dest
);
163 void lshift32(RegisterID shiftAmount
, RegisterID dest
)
165 lshift32(dest
, shiftAmount
, dest
);
168 void lshift32(RegisterID src
, RegisterID shiftAmount
, RegisterID dest
)
170 ARMWord w
= ARMAssembler::getOp2Byte(0x1f);
171 m_assembler
.bitAnd(ARMRegisters::S0
, shiftAmount
, w
);
173 m_assembler
.movs(dest
, m_assembler
.lslRegister(src
, ARMRegisters::S0
));
176 void lshift32(TrustedImm32 imm
, RegisterID dest
)
178 m_assembler
.movs(dest
, m_assembler
.lsl(dest
, imm
.m_value
& 0x1f));
181 void lshift32(RegisterID src
, TrustedImm32 imm
, RegisterID dest
)
183 m_assembler
.movs(dest
, m_assembler
.lsl(src
, imm
.m_value
& 0x1f));
186 void mul32(RegisterID op1
, RegisterID op2
, RegisterID dest
)
190 move(op2
, ARMRegisters::S0
);
191 op2
= ARMRegisters::S0
;
193 // Swap the operands.
194 RegisterID tmp
= op1
;
199 m_assembler
.muls(dest
, op1
, op2
);
202 void mul32(RegisterID src
, RegisterID dest
)
204 mul32(src
, dest
, dest
);
207 void mul32(TrustedImm32 imm
, RegisterID src
, RegisterID dest
)
209 move(imm
, ARMRegisters::S0
);
210 m_assembler
.muls(dest
, src
, ARMRegisters::S0
);
213 void neg32(RegisterID srcDest
)
215 m_assembler
.rsbs(srcDest
, srcDest
, ARMAssembler::getOp2Byte(0));
218 void or32(RegisterID src
, RegisterID dest
)
220 m_assembler
.orrs(dest
, dest
, src
);
223 void or32(RegisterID src
, AbsoluteAddress dest
)
225 move(TrustedImmPtr(dest
.m_ptr
), ARMRegisters::S0
);
226 load32(Address(ARMRegisters::S0
), ARMRegisters::S1
);
227 or32(src
, ARMRegisters::S1
);
228 store32(ARMRegisters::S1
, ARMRegisters::S0
);
231 void or32(TrustedImm32 imm
, RegisterID dest
)
233 m_assembler
.orrs(dest
, dest
, m_assembler
.getImm(imm
.m_value
, ARMRegisters::S0
));
236 void or32(TrustedImm32 imm
, RegisterID src
, RegisterID dest
)
238 m_assembler
.orrs(dest
, src
, m_assembler
.getImm(imm
.m_value
, ARMRegisters::S0
));
241 void or32(RegisterID op1
, RegisterID op2
, RegisterID dest
)
243 m_assembler
.orrs(dest
, op1
, op2
);
246 void rshift32(RegisterID shiftAmount
, RegisterID dest
)
248 rshift32(dest
, shiftAmount
, dest
);
251 void rshift32(RegisterID src
, RegisterID shiftAmount
, RegisterID dest
)
253 ARMWord w
= ARMAssembler::getOp2Byte(0x1f);
254 m_assembler
.bitAnd(ARMRegisters::S0
, shiftAmount
, w
);
256 m_assembler
.movs(dest
, m_assembler
.asrRegister(src
, ARMRegisters::S0
));
259 void rshift32(TrustedImm32 imm
, RegisterID dest
)
261 rshift32(dest
, imm
, dest
);
264 void rshift32(RegisterID src
, TrustedImm32 imm
, RegisterID dest
)
266 m_assembler
.movs(dest
, m_assembler
.asr(src
, imm
.m_value
& 0x1f));
269 void urshift32(RegisterID shiftAmount
, RegisterID dest
)
271 urshift32(dest
, shiftAmount
, dest
);
274 void urshift32(RegisterID src
, RegisterID shiftAmount
, RegisterID dest
)
276 ARMWord w
= ARMAssembler::getOp2Byte(0x1f);
277 m_assembler
.bitAnd(ARMRegisters::S0
, shiftAmount
, w
);
279 m_assembler
.movs(dest
, m_assembler
.lsrRegister(src
, ARMRegisters::S0
));
282 void urshift32(TrustedImm32 imm
, RegisterID dest
)
284 m_assembler
.movs(dest
, m_assembler
.lsr(dest
, imm
.m_value
& 0x1f));
287 void urshift32(RegisterID src
, TrustedImm32 imm
, RegisterID dest
)
289 m_assembler
.movs(dest
, m_assembler
.lsr(src
, imm
.m_value
& 0x1f));
292 void sub32(RegisterID src
, RegisterID dest
)
294 m_assembler
.subs(dest
, dest
, src
);
297 void sub32(TrustedImm32 imm
, RegisterID dest
)
299 m_assembler
.subs(dest
, dest
, m_assembler
.getImm(imm
.m_value
, ARMRegisters::S0
));
302 void sub32(TrustedImm32 imm
, Address address
)
304 load32(address
, ARMRegisters::S1
);
305 sub32(imm
, ARMRegisters::S1
);
306 store32(ARMRegisters::S1
, address
);
309 void sub32(Address src
, RegisterID dest
)
311 load32(src
, ARMRegisters::S1
);
312 sub32(ARMRegisters::S1
, dest
);
315 void sub32(RegisterID src
, TrustedImm32 imm
, RegisterID dest
)
317 m_assembler
.subs(dest
, src
, m_assembler
.getImm(imm
.m_value
, ARMRegisters::S0
));
320 void xor32(RegisterID src
, RegisterID dest
)
322 m_assembler
.eors(dest
, dest
, src
);
325 void xor32(RegisterID op1
, RegisterID op2
, RegisterID dest
)
327 m_assembler
.eors(dest
, op1
, op2
);
330 void xor32(TrustedImm32 imm
, RegisterID dest
)
332 if (imm
.m_value
== -1)
333 m_assembler
.mvns(dest
, dest
);
335 m_assembler
.eors(dest
, dest
, m_assembler
.getImm(imm
.m_value
, ARMRegisters::S0
));
338 void xor32(TrustedImm32 imm
, RegisterID src
, RegisterID dest
)
340 if (imm
.m_value
== -1)
341 m_assembler
.mvns(dest
, src
);
343 m_assembler
.eors(dest
, src
, m_assembler
.getImm(imm
.m_value
, ARMRegisters::S0
));
346 void countLeadingZeros32(RegisterID src
, RegisterID dest
)
348 #if WTF_ARM_ARCH_AT_LEAST(5)
349 m_assembler
.clz(dest
, src
);
353 RELEASE_ASSERT_NOT_REACHED();
357 void load8(ImplicitAddress address
, RegisterID dest
)
359 m_assembler
.dataTransfer32(ARMAssembler::LoadUint8
, dest
, address
.base
, address
.offset
);
362 void load8(BaseIndex address
, RegisterID dest
)
364 m_assembler
.baseIndexTransfer32(ARMAssembler::LoadUint8
, dest
, address
.base
, address
.index
, static_cast<int>(address
.scale
), address
.offset
);
367 void load8(const void* address
, RegisterID dest
)
369 move(TrustedImmPtr(address
), ARMRegisters::S0
);
370 m_assembler
.dataTransfer32(ARMAssembler::LoadUint8
, dest
, ARMRegisters::S0
, 0);
373 void load8Signed(BaseIndex address
, RegisterID dest
)
375 m_assembler
.baseIndexTransfer16(ARMAssembler::LoadInt8
, dest
, address
.base
, address
.index
, static_cast<int>(address
.scale
), address
.offset
);
378 void load16(ImplicitAddress address
, RegisterID dest
)
380 m_assembler
.dataTransfer16(ARMAssembler::LoadUint16
, dest
, address
.base
, address
.offset
);
383 void load16(BaseIndex address
, RegisterID dest
)
385 m_assembler
.baseIndexTransfer16(ARMAssembler::LoadUint16
, dest
, address
.base
, address
.index
, static_cast<int>(address
.scale
), address
.offset
);
388 void load16Signed(BaseIndex address
, RegisterID dest
)
390 m_assembler
.baseIndexTransfer16(ARMAssembler::LoadInt16
, dest
, address
.base
, address
.index
, static_cast<int>(address
.scale
), address
.offset
);
393 void load32(ImplicitAddress address
, RegisterID dest
)
395 m_assembler
.dataTransfer32(ARMAssembler::LoadUint32
, dest
, address
.base
, address
.offset
);
398 void load32(BaseIndex address
, RegisterID dest
)
400 m_assembler
.baseIndexTransfer32(ARMAssembler::LoadUint32
, dest
, address
.base
, address
.index
, static_cast<int>(address
.scale
), address
.offset
);
403 #if CPU(ARMV5_OR_LOWER)
404 void load32WithUnalignedHalfWords(BaseIndex address
, RegisterID dest
);
406 void load32WithUnalignedHalfWords(BaseIndex address
, RegisterID dest
)
408 load32(address
, dest
);
412 void load16Unaligned(BaseIndex address
, RegisterID dest
)
414 load16(address
, dest
);
417 void abortWithReason(AbortReason reason
)
419 move(TrustedImm32(reason
), ARMRegisters::S0
);
423 void abortWithReason(AbortReason reason
, intptr_t misc
)
425 move(TrustedImm32(misc
), ARMRegisters::S1
);
426 abortWithReason(reason
);
429 ConvertibleLoadLabel
convertibleLoadPtr(Address address
, RegisterID dest
)
431 ConvertibleLoadLabel
result(this);
432 ASSERT(address
.offset
>= 0 && address
.offset
<= 255);
433 m_assembler
.dtrUp(ARMAssembler::LoadUint32
, dest
, address
.base
, address
.offset
);
437 DataLabel32
load32WithAddressOffsetPatch(Address address
, RegisterID dest
)
439 DataLabel32
dataLabel(this);
440 m_assembler
.ldrUniqueImmediate(ARMRegisters::S0
, 0);
441 m_assembler
.dtrUpRegister(ARMAssembler::LoadUint32
, dest
, address
.base
, ARMRegisters::S0
);
445 static bool isCompactPtrAlignedAddressOffset(ptrdiff_t value
)
447 return value
>= -4095 && value
<= 4095;
450 DataLabelCompact
load32WithCompactAddressOffsetPatch(Address address
, RegisterID dest
)
452 DataLabelCompact
dataLabel(this);
453 ASSERT(isCompactPtrAlignedAddressOffset(address
.offset
));
454 if (address
.offset
>= 0)
455 m_assembler
.dtrUp(ARMAssembler::LoadUint32
, dest
, address
.base
, address
.offset
);
457 m_assembler
.dtrDown(ARMAssembler::LoadUint32
, dest
, address
.base
, address
.offset
);
461 DataLabel32
store32WithAddressOffsetPatch(RegisterID src
, Address address
)
463 DataLabel32
dataLabel(this);
464 m_assembler
.ldrUniqueImmediate(ARMRegisters::S0
, 0);
465 m_assembler
.dtrUpRegister(ARMAssembler::StoreUint32
, src
, address
.base
, ARMRegisters::S0
);
469 void store8(RegisterID src
, BaseIndex address
)
471 m_assembler
.baseIndexTransfer32(ARMAssembler::StoreUint8
, src
, address
.base
, address
.index
, static_cast<int>(address
.scale
), address
.offset
);
474 void store8(RegisterID src
, ImplicitAddress address
)
476 m_assembler
.dtrUp(ARMAssembler::StoreUint8
, src
, address
.base
, address
.offset
);
479 void store8(RegisterID src
, const void* address
)
481 move(TrustedImmPtr(address
), ARMRegisters::S0
);
482 m_assembler
.dtrUp(ARMAssembler::StoreUint8
, src
, ARMRegisters::S0
, 0);
485 void store8(TrustedImm32 imm
, ImplicitAddress address
)
487 move(imm
, ARMRegisters::S1
);
488 store8(ARMRegisters::S1
, address
);
491 void store8(TrustedImm32 imm
, const void* address
)
493 move(TrustedImm32(reinterpret_cast<ARMWord
>(address
)), ARMRegisters::S0
);
494 move(imm
, ARMRegisters::S1
);
495 m_assembler
.dtrUp(ARMAssembler::StoreUint8
, ARMRegisters::S1
, ARMRegisters::S0
, 0);
498 void store16(RegisterID src
, BaseIndex address
)
500 m_assembler
.baseIndexTransfer16(ARMAssembler::StoreUint16
, src
, address
.base
, address
.index
, static_cast<int>(address
.scale
), address
.offset
);
503 void store32(RegisterID src
, ImplicitAddress address
)
505 m_assembler
.dataTransfer32(ARMAssembler::StoreUint32
, src
, address
.base
, address
.offset
);
508 void store32(RegisterID src
, BaseIndex address
)
510 m_assembler
.baseIndexTransfer32(ARMAssembler::StoreUint32
, src
, address
.base
, address
.index
, static_cast<int>(address
.scale
), address
.offset
);
513 void store32(TrustedImm32 imm
, ImplicitAddress address
)
515 move(imm
, ARMRegisters::S1
);
516 store32(ARMRegisters::S1
, address
);
519 void store32(TrustedImm32 imm
, BaseIndex address
)
521 move(imm
, ARMRegisters::S1
);
522 m_assembler
.baseIndexTransfer32(ARMAssembler::StoreUint32
, ARMRegisters::S1
, address
.base
, address
.index
, static_cast<int>(address
.scale
), address
.offset
);
525 void store32(RegisterID src
, const void* address
)
527 m_assembler
.ldrUniqueImmediate(ARMRegisters::S0
, reinterpret_cast<ARMWord
>(address
));
528 m_assembler
.dtrUp(ARMAssembler::StoreUint32
, src
, ARMRegisters::S0
, 0);
531 void store32(TrustedImm32 imm
, const void* address
)
533 m_assembler
.ldrUniqueImmediate(ARMRegisters::S0
, reinterpret_cast<ARMWord
>(address
));
534 m_assembler
.moveImm(imm
.m_value
, ARMRegisters::S1
);
535 m_assembler
.dtrUp(ARMAssembler::StoreUint32
, ARMRegisters::S1
, ARMRegisters::S0
, 0);
538 void pop(RegisterID dest
)
540 m_assembler
.pop(dest
);
543 void popPair(RegisterID dest1
, RegisterID dest2
)
545 m_assembler
.pop(dest1
);
546 m_assembler
.pop(dest2
);
549 void push(RegisterID src
)
551 m_assembler
.push(src
);
554 void push(Address address
)
556 load32(address
, ARMRegisters::S1
);
557 push(ARMRegisters::S1
);
560 void push(TrustedImm32 imm
)
562 move(imm
, ARMRegisters::S0
);
563 push(ARMRegisters::S0
);
566 void pushPair(RegisterID src1
, RegisterID src2
)
568 m_assembler
.push(src2
);
569 m_assembler
.push(src1
);
572 void move(TrustedImm32 imm
, RegisterID dest
)
574 m_assembler
.moveImm(imm
.m_value
, dest
);
577 void move(RegisterID src
, RegisterID dest
)
580 m_assembler
.mov(dest
, src
);
583 void move(TrustedImmPtr imm
, RegisterID dest
)
585 move(TrustedImm32(imm
), dest
);
588 void swap(RegisterID reg1
, RegisterID reg2
)
595 void signExtend32ToPtr(RegisterID src
, RegisterID dest
)
601 void zeroExtend32ToPtr(RegisterID src
, RegisterID dest
)
607 Jump
branch8(RelationalCondition cond
, Address left
, TrustedImm32 right
)
609 load8(left
, ARMRegisters::S1
);
610 return branch32(cond
, ARMRegisters::S1
, right
);
613 Jump
branch8(RelationalCondition cond
, BaseIndex left
, TrustedImm32 right
)
615 ASSERT(!(right
.m_value
& 0xFFFFFF00));
616 load8(left
, ARMRegisters::S1
);
617 return branch32(cond
, ARMRegisters::S1
, right
);
620 Jump
branch8(RelationalCondition cond
, AbsoluteAddress left
, TrustedImm32 right
)
622 move(TrustedImmPtr(left
.m_ptr
), ARMRegisters::S1
);
623 load8(Address(ARMRegisters::S1
), ARMRegisters::S1
);
624 return branch32(cond
, ARMRegisters::S1
, right
);
627 Jump
branch32(RelationalCondition cond
, RegisterID left
, RegisterID right
, int useConstantPool
= 0)
629 m_assembler
.cmp(left
, right
);
630 return Jump(m_assembler
.jmp(ARMCondition(cond
), useConstantPool
));
633 Jump
branch32(RelationalCondition cond
, RegisterID left
, TrustedImm32 right
, int useConstantPool
= 0)
635 internalCompare32(left
, right
);
636 return Jump(m_assembler
.jmp(ARMCondition(cond
), useConstantPool
));
639 Jump
branch32(RelationalCondition cond
, RegisterID left
, Address right
)
641 load32(right
, ARMRegisters::S1
);
642 return branch32(cond
, left
, ARMRegisters::S1
);
645 Jump
branch32(RelationalCondition cond
, Address left
, RegisterID right
)
647 load32(left
, ARMRegisters::S1
);
648 return branch32(cond
, ARMRegisters::S1
, right
);
651 Jump
branch32(RelationalCondition cond
, Address left
, TrustedImm32 right
)
653 load32(left
, ARMRegisters::S1
);
654 return branch32(cond
, ARMRegisters::S1
, right
);
657 Jump
branch32(RelationalCondition cond
, BaseIndex left
, TrustedImm32 right
)
659 load32(left
, ARMRegisters::S1
);
660 return branch32(cond
, ARMRegisters::S1
, right
);
663 Jump
branch32WithUnalignedHalfWords(RelationalCondition cond
, BaseIndex left
, TrustedImm32 right
)
665 load32WithUnalignedHalfWords(left
, ARMRegisters::S1
);
666 return branch32(cond
, ARMRegisters::S1
, right
);
669 Jump
branchTest8(ResultCondition cond
, Address address
, TrustedImm32 mask
= TrustedImm32(-1))
671 load8(address
, ARMRegisters::S1
);
672 return branchTest32(cond
, ARMRegisters::S1
, mask
);
675 Jump
branchTest8(ResultCondition cond
, BaseIndex address
, TrustedImm32 mask
= TrustedImm32(-1))
677 load8(address
, ARMRegisters::S1
);
678 return branchTest32(cond
, ARMRegisters::S1
, mask
);
681 Jump
branchTest8(ResultCondition cond
, AbsoluteAddress address
, TrustedImm32 mask
= TrustedImm32(-1))
683 move(TrustedImmPtr(address
.m_ptr
), ARMRegisters::S1
);
684 load8(Address(ARMRegisters::S1
), ARMRegisters::S1
);
685 return branchTest32(cond
, ARMRegisters::S1
, mask
);
688 Jump
branchTest32(ResultCondition cond
, RegisterID reg
, RegisterID mask
)
690 ASSERT((cond
== Zero
) || (cond
== NonZero
));
691 m_assembler
.tst(reg
, mask
);
692 return Jump(m_assembler
.jmp(ARMCondition(cond
)));
695 Jump
branchTest32(ResultCondition cond
, RegisterID reg
, TrustedImm32 mask
= TrustedImm32(-1))
697 ASSERT((cond
== Zero
) || (cond
== NonZero
));
698 ARMWord w
= m_assembler
.getImm(mask
.m_value
, ARMRegisters::S0
, true);
699 if (w
& ARMAssembler::Op2InvertedImmediate
)
700 m_assembler
.bics(ARMRegisters::S0
, reg
, w
& ~ARMAssembler::Op2InvertedImmediate
);
702 m_assembler
.tst(reg
, w
);
703 return Jump(m_assembler
.jmp(ARMCondition(cond
)));
706 Jump
branchTest32(ResultCondition cond
, Address address
, TrustedImm32 mask
= TrustedImm32(-1))
708 load32(address
, ARMRegisters::S1
);
709 return branchTest32(cond
, ARMRegisters::S1
, mask
);
712 Jump
branchTest32(ResultCondition cond
, BaseIndex address
, TrustedImm32 mask
= TrustedImm32(-1))
714 load32(address
, ARMRegisters::S1
);
715 return branchTest32(cond
, ARMRegisters::S1
, mask
);
720 return Jump(m_assembler
.jmp());
723 void jump(RegisterID target
)
725 m_assembler
.bx(target
);
728 void jump(Address address
)
730 load32(address
, ARMRegisters::pc
);
733 void jump(AbsoluteAddress address
)
735 move(TrustedImmPtr(address
.m_ptr
), ARMRegisters::S0
);
736 load32(Address(ARMRegisters::S0
, 0), ARMRegisters::pc
);
739 void moveDoubleToInts(FPRegisterID src
, RegisterID dest1
, RegisterID dest2
)
741 m_assembler
.vmov(dest1
, dest2
, src
);
744 void moveIntsToDouble(RegisterID src1
, RegisterID src2
, FPRegisterID dest
, FPRegisterID
)
746 m_assembler
.vmov(dest
, src1
, src2
);
749 Jump
branchAdd32(ResultCondition cond
, RegisterID src
, RegisterID dest
)
751 ASSERT((cond
== Overflow
) || (cond
== Signed
) || (cond
== Zero
)
752 || (cond
== NonZero
) || (cond
== PositiveOrZero
));
754 return Jump(m_assembler
.jmp(ARMCondition(cond
)));
757 Jump
branchAdd32(ResultCondition cond
, RegisterID op1
, RegisterID op2
, RegisterID dest
)
759 ASSERT((cond
== Overflow
) || (cond
== Signed
) || (cond
== Zero
)
760 || (cond
== NonZero
) || (cond
== PositiveOrZero
));
761 add32(op1
, op2
, dest
);
762 return Jump(m_assembler
.jmp(ARMCondition(cond
)));
765 Jump
branchAdd32(ResultCondition cond
, TrustedImm32 imm
, RegisterID dest
)
767 ASSERT((cond
== Overflow
) || (cond
== Signed
) || (cond
== Zero
)
768 || (cond
== NonZero
) || (cond
== PositiveOrZero
));
770 return Jump(m_assembler
.jmp(ARMCondition(cond
)));
773 Jump
branchAdd32(ResultCondition cond
, RegisterID src
, TrustedImm32 imm
, RegisterID dest
)
775 ASSERT((cond
== Overflow
) || (cond
== Signed
) || (cond
== Zero
)
776 || (cond
== NonZero
) || (cond
== PositiveOrZero
));
777 add32(src
, imm
, dest
);
778 return Jump(m_assembler
.jmp(ARMCondition(cond
)));
781 Jump
branchAdd32(ResultCondition cond
, TrustedImm32 imm
, AbsoluteAddress dest
)
783 ASSERT((cond
== Overflow
) || (cond
== Signed
) || (cond
== Zero
)
784 || (cond
== NonZero
) || (cond
== PositiveOrZero
));
786 return Jump(m_assembler
.jmp(ARMCondition(cond
)));
789 Jump
branchAdd32(ResultCondition cond
, Address src
, RegisterID dest
)
791 load32(src
, ARMRegisters::S0
);
792 return branchAdd32(cond
, dest
, ARMRegisters::S0
, dest
);
794 void mull32(RegisterID op1
, RegisterID op2
, RegisterID dest
)
798 move(op2
, ARMRegisters::S0
);
799 op2
= ARMRegisters::S0
;
801 // Swap the operands.
802 RegisterID tmp
= op1
;
807 m_assembler
.mull(ARMRegisters::S1
, dest
, op1
, op2
);
808 m_assembler
.cmp(ARMRegisters::S1
, m_assembler
.asr(dest
, 31));
811 Jump
branchMul32(ResultCondition cond
, RegisterID src1
, RegisterID src2
, RegisterID dest
)
813 ASSERT((cond
== Overflow
) || (cond
== Signed
) || (cond
== Zero
) || (cond
== NonZero
));
814 if (cond
== Overflow
) {
815 mull32(src1
, src2
, dest
);
819 mul32(src1
, src2
, dest
);
820 return Jump(m_assembler
.jmp(ARMCondition(cond
)));
823 Jump
branchMul32(ResultCondition cond
, RegisterID src
, RegisterID dest
)
825 return branchMul32(cond
, src
, dest
, dest
);
828 Jump
branchMul32(ResultCondition cond
, TrustedImm32 imm
, RegisterID src
, RegisterID dest
)
830 ASSERT((cond
== Overflow
) || (cond
== Signed
) || (cond
== Zero
) || (cond
== NonZero
));
831 if (cond
== Overflow
) {
832 move(imm
, ARMRegisters::S0
);
833 mull32(ARMRegisters::S0
, src
, dest
);
837 mul32(imm
, src
, dest
);
838 return Jump(m_assembler
.jmp(ARMCondition(cond
)));
841 Jump
branchSub32(ResultCondition cond
, RegisterID src
, RegisterID dest
)
843 ASSERT((cond
== Overflow
) || (cond
== Signed
) || (cond
== Zero
) || (cond
== NonZero
));
845 return Jump(m_assembler
.jmp(ARMCondition(cond
)));
848 Jump
branchSub32(ResultCondition cond
, TrustedImm32 imm
, RegisterID dest
)
850 ASSERT((cond
== Overflow
) || (cond
== Signed
) || (cond
== Zero
) || (cond
== NonZero
));
852 return Jump(m_assembler
.jmp(ARMCondition(cond
)));
855 Jump
branchSub32(ResultCondition cond
, RegisterID src
, TrustedImm32 imm
, RegisterID dest
)
857 ASSERT((cond
== Overflow
) || (cond
== Signed
) || (cond
== Zero
) || (cond
== NonZero
));
858 sub32(src
, imm
, dest
);
859 return Jump(m_assembler
.jmp(ARMCondition(cond
)));
862 Jump
branchSub32(ResultCondition cond
, RegisterID op1
, RegisterID op2
, RegisterID dest
)
864 ASSERT((cond
== Overflow
) || (cond
== Signed
) || (cond
== Zero
) || (cond
== NonZero
));
865 m_assembler
.subs(dest
, op1
, op2
);
866 return Jump(m_assembler
.jmp(ARMCondition(cond
)));
869 Jump
branchNeg32(ResultCondition cond
, RegisterID srcDest
)
871 ASSERT((cond
== Overflow
) || (cond
== Signed
) || (cond
== Zero
) || (cond
== NonZero
));
873 return Jump(m_assembler
.jmp(ARMCondition(cond
)));
876 Jump
branchOr32(ResultCondition cond
, RegisterID src
, RegisterID dest
)
878 ASSERT((cond
== Signed
) || (cond
== Zero
) || (cond
== NonZero
));
880 return Jump(m_assembler
.jmp(ARMCondition(cond
)));
883 PatchableJump
patchableJump()
885 return PatchableJump(m_assembler
.jmp(ARMAssembler::AL
, 1));
888 PatchableJump
patchableBranch32(RelationalCondition cond
, RegisterID reg
, TrustedImm32 imm
)
890 internalCompare32(reg
, imm
);
891 Jump
jump(m_assembler
.loadBranchTarget(ARMRegisters::S1
, ARMCondition(cond
), true));
892 m_assembler
.bx(ARMRegisters::S1
, ARMCondition(cond
));
893 return PatchableJump(jump
);
903 m_assembler
.loadBranchTarget(ARMRegisters::S1
, ARMAssembler::AL
, true);
904 return Call(m_assembler
.blx(ARMRegisters::S1
), Call::LinkableNear
);
907 Call
call(RegisterID target
)
909 return Call(m_assembler
.blx(target
), Call::None
);
912 void call(Address address
)
914 call32(address
.base
, address
.offset
);
919 m_assembler
.bx(linkRegister
);
922 void compare32(RelationalCondition cond
, RegisterID left
, RegisterID right
, RegisterID dest
)
924 m_assembler
.cmp(left
, right
);
925 m_assembler
.mov(dest
, ARMAssembler::getOp2Byte(0));
926 m_assembler
.mov(dest
, ARMAssembler::getOp2Byte(1), ARMCondition(cond
));
929 void compare32(RelationalCondition cond
, RegisterID left
, TrustedImm32 right
, RegisterID dest
)
931 m_assembler
.cmp(left
, m_assembler
.getImm(right
.m_value
, ARMRegisters::S0
));
932 m_assembler
.mov(dest
, ARMAssembler::getOp2Byte(0));
933 m_assembler
.mov(dest
, ARMAssembler::getOp2Byte(1), ARMCondition(cond
));
936 void compare8(RelationalCondition cond
, Address left
, TrustedImm32 right
, RegisterID dest
)
938 load8(left
, ARMRegisters::S1
);
939 compare32(cond
, ARMRegisters::S1
, right
, dest
);
942 void test32(ResultCondition cond
, RegisterID reg
, TrustedImm32 mask
, RegisterID dest
)
944 if (mask
.m_value
== -1)
945 m_assembler
.cmp(0, reg
);
947 m_assembler
.tst(reg
, m_assembler
.getImm(mask
.m_value
, ARMRegisters::S0
));
948 m_assembler
.mov(dest
, ARMAssembler::getOp2Byte(0));
949 m_assembler
.mov(dest
, ARMAssembler::getOp2Byte(1), ARMCondition(cond
));
952 void test32(ResultCondition cond
, Address address
, TrustedImm32 mask
, RegisterID dest
)
954 load32(address
, ARMRegisters::S1
);
955 test32(cond
, ARMRegisters::S1
, mask
, dest
);
958 void test8(ResultCondition cond
, Address address
, TrustedImm32 mask
, RegisterID dest
)
960 load8(address
, ARMRegisters::S1
);
961 test32(cond
, ARMRegisters::S1
, mask
, dest
);
964 void add32(TrustedImm32 imm
, RegisterID src
, RegisterID dest
)
966 m_assembler
.add(dest
, src
, m_assembler
.getImm(imm
.m_value
, ARMRegisters::S0
));
969 void add32(TrustedImm32 imm
, AbsoluteAddress address
)
971 load32(address
.m_ptr
, ARMRegisters::S1
);
972 add32(imm
, ARMRegisters::S1
);
973 store32(ARMRegisters::S1
, address
.m_ptr
);
976 void add64(TrustedImm32 imm
, AbsoluteAddress address
)
980 move(TrustedImmPtr(address
.m_ptr
), ARMRegisters::S1
);
981 m_assembler
.dtrUp(ARMAssembler::LoadUint32
, ARMRegisters::S0
, ARMRegisters::S1
, 0);
983 if ((tmp
= ARMAssembler::getOp2(imm
.m_value
)) != ARMAssembler::InvalidImmediate
)
984 m_assembler
.adds(ARMRegisters::S0
, ARMRegisters::S0
, tmp
);
985 else if ((tmp
= ARMAssembler::getOp2(-imm
.m_value
)) != ARMAssembler::InvalidImmediate
)
986 m_assembler
.subs(ARMRegisters::S0
, ARMRegisters::S0
, tmp
);
988 m_assembler
.adds(ARMRegisters::S0
, ARMRegisters::S0
, m_assembler
.getImm(imm
.m_value
, ARMRegisters::S1
));
989 move(TrustedImmPtr(address
.m_ptr
), ARMRegisters::S1
);
991 m_assembler
.dtrUp(ARMAssembler::StoreUint32
, ARMRegisters::S0
, ARMRegisters::S1
, 0);
993 m_assembler
.dtrUp(ARMAssembler::LoadUint32
, ARMRegisters::S0
, ARMRegisters::S1
, sizeof(ARMWord
));
994 if (imm
.m_value
>= 0)
995 m_assembler
.adc(ARMRegisters::S0
, ARMRegisters::S0
, ARMAssembler::getOp2Byte(0));
997 m_assembler
.sbc(ARMRegisters::S0
, ARMRegisters::S0
, ARMAssembler::getOp2Byte(0));
998 m_assembler
.dtrUp(ARMAssembler::StoreUint32
, ARMRegisters::S0
, ARMRegisters::S1
, sizeof(ARMWord
));
1001 void sub32(TrustedImm32 imm
, AbsoluteAddress address
)
1003 load32(address
.m_ptr
, ARMRegisters::S1
);
1004 sub32(imm
, ARMRegisters::S1
);
1005 store32(ARMRegisters::S1
, address
.m_ptr
);
1008 void load32(const void* address
, RegisterID dest
)
1010 m_assembler
.ldrUniqueImmediate(ARMRegisters::S0
, reinterpret_cast<ARMWord
>(address
));
1011 m_assembler
.dtrUp(ARMAssembler::LoadUint32
, dest
, ARMRegisters::S0
, 0);
1014 Jump
branch32(RelationalCondition cond
, AbsoluteAddress left
, RegisterID right
)
1016 load32(left
.m_ptr
, ARMRegisters::S1
);
1017 return branch32(cond
, ARMRegisters::S1
, right
);
1020 Jump
branch32(RelationalCondition cond
, AbsoluteAddress left
, TrustedImm32 right
)
1022 load32(left
.m_ptr
, ARMRegisters::S1
);
1023 return branch32(cond
, ARMRegisters::S1
, right
);
1026 void relativeTableJump(RegisterID index
, int scale
)
1028 ASSERT(scale
>= 0 && scale
<= 31);
1029 m_assembler
.add(ARMRegisters::pc
, ARMRegisters::pc
, m_assembler
.lsl(index
, scale
));
1031 // NOP the default prefetching
1032 m_assembler
.mov(ARMRegisters::r0
, ARMRegisters::r0
);
1037 ensureSpace(2 * sizeof(ARMWord
), sizeof(ARMWord
));
1038 m_assembler
.loadBranchTarget(ARMRegisters::S1
, ARMAssembler::AL
, true);
1039 return Call(m_assembler
.blx(ARMRegisters::S1
), Call::Linkable
);
1042 Call
tailRecursiveCall()
1044 return Call::fromTailJump(jump());
1047 Call
makeTailRecursiveCall(Jump oldJump
)
1049 return Call::fromTailJump(oldJump
);
1052 DataLabelPtr
moveWithPatch(TrustedImmPtr initialValue
, RegisterID dest
)
1054 DataLabelPtr
dataLabel(this);
1055 m_assembler
.ldrUniqueImmediate(dest
, reinterpret_cast<ARMWord
>(initialValue
.m_value
));
1059 DataLabel32
moveWithPatch(TrustedImm32 initialValue
, RegisterID dest
)
1061 DataLabel32
dataLabel(this);
1062 m_assembler
.ldrUniqueImmediate(dest
, static_cast<ARMWord
>(initialValue
.m_value
));
1066 Jump
branchPtrWithPatch(RelationalCondition cond
, RegisterID left
, DataLabelPtr
& dataLabel
, TrustedImmPtr initialRightValue
= TrustedImmPtr(0))
1068 ensureSpace(3 * sizeof(ARMWord
), 2 * sizeof(ARMWord
));
1069 dataLabel
= moveWithPatch(initialRightValue
, ARMRegisters::S1
);
1070 Jump jump
= branch32(cond
, left
, ARMRegisters::S1
, true);
1074 Jump
branchPtrWithPatch(RelationalCondition cond
, Address left
, DataLabelPtr
& dataLabel
, TrustedImmPtr initialRightValue
= TrustedImmPtr(0))
1076 load32(left
, ARMRegisters::S1
);
1077 ensureSpace(3 * sizeof(ARMWord
), 2 * sizeof(ARMWord
));
1078 dataLabel
= moveWithPatch(initialRightValue
, ARMRegisters::S0
);
1079 Jump jump
= branch32(cond
, ARMRegisters::S0
, ARMRegisters::S1
, true);
1083 Jump
branch32WithPatch(RelationalCondition cond
, Address left
, DataLabel32
& dataLabel
, TrustedImm32 initialRightValue
= TrustedImm32(0))
1085 load32(left
, ARMRegisters::S1
);
1086 ensureSpace(3 * sizeof(ARMWord
), 2 * sizeof(ARMWord
));
1087 dataLabel
= moveWithPatch(initialRightValue
, ARMRegisters::S0
);
1088 Jump jump
= branch32(cond
, ARMRegisters::S0
, ARMRegisters::S1
, true);
1092 DataLabelPtr
storePtrWithPatch(TrustedImmPtr initialValue
, ImplicitAddress address
)
1094 DataLabelPtr dataLabel
= moveWithPatch(initialValue
, ARMRegisters::S1
);
1095 store32(ARMRegisters::S1
, address
);
1099 DataLabelPtr
storePtrWithPatch(ImplicitAddress address
)
1101 return storePtrWithPatch(TrustedImmPtr(0), address
);
1104 // Floating point operators
1105 static bool supportsFloatingPoint()
1107 return s_isVFPPresent
;
1110 static bool supportsFloatingPointTruncate()
1115 static bool supportsFloatingPointSqrt()
1117 return s_isVFPPresent
;
1119 static bool supportsFloatingPointAbs() { return false; }
1121 void loadFloat(BaseIndex address
, FPRegisterID dest
)
1123 m_assembler
.baseIndexTransferFloat(ARMAssembler::LoadFloat
, dest
, address
.base
, address
.index
, static_cast<int>(address
.scale
), address
.offset
);
1126 void loadDouble(ImplicitAddress address
, FPRegisterID dest
)
1128 m_assembler
.dataTransferFloat(ARMAssembler::LoadDouble
, dest
, address
.base
, address
.offset
);
1131 void loadDouble(BaseIndex address
, FPRegisterID dest
)
1133 m_assembler
.baseIndexTransferFloat(ARMAssembler::LoadDouble
, dest
, address
.base
, address
.index
, static_cast<int>(address
.scale
), address
.offset
);
1136 void loadDouble(TrustedImmPtr address
, FPRegisterID dest
)
1138 move(TrustedImm32(reinterpret_cast<ARMWord
>(address
.m_value
)), ARMRegisters::S0
);
1139 m_assembler
.doubleDtrUp(ARMAssembler::LoadDouble
, dest
, ARMRegisters::S0
, 0);
1142 void storeFloat(FPRegisterID src
, BaseIndex address
)
1144 m_assembler
.baseIndexTransferFloat(ARMAssembler::StoreFloat
, src
, address
.base
, address
.index
, static_cast<int>(address
.scale
), address
.offset
);
1147 void storeDouble(FPRegisterID src
, ImplicitAddress address
)
1149 m_assembler
.dataTransferFloat(ARMAssembler::StoreDouble
, src
, address
.base
, address
.offset
);
1152 void storeDouble(FPRegisterID src
, BaseIndex address
)
1154 m_assembler
.baseIndexTransferFloat(ARMAssembler::StoreDouble
, src
, address
.base
, address
.index
, static_cast<int>(address
.scale
), address
.offset
);
1157 void storeDouble(FPRegisterID src
, TrustedImmPtr address
)
1159 move(TrustedImm32(reinterpret_cast<ARMWord
>(address
.m_value
)), ARMRegisters::S0
);
1160 m_assembler
.dataTransferFloat(ARMAssembler::StoreDouble
, src
, ARMRegisters::S0
, 0);
1163 void moveDouble(FPRegisterID src
, FPRegisterID dest
)
1166 m_assembler
.vmov_f64(dest
, src
);
1169 void addDouble(FPRegisterID src
, FPRegisterID dest
)
1171 m_assembler
.vadd_f64(dest
, dest
, src
);
1174 void addDouble(FPRegisterID op1
, FPRegisterID op2
, FPRegisterID dest
)
1176 m_assembler
.vadd_f64(dest
, op1
, op2
);
1179 void addDouble(Address src
, FPRegisterID dest
)
1181 loadDouble(src
, ARMRegisters::SD0
);
1182 addDouble(ARMRegisters::SD0
, dest
);
1185 void addDouble(AbsoluteAddress address
, FPRegisterID dest
)
1187 loadDouble(TrustedImmPtr(address
.m_ptr
), ARMRegisters::SD0
);
1188 addDouble(ARMRegisters::SD0
, dest
);
1191 void divDouble(FPRegisterID src
, FPRegisterID dest
)
1193 m_assembler
.vdiv_f64(dest
, dest
, src
);
1196 void divDouble(FPRegisterID op1
, FPRegisterID op2
, FPRegisterID dest
)
1198 m_assembler
.vdiv_f64(dest
, op1
, op2
);
1201 void divDouble(Address src
, FPRegisterID dest
)
1203 RELEASE_ASSERT_NOT_REACHED(); // Untested
1204 loadDouble(src
, ARMRegisters::SD0
);
1205 divDouble(ARMRegisters::SD0
, dest
);
1208 void subDouble(FPRegisterID src
, FPRegisterID dest
)
1210 m_assembler
.vsub_f64(dest
, dest
, src
);
1213 void subDouble(FPRegisterID op1
, FPRegisterID op2
, FPRegisterID dest
)
1215 m_assembler
.vsub_f64(dest
, op1
, op2
);
1218 void subDouble(Address src
, FPRegisterID dest
)
1220 loadDouble(src
, ARMRegisters::SD0
);
1221 subDouble(ARMRegisters::SD0
, dest
);
1224 void mulDouble(FPRegisterID src
, FPRegisterID dest
)
1226 m_assembler
.vmul_f64(dest
, dest
, src
);
1229 void mulDouble(Address src
, FPRegisterID dest
)
1231 loadDouble(src
, ARMRegisters::SD0
);
1232 mulDouble(ARMRegisters::SD0
, dest
);
1235 void mulDouble(FPRegisterID op1
, FPRegisterID op2
, FPRegisterID dest
)
1237 m_assembler
.vmul_f64(dest
, op1
, op2
);
1240 void sqrtDouble(FPRegisterID src
, FPRegisterID dest
)
1242 m_assembler
.vsqrt_f64(dest
, src
);
1245 void absDouble(FPRegisterID src
, FPRegisterID dest
)
1247 m_assembler
.vabs_f64(dest
, src
);
1250 void negateDouble(FPRegisterID src
, FPRegisterID dest
)
1252 m_assembler
.vneg_f64(dest
, src
);
1255 void convertInt32ToDouble(RegisterID src
, FPRegisterID dest
)
1257 m_assembler
.vmov_vfp32(dest
<< 1, src
);
1258 m_assembler
.vcvt_f64_s32(dest
, dest
<< 1);
1261 void convertInt32ToDouble(Address src
, FPRegisterID dest
)
1263 load32(src
, ARMRegisters::S1
);
1264 convertInt32ToDouble(ARMRegisters::S1
, dest
);
1267 void convertInt32ToDouble(AbsoluteAddress src
, FPRegisterID dest
)
1269 move(TrustedImmPtr(src
.m_ptr
), ARMRegisters::S1
);
1270 load32(Address(ARMRegisters::S1
), ARMRegisters::S1
);
1271 convertInt32ToDouble(ARMRegisters::S1
, dest
);
1274 void convertFloatToDouble(FPRegisterID src
, FPRegisterID dst
)
1276 m_assembler
.vcvt_f64_f32(dst
, src
);
1279 void convertDoubleToFloat(FPRegisterID src
, FPRegisterID dst
)
1281 m_assembler
.vcvt_f32_f64(dst
, src
);
1284 Jump
branchDouble(DoubleCondition cond
, FPRegisterID left
, FPRegisterID right
)
1286 m_assembler
.vcmp_f64(left
, right
);
1287 m_assembler
.vmrs_apsr();
1288 if (cond
& DoubleConditionBitSpecial
)
1289 m_assembler
.cmp(ARMRegisters::S0
, ARMRegisters::S0
, ARMAssembler::VS
);
1290 return Jump(m_assembler
.jmp(static_cast<ARMAssembler::Condition
>(cond
& ~DoubleConditionMask
)));
1293 // Truncates 'src' to an integer, and places the resulting 'dest'.
1294 // If the result is not representable as a 32 bit value, branch.
1295 // May also branch for some values that are representable in 32 bits
1296 // (specifically, in this case, INT_MIN).
1297 enum BranchTruncateType
{ BranchIfTruncateFailed
, BranchIfTruncateSuccessful
};
1298 Jump
branchTruncateDoubleToInt32(FPRegisterID src
, RegisterID dest
, BranchTruncateType branchType
= BranchIfTruncateFailed
)
1300 truncateDoubleToInt32(src
, dest
);
1302 m_assembler
.add(ARMRegisters::S0
, dest
, ARMAssembler::getOp2Byte(1));
1303 m_assembler
.bic(ARMRegisters::S0
, ARMRegisters::S0
, ARMAssembler::getOp2Byte(1));
1305 ARMWord w
= ARMAssembler::getOp2(0x80000000);
1306 ASSERT(w
!= ARMAssembler::InvalidImmediate
);
1307 m_assembler
.cmp(ARMRegisters::S0
, w
);
1308 return Jump(m_assembler
.jmp(branchType
== BranchIfTruncateFailed
? ARMAssembler::EQ
: ARMAssembler::NE
));
1311 Jump
branchTruncateDoubleToUint32(FPRegisterID src
, RegisterID dest
, BranchTruncateType branchType
= BranchIfTruncateFailed
)
1313 truncateDoubleToUint32(src
, dest
);
1315 m_assembler
.add(ARMRegisters::S0
, dest
, ARMAssembler::getOp2Byte(1));
1316 m_assembler
.bic(ARMRegisters::S0
, ARMRegisters::S0
, ARMAssembler::getOp2Byte(1));
1318 m_assembler
.cmp(ARMRegisters::S0
, ARMAssembler::getOp2Byte(0));
1319 return Jump(m_assembler
.jmp(branchType
== BranchIfTruncateFailed
? ARMAssembler::EQ
: ARMAssembler::NE
));
1322 // Result is undefined if the value is outside of the integer range.
1323 void truncateDoubleToInt32(FPRegisterID src
, RegisterID dest
)
1325 m_assembler
.vcvt_s32_f64(ARMRegisters::SD0
<< 1, src
);
1326 m_assembler
.vmov_arm32(dest
, ARMRegisters::SD0
<< 1);
1329 void truncateDoubleToUint32(FPRegisterID src
, RegisterID dest
)
1331 m_assembler
.vcvt_u32_f64(ARMRegisters::SD0
<< 1, src
);
1332 m_assembler
.vmov_arm32(dest
, ARMRegisters::SD0
<< 1);
1335 // Convert 'src' to an integer, and places the resulting 'dest'.
1336 // If the result is not representable as a 32 bit value, branch.
1337 // May also branch for some values that are representable in 32 bits
1338 // (specifically, in this case, 0).
1339 void branchConvertDoubleToInt32(FPRegisterID src
, RegisterID dest
, JumpList
& failureCases
, FPRegisterID
, bool negZeroCheck
= true)
1341 m_assembler
.vcvt_s32_f64(ARMRegisters::SD0
<< 1, src
);
1342 m_assembler
.vmov_arm32(dest
, ARMRegisters::SD0
<< 1);
1344 // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
1345 m_assembler
.vcvt_f64_s32(ARMRegisters::SD0
, ARMRegisters::SD0
<< 1);
1346 failureCases
.append(branchDouble(DoubleNotEqualOrUnordered
, src
, ARMRegisters::SD0
));
1348 // If the result is zero, it might have been -0.0, and 0.0 equals to -0.0
1350 failureCases
.append(branchTest32(Zero
, dest
));
1353 Jump
branchDoubleNonZero(FPRegisterID reg
, FPRegisterID scratch
)
1355 m_assembler
.mov(ARMRegisters::S0
, ARMAssembler::getOp2Byte(0));
1356 convertInt32ToDouble(ARMRegisters::S0
, scratch
);
1357 return branchDouble(DoubleNotEqual
, reg
, scratch
);
1360 Jump
branchDoubleZeroOrNaN(FPRegisterID reg
, FPRegisterID scratch
)
1362 m_assembler
.mov(ARMRegisters::S0
, ARMAssembler::getOp2Byte(0));
1363 convertInt32ToDouble(ARMRegisters::S0
, scratch
);
1364 return branchDouble(DoubleEqualOrUnordered
, reg
, scratch
);
1367 // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc.
1368 static RelationalCondition
invert(RelationalCondition cond
)
1370 ASSERT((static_cast<uint32_t>(cond
& 0x0fffffff)) == 0 && static_cast<uint32_t>(cond
) < static_cast<uint32_t>(ARMAssembler::AL
));
1371 return static_cast<RelationalCondition
>(cond
^ 0x10000000);
1381 m_assembler
.dmbSY();
1384 static FunctionPtr
readCallTarget(CodeLocationCall call
)
1386 return FunctionPtr(reinterpret_cast<void(*)()>(ARMAssembler::readCallTarget(call
.dataLocation())));
1389 static void replaceWithJump(CodeLocationLabel instructionStart
, CodeLocationLabel destination
)
1391 ARMAssembler::replaceWithJump(instructionStart
.dataLocation(), destination
.dataLocation());
1394 static ptrdiff_t maxJumpReplacementSize()
1396 ARMAssembler::maxJumpReplacementSize();
1400 static bool canJumpReplacePatchableBranchPtrWithPatch() { return false; }
1401 static bool canJumpReplacePatchableBranch32WithPatch() { return false; }
1403 static CodeLocationLabel
startOfPatchableBranch32WithPatchOnAddress(CodeLocationDataLabel32
)
1405 UNREACHABLE_FOR_PLATFORM();
1406 return CodeLocationLabel();
1409 static CodeLocationLabel
startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr
)
1411 UNREACHABLE_FOR_PLATFORM();
1412 return CodeLocationLabel();
1415 static CodeLocationLabel
startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label
)
1417 return label
.labelAtOffset(0);
1420 static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart
, RegisterID reg
, void* initialValue
)
1422 ARMAssembler::revertBranchPtrWithPatch(instructionStart
.dataLocation(), reg
, reinterpret_cast<uintptr_t>(initialValue
) & 0xffff);
1425 static void revertJumpReplacementToPatchableBranch32WithPatch(CodeLocationLabel
, Address
, int32_t)
1427 UNREACHABLE_FOR_PLATFORM();
1430 static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel
, Address
, void*)
1432 UNREACHABLE_FOR_PLATFORM();
1437 #define DECLARE_REGISTER(_type, _regName) \
1439 FOR_EACH_CPU_REGISTER(DECLARE_REGISTER
)
1440 #undef DECLARE_REGISTER
1443 struct ProbeContext
;
1444 typedef void (*ProbeFunction
)(struct ProbeContext
*);
1446 struct ProbeContext
{
1447 ProbeFunction probeFunction
;
1452 void dump(const char* indentation
= 0);
1454 void dumpCPURegisters(const char* indentation
);
1457 // For details about probe(), see comment in MacroAssemblerX86_64.h.
1458 void probe(ProbeFunction
, void* arg1
= 0, void* arg2
= 0);
1459 #endif // USE(MASM_PROBE)
1462 ARMAssembler::Condition
ARMCondition(RelationalCondition cond
)
1464 return static_cast<ARMAssembler::Condition
>(cond
);
1467 ARMAssembler::Condition
ARMCondition(ResultCondition cond
)
1469 return static_cast<ARMAssembler::Condition
>(cond
);
1472 void ensureSpace(int insnSpace
, int constSpace
)
1474 m_assembler
.ensureSpace(insnSpace
, constSpace
);
1477 int sizeOfConstantPool()
1479 return m_assembler
.sizeOfConstantPool();
1482 void call32(RegisterID base
, int32_t offset
)
1484 load32(Address(base
, offset
), ARMRegisters::S1
);
1485 m_assembler
.blx(ARMRegisters::S1
);
1489 friend class LinkBuffer
;
1490 friend class RepatchBuffer
;
1492 void internalCompare32(RegisterID left
, TrustedImm32 right
)
1494 ARMWord tmp
= (static_cast<unsigned>(right
.m_value
) == 0x80000000) ? ARMAssembler::InvalidImmediate
: m_assembler
.getOp2(-right
.m_value
);
1495 if (tmp
!= ARMAssembler::InvalidImmediate
)
1496 m_assembler
.cmn(left
, tmp
);
1498 m_assembler
.cmp(left
, m_assembler
.getImm(right
.m_value
, ARMRegisters::S0
));
1501 static void linkCall(void* code
, Call call
, FunctionPtr function
)
1503 ARMAssembler::linkCall(code
, call
.m_label
, function
.value());
1506 static void repatchCall(CodeLocationCall call
, CodeLocationLabel destination
)
1508 ARMAssembler::relinkCall(call
.dataLocation(), destination
.executableAddress());
1511 static void repatchCall(CodeLocationCall call
, FunctionPtr destination
)
1513 ARMAssembler::relinkCall(call
.dataLocation(), destination
.executableAddress());
1517 inline TrustedImm32
trustedImm32FromPtr(void* ptr
)
1519 return TrustedImm32(TrustedImmPtr(ptr
));
1522 inline TrustedImm32
trustedImm32FromPtr(ProbeFunction function
)
1524 return TrustedImm32(TrustedImmPtr(reinterpret_cast<void*>(function
)));
1527 inline TrustedImm32
trustedImm32FromPtr(void (*function
)())
1529 return TrustedImm32(TrustedImmPtr(reinterpret_cast<void*>(function
)));
1533 static const bool s_isVFPPresent
;
1538 #endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
1540 #endif // MacroAssemblerARM_h