2 * Copyright (C) 2009 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #ifndef MacroAssemblerARMv7_h
27 #define MacroAssemblerARMv7_h
29 #include <wtf/Platform.h>
33 #include "ARMv7Assembler.h"
34 #include "AbstractMacroAssembler.h"
38 class MacroAssemblerARMv7
: public AbstractMacroAssembler
<ARMv7Assembler
> {
39 // FIXME: switch dataTempRegister & addressTempRegister, or possibly use r7?
40 // - dTR is likely used more than aTR, and we'll get better instruction
41 // encoding if it's in the low 8 registers.
42 static const ARM::RegisterID dataTempRegister
= ARM::ip
;
43 static const RegisterID addressTempRegister
= ARM::r3
;
44 static const FPRegisterID fpTempRegister
= ARM::d7
;
60 explicit ArmAddress(RegisterID base
, int32_t offset
= 0)
67 explicit ArmAddress(RegisterID base
, RegisterID index
, Scale scale
= TimesOne
)
78 static const Scale ScalePtr
= TimesFour
;
81 Equal
= ARMv7Assembler::ConditionEQ
,
82 NotEqual
= ARMv7Assembler::ConditionNE
,
83 Above
= ARMv7Assembler::ConditionHI
,
84 AboveOrEqual
= ARMv7Assembler::ConditionHS
,
85 Below
= ARMv7Assembler::ConditionLO
,
86 BelowOrEqual
= ARMv7Assembler::ConditionLS
,
87 GreaterThan
= ARMv7Assembler::ConditionGT
,
88 GreaterThanOrEqual
= ARMv7Assembler::ConditionGE
,
89 LessThan
= ARMv7Assembler::ConditionLT
,
90 LessThanOrEqual
= ARMv7Assembler::ConditionLE
,
91 Overflow
= ARMv7Assembler::ConditionVS
,
92 Signed
= ARMv7Assembler::ConditionMI
,
93 Zero
= ARMv7Assembler::ConditionEQ
,
94 NonZero
= ARMv7Assembler::ConditionNE
97 enum DoubleCondition
{
98 DoubleEqual
= ARMv7Assembler::ConditionEQ
,
99 DoubleGreaterThan
= ARMv7Assembler::ConditionGT
,
100 DoubleGreaterThanOrEqual
= ARMv7Assembler::ConditionGE
,
101 DoubleLessThan
= ARMv7Assembler::ConditionLO
,
102 DoubleLessThanOrEqual
= ARMv7Assembler::ConditionLS
,
105 static const RegisterID stackPointerRegister
= ARM::sp
;
106 static const RegisterID linkRegister
= ARM::lr
;
108 // Integer arithmetic operations:
110 // Operations are typically two operand - operation(source, srcDst)
111 // For many operations the source may be an Imm32, the srcDst operand
112 // may often be a memory location (explictly described using an Address
115 void add32(RegisterID src
, RegisterID dest
)
117 m_assembler
.add(dest
, dest
, src
);
120 void add32(Imm32 imm
, RegisterID dest
)
122 add32(imm
, dest
, dest
);
125 void add32(Imm32 imm
, RegisterID src
, RegisterID dest
)
127 ARMThumbImmediate armImm
= ARMThumbImmediate::makeUInt12OrEncodedImm(imm
.m_value
);
128 if (armImm
.isValid())
129 m_assembler
.add(dest
, src
, armImm
);
131 move(imm
, dataTempRegister
);
132 m_assembler
.add(dest
, src
, dataTempRegister
);
136 void add32(Imm32 imm
, Address address
)
138 load32(address
, dataTempRegister
);
140 ARMThumbImmediate armImm
= ARMThumbImmediate::makeUInt12OrEncodedImm(imm
.m_value
);
141 if (armImm
.isValid())
142 m_assembler
.add(dataTempRegister
, dataTempRegister
, armImm
);
144 // Hrrrm, since dataTempRegister holds the data loaded,
145 // use addressTempRegister to hold the immediate.
146 move(imm
, addressTempRegister
);
147 m_assembler
.add(dataTempRegister
, dataTempRegister
, addressTempRegister
);
150 store32(dataTempRegister
, address
);
153 void add32(Address src
, RegisterID dest
)
155 load32(src
, dataTempRegister
);
156 add32(dataTempRegister
, dest
);
159 void add32(Imm32 imm
, AbsoluteAddress address
)
161 load32(address
.m_ptr
, dataTempRegister
);
163 ARMThumbImmediate armImm
= ARMThumbImmediate::makeUInt12OrEncodedImm(imm
.m_value
);
164 if (armImm
.isValid())
165 m_assembler
.add(dataTempRegister
, dataTempRegister
, armImm
);
167 // Hrrrm, since dataTempRegister holds the data loaded,
168 // use addressTempRegister to hold the immediate.
169 move(imm
, addressTempRegister
);
170 m_assembler
.add(dataTempRegister
, dataTempRegister
, addressTempRegister
);
173 store32(dataTempRegister
, address
.m_ptr
);
176 void and32(RegisterID src
, RegisterID dest
)
178 m_assembler
.ARM_and(dest
, dest
, src
);
181 void and32(Imm32 imm
, RegisterID dest
)
183 ARMThumbImmediate armImm
= ARMThumbImmediate::makeEncodedImm(imm
.m_value
);
184 if (armImm
.isValid())
185 m_assembler
.ARM_and(dest
, dest
, armImm
);
187 move(imm
, dataTempRegister
);
188 m_assembler
.ARM_and(dest
, dest
, dataTempRegister
);
192 void lshift32(Imm32 imm
, RegisterID dest
)
194 m_assembler
.lsl(dest
, dest
, imm
.m_value
);
197 void lshift32(RegisterID shift_amount
, RegisterID dest
)
199 m_assembler
.lsl(dest
, dest
, shift_amount
);
202 void mul32(RegisterID src
, RegisterID dest
)
204 m_assembler
.smull(dest
, dataTempRegister
, dest
, src
);
207 void mul32(Imm32 imm
, RegisterID src
, RegisterID dest
)
209 move(imm
, dataTempRegister
);
210 m_assembler
.smull(dest
, dataTempRegister
, src
, dataTempRegister
);
213 void not32(RegisterID srcDest
)
215 m_assembler
.mvn(srcDest
, srcDest
);
218 void or32(RegisterID src
, RegisterID dest
)
220 m_assembler
.orr(dest
, dest
, src
);
223 void or32(Imm32 imm
, RegisterID dest
)
225 ARMThumbImmediate armImm
= ARMThumbImmediate::makeEncodedImm(imm
.m_value
);
226 if (armImm
.isValid())
227 m_assembler
.orr(dest
, dest
, armImm
);
229 move(imm
, dataTempRegister
);
230 m_assembler
.orr(dest
, dest
, dataTempRegister
);
234 void rshift32(RegisterID shift_amount
, RegisterID dest
)
236 m_assembler
.asr(dest
, dest
, shift_amount
);
239 void rshift32(Imm32 imm
, RegisterID dest
)
241 m_assembler
.asr(dest
, dest
, imm
.m_value
);
244 void sub32(RegisterID src
, RegisterID dest
)
246 m_assembler
.sub(dest
, dest
, src
);
249 void sub32(Imm32 imm
, RegisterID dest
)
251 ARMThumbImmediate armImm
= ARMThumbImmediate::makeUInt12OrEncodedImm(imm
.m_value
);
252 if (armImm
.isValid())
253 m_assembler
.sub(dest
, dest
, armImm
);
255 move(imm
, dataTempRegister
);
256 m_assembler
.sub(dest
, dest
, dataTempRegister
);
260 void sub32(Imm32 imm
, Address address
)
262 load32(address
, dataTempRegister
);
264 ARMThumbImmediate armImm
= ARMThumbImmediate::makeUInt12OrEncodedImm(imm
.m_value
);
265 if (armImm
.isValid())
266 m_assembler
.sub(dataTempRegister
, dataTempRegister
, armImm
);
268 // Hrrrm, since dataTempRegister holds the data loaded,
269 // use addressTempRegister to hold the immediate.
270 move(imm
, addressTempRegister
);
271 m_assembler
.sub(dataTempRegister
, dataTempRegister
, addressTempRegister
);
274 store32(dataTempRegister
, address
);
277 void sub32(Address src
, RegisterID dest
)
279 load32(src
, dataTempRegister
);
280 sub32(dataTempRegister
, dest
);
283 void sub32(Imm32 imm
, AbsoluteAddress address
)
285 load32(address
.m_ptr
, dataTempRegister
);
287 ARMThumbImmediate armImm
= ARMThumbImmediate::makeUInt12OrEncodedImm(imm
.m_value
);
288 if (armImm
.isValid())
289 m_assembler
.sub(dataTempRegister
, dataTempRegister
, armImm
);
291 // Hrrrm, since dataTempRegister holds the data loaded,
292 // use addressTempRegister to hold the immediate.
293 move(imm
, addressTempRegister
);
294 m_assembler
.sub(dataTempRegister
, dataTempRegister
, addressTempRegister
);
297 store32(dataTempRegister
, address
.m_ptr
);
300 void xor32(RegisterID src
, RegisterID dest
)
302 m_assembler
.eor(dest
, dest
, src
);
305 void xor32(Imm32 imm
, RegisterID dest
)
307 ARMThumbImmediate armImm
= ARMThumbImmediate::makeEncodedImm(imm
.m_value
);
308 if (armImm
.isValid())
309 m_assembler
.eor(dest
, dest
, armImm
);
311 move(imm
, dataTempRegister
);
312 m_assembler
.eor(dest
, dest
, dataTempRegister
);
317 // Memory access operations:
319 // Loads are of the form load(address, destination) and stores of the form
320 // store(source, address). The source for a store may be an Imm32. Address
321 // operand objects to loads and store will be implicitly constructed if a
322 // register is passed.
325 void load32(ArmAddress address
, RegisterID dest
)
327 if (address
.type
== ArmAddress::HasIndex
)
328 m_assembler
.ldr(dest
, address
.base
, address
.u
.index
, address
.u
.scale
);
329 else if (address
.u
.offset
>= 0) {
330 ARMThumbImmediate armImm
= ARMThumbImmediate::makeUInt12(address
.u
.offset
);
331 ASSERT(armImm
.isValid());
332 m_assembler
.ldr(dest
, address
.base
, armImm
);
334 ASSERT(address
.u
.offset
>= -255);
335 m_assembler
.ldr(dest
, address
.base
, address
.u
.offset
, true, false);
339 void load16(ArmAddress address
, RegisterID dest
)
341 if (address
.type
== ArmAddress::HasIndex
)
342 m_assembler
.ldrh(dest
, address
.base
, address
.u
.index
, address
.u
.scale
);
343 else if (address
.u
.offset
>= 0) {
344 ARMThumbImmediate armImm
= ARMThumbImmediate::makeUInt12(address
.u
.offset
);
345 ASSERT(armImm
.isValid());
346 m_assembler
.ldrh(dest
, address
.base
, armImm
);
348 ASSERT(address
.u
.offset
>= -255);
349 m_assembler
.ldrh(dest
, address
.base
, address
.u
.offset
, true, false);
353 void store32(RegisterID src
, ArmAddress address
)
355 if (address
.type
== ArmAddress::HasIndex
)
356 m_assembler
.str(src
, address
.base
, address
.u
.index
, address
.u
.scale
);
357 else if (address
.u
.offset
>= 0) {
358 ARMThumbImmediate armImm
= ARMThumbImmediate::makeUInt12(address
.u
.offset
);
359 ASSERT(armImm
.isValid());
360 m_assembler
.str(src
, address
.base
, armImm
);
362 ASSERT(address
.u
.offset
>= -255);
363 m_assembler
.str(src
, address
.base
, address
.u
.offset
, true, false);
368 void load32(ImplicitAddress address
, RegisterID dest
)
370 load32(setupArmAddress(address
), dest
);
373 void load32(BaseIndex address
, RegisterID dest
)
375 load32(setupArmAddress(address
), dest
);
378 void load32(void* address
, RegisterID dest
)
380 move(ImmPtr(address
), addressTempRegister
);
381 m_assembler
.ldr(dest
, addressTempRegister
, ARMThumbImmediate::makeUInt16(0));
384 DataLabel32
load32WithAddressOffsetPatch(Address address
, RegisterID dest
)
386 DataLabel32 label
= moveWithPatch(Imm32(address
.offset
), dataTempRegister
);
387 load32(ArmAddress(address
.base
, dataTempRegister
), dest
);
391 Label
loadPtrWithPatchToLEA(Address address
, RegisterID dest
)
394 moveFixedWidthEncoding(Imm32(address
.offset
), dataTempRegister
);
395 load32(ArmAddress(address
.base
, dataTempRegister
), dest
);
399 void load16(BaseIndex address
, RegisterID dest
)
401 m_assembler
.ldrh(dest
, makeBaseIndexBase(address
), address
.index
, address
.scale
);
404 DataLabel32
store32WithAddressOffsetPatch(RegisterID src
, Address address
)
406 DataLabel32 label
= moveWithPatch(Imm32(address
.offset
), dataTempRegister
);
407 store32(src
, ArmAddress(address
.base
, dataTempRegister
));
411 void store32(RegisterID src
, ImplicitAddress address
)
413 store32(src
, setupArmAddress(address
));
416 void store32(RegisterID src
, BaseIndex address
)
418 store32(src
, setupArmAddress(address
));
421 void store32(Imm32 imm
, ImplicitAddress address
)
423 move(imm
, dataTempRegister
);
424 store32(dataTempRegister
, setupArmAddress(address
));
427 void store32(RegisterID src
, void* address
)
429 move(ImmPtr(address
), addressTempRegister
);
430 m_assembler
.str(src
, addressTempRegister
, ARMThumbImmediate::makeUInt16(0));
433 void store32(Imm32 imm
, void* address
)
435 move(imm
, dataTempRegister
);
436 store32(dataTempRegister
, address
);
440 // Floating-point operations:
442 bool supportsFloatingPoint() const { return true; }
443 // On x86(_64) the MacroAssembler provides an interface to truncate a double to an integer.
444 // If a value is not representable as an integer, and possibly for some values that are,
445 // (on x86 INT_MIN, since this is indistinguishable from results for out-of-range/NaN input)
446 // a branch will be taken. It is not clear whether this interface will be well suited to
447 // other platforms. On ARMv7 the hardware truncation operation produces multiple possible
448 // failure values (saturates to INT_MIN & INT_MAX, NaN reulsts in a value of 0). This is a
449 // temporary solution while we work out what this interface should be. Either we need to
450 // decide to make this interface work on all platforms, rework the interface to make it more
451 // generic, or decide that the MacroAssembler cannot practically be used to abstracted these
452 // operations, and make clients go directly to the m_assembler to plant truncation instructions.
454 bool supportsFloatingPointTruncate() const { return false; }
456 void loadDouble(ImplicitAddress address
, FPRegisterID dest
)
458 RegisterID base
= address
.base
;
459 int32_t offset
= address
.offset
;
461 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
462 if ((offset
& 3) || (offset
> (255 * 4)) || (offset
< -(255 * 4))) {
463 add32(Imm32(offset
), base
, addressTempRegister
);
464 base
= addressTempRegister
;
468 m_assembler
.vldr(dest
, base
, offset
);
471 void storeDouble(FPRegisterID src
, ImplicitAddress address
)
473 RegisterID base
= address
.base
;
474 int32_t offset
= address
.offset
;
476 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
477 if ((offset
& 3) || (offset
> (255 * 4)) || (offset
< -(255 * 4))) {
478 add32(Imm32(offset
), base
, addressTempRegister
);
479 base
= addressTempRegister
;
483 m_assembler
.vstr(src
, base
, offset
);
486 void addDouble(FPRegisterID src
, FPRegisterID dest
)
488 m_assembler
.vadd_F64(dest
, dest
, src
);
491 void addDouble(Address src
, FPRegisterID dest
)
493 loadDouble(src
, fpTempRegister
);
494 addDouble(fpTempRegister
, dest
);
497 void subDouble(FPRegisterID src
, FPRegisterID dest
)
499 m_assembler
.vsub_F64(dest
, dest
, src
);
502 void subDouble(Address src
, FPRegisterID dest
)
504 loadDouble(src
, fpTempRegister
);
505 subDouble(fpTempRegister
, dest
);
508 void mulDouble(FPRegisterID src
, FPRegisterID dest
)
510 m_assembler
.vmul_F64(dest
, dest
, src
);
513 void mulDouble(Address src
, FPRegisterID dest
)
515 loadDouble(src
, fpTempRegister
);
516 mulDouble(fpTempRegister
, dest
);
519 void convertInt32ToDouble(RegisterID src
, FPRegisterID dest
)
521 m_assembler
.vmov(fpTempRegister
, src
);
522 m_assembler
.vcvt_F64_S32(dest
, fpTempRegister
);
525 Jump
branchDouble(DoubleCondition cond
, FPRegisterID left
, FPRegisterID right
)
527 m_assembler
.vcmp_F64(left
, right
);
528 m_assembler
.vmrs_APSR_nzcv_FPSCR();
529 return makeBranch(cond
);
532 Jump
branchTruncateDoubleToInt32(FPRegisterID
, RegisterID
)
534 ASSERT_NOT_REACHED();
538 // Stack manipulation operations:
540 // The ABI is assumed to provide a stack abstraction to memory,
541 // containing machine word sized units of data. Push and pop
542 // operations add and remove a single register sized unit of data
543 // to or from the stack. Peek and poke operations read or write
544 // values on the stack, without moving the current stack position.
546 void pop(RegisterID dest
)
548 // store postindexed with writeback
549 m_assembler
.ldr(dest
, ARM::sp
, sizeof(void*), false, true);
552 void push(RegisterID src
)
554 // store preindexed with writeback
555 m_assembler
.str(src
, ARM::sp
, -sizeof(void*), true, true);
558 void push(Address address
)
560 load32(address
, dataTempRegister
);
561 push(dataTempRegister
);
566 move(imm
, dataTempRegister
);
567 push(dataTempRegister
);
570 // Register move operations:
572 // Move values in registers.
574 void move(Imm32 imm
, RegisterID dest
)
576 uint32_t value
= imm
.m_value
;
579 moveFixedWidthEncoding(imm
, dest
);
581 ARMThumbImmediate armImm
= ARMThumbImmediate::makeEncodedImm(value
);
583 if (armImm
.isValid())
584 m_assembler
.mov(dest
, armImm
);
585 else if ((armImm
= ARMThumbImmediate::makeEncodedImm(~value
)).isValid())
586 m_assembler
.mvn(dest
, armImm
);
588 m_assembler
.mov(dest
, ARMThumbImmediate::makeUInt16(value
));
589 if (value
& 0xffff0000)
590 m_assembler
.movt(dest
, ARMThumbImmediate::makeUInt16(value
>> 16));
595 void move(RegisterID src
, RegisterID dest
)
597 m_assembler
.mov(dest
, src
);
600 void move(ImmPtr imm
, RegisterID dest
)
602 move(Imm32(imm
), dest
);
605 void swap(RegisterID reg1
, RegisterID reg2
)
607 move(reg1
, dataTempRegister
);
609 move(dataTempRegister
, reg2
);
612 void signExtend32ToPtr(RegisterID src
, RegisterID dest
)
618 void zeroExtend32ToPtr(RegisterID src
, RegisterID dest
)
625 // Forwards / external control flow operations:
627 // This set of jump and conditional branch operations return a Jump
628 // object which may linked at a later point, allow forwards jump,
629 // or jumps that will require external linkage (after the code has been
632 // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
633 // respecitvely, for unsigned comparisons the names b, a, be, and ae are
634 // used (representing the names 'below' and 'above').
636 // Operands to the comparision are provided in the expected order, e.g.
637 // jle32(reg1, Imm32(5)) will branch if the value held in reg1, when
638 // treated as a signed 32bit value, is less than or equal to 5.
640 // jz and jnz test whether the first operand is equal to zero, and take
641 // an optional second operand of a mask under which to perform the test.
644 // Should we be using TEQ for equal/not-equal?
645 void compare32(RegisterID left
, Imm32 right
)
647 int32_t imm
= right
.m_value
;
649 m_assembler
.tst(left
, left
);
651 ARMThumbImmediate armImm
= ARMThumbImmediate::makeEncodedImm(imm
);
652 if (armImm
.isValid())
653 m_assembler
.cmp(left
, armImm
);
654 if ((armImm
= ARMThumbImmediate::makeEncodedImm(-imm
)).isValid())
655 m_assembler
.cmn(left
, armImm
);
657 move(Imm32(imm
), dataTempRegister
);
658 m_assembler
.cmp(left
, dataTempRegister
);
663 void test32(RegisterID reg
, Imm32 mask
)
665 int32_t imm
= mask
.m_value
;
668 m_assembler
.tst(reg
, reg
);
670 ARMThumbImmediate armImm
= ARMThumbImmediate::makeEncodedImm(imm
);
671 if (armImm
.isValid())
672 m_assembler
.tst(reg
, armImm
);
674 move(mask
, dataTempRegister
);
675 m_assembler
.tst(reg
, dataTempRegister
);
681 Jump
branch32(Condition cond
, RegisterID left
, RegisterID right
)
683 m_assembler
.cmp(left
, right
);
684 return Jump(makeBranch(cond
));
687 Jump
branch32(Condition cond
, RegisterID left
, Imm32 right
)
689 compare32(left
, right
);
690 return Jump(makeBranch(cond
));
693 Jump
branch32(Condition cond
, RegisterID left
, Address right
)
695 load32(right
, dataTempRegister
);
696 return branch32(cond
, left
, dataTempRegister
);
699 Jump
branch32(Condition cond
, Address left
, RegisterID right
)
701 load32(left
, dataTempRegister
);
702 return branch32(cond
, dataTempRegister
, right
);
705 Jump
branch32(Condition cond
, Address left
, Imm32 right
)
707 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
708 load32(left
, addressTempRegister
);
709 return branch32(cond
, addressTempRegister
, right
);
712 Jump
branch32(Condition cond
, BaseIndex left
, Imm32 right
)
714 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
715 load32(left
, addressTempRegister
);
716 return branch32(cond
, addressTempRegister
, right
);
719 Jump
branch32(Condition cond
, AbsoluteAddress left
, RegisterID right
)
721 load32(left
.m_ptr
, dataTempRegister
);
722 return branch32(cond
, dataTempRegister
, right
);
725 Jump
branch32(Condition cond
, AbsoluteAddress left
, Imm32 right
)
727 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
728 load32(left
.m_ptr
, addressTempRegister
);
729 return branch32(cond
, addressTempRegister
, right
);
732 Jump
branch16(Condition cond
, BaseIndex left
, RegisterID right
)
734 load16(left
, dataTempRegister
);
735 m_assembler
.lsl(addressTempRegister
, right
, 16);
736 m_assembler
.lsl(dataTempRegister
, dataTempRegister
, 16);
737 return branch32(cond
, dataTempRegister
, addressTempRegister
);
740 Jump
branch16(Condition cond
, BaseIndex left
, Imm32 right
)
742 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
743 load16(left
, addressTempRegister
);
744 m_assembler
.lsl(addressTempRegister
, addressTempRegister
, 16);
745 return branch32(cond
, addressTempRegister
, Imm32(right
.m_value
<< 16));
748 Jump
branchTest32(Condition cond
, RegisterID reg
, RegisterID mask
)
750 ASSERT((cond
== Zero
) || (cond
== NonZero
));
751 m_assembler
.tst(reg
, mask
);
752 return Jump(makeBranch(cond
));
755 Jump
branchTest32(Condition cond
, RegisterID reg
, Imm32 mask
= Imm32(-1))
757 ASSERT((cond
== Zero
) || (cond
== NonZero
));
759 return Jump(makeBranch(cond
));
762 Jump
branchTest32(Condition cond
, Address address
, Imm32 mask
= Imm32(-1))
764 ASSERT((cond
== Zero
) || (cond
== NonZero
));
765 // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
766 load32(address
, addressTempRegister
);
767 return branchTest32(cond
, addressTempRegister
, mask
);
770 Jump
branchTest32(Condition cond
, BaseIndex address
, Imm32 mask
= Imm32(-1))
772 ASSERT((cond
== Zero
) || (cond
== NonZero
));
773 // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
774 load32(address
, addressTempRegister
);
775 return branchTest32(cond
, addressTempRegister
, mask
);
780 return Jump(makeJump());
783 void jump(RegisterID target
)
785 m_assembler
.bx(target
);
788 // Address is a memory location containing the address to jump to
789 void jump(Address address
)
791 load32(address
, dataTempRegister
);
792 m_assembler
.bx(dataTempRegister
);
796 // Arithmetic control flow operations:
798 // This set of conditional branch operations branch based
799 // on the result of an arithmetic operation. The operation
800 // is performed as normal, storing the result.
802 // * jz operations branch if the result is zero.
803 // * jo operations branch if the (signed) arithmetic
804 // operation caused an overflow to occur.
806 Jump
branchAdd32(Condition cond
, RegisterID src
, RegisterID dest
)
808 ASSERT((cond
== Overflow
) || (cond
== Signed
) || (cond
== Zero
) || (cond
== NonZero
));
809 m_assembler
.add_S(dest
, dest
, src
);
810 return Jump(makeBranch(cond
));
813 Jump
branchAdd32(Condition cond
, Imm32 imm
, RegisterID dest
)
815 ASSERT((cond
== Overflow
) || (cond
== Signed
) || (cond
== Zero
) || (cond
== NonZero
));
816 ARMThumbImmediate armImm
= ARMThumbImmediate::makeEncodedImm(imm
.m_value
);
817 if (armImm
.isValid())
818 m_assembler
.add_S(dest
, dest
, armImm
);
820 move(imm
, dataTempRegister
);
821 m_assembler
.add_S(dest
, dest
, dataTempRegister
);
823 return Jump(makeBranch(cond
));
826 Jump
branchMul32(Condition cond
, RegisterID src
, RegisterID dest
)
828 ASSERT(cond
== Overflow
);
829 m_assembler
.smull(dest
, dataTempRegister
, dest
, src
);
830 m_assembler
.asr(addressTempRegister
, dest
, 31);
831 return branch32(NotEqual
, addressTempRegister
, dataTempRegister
);
834 Jump
branchMul32(Condition cond
, Imm32 imm
, RegisterID src
, RegisterID dest
)
836 ASSERT(cond
== Overflow
);
837 move(imm
, dataTempRegister
);
838 m_assembler
.smull(dest
, dataTempRegister
, src
, dataTempRegister
);
839 m_assembler
.asr(addressTempRegister
, dest
, 31);
840 return branch32(NotEqual
, addressTempRegister
, dataTempRegister
);
843 Jump
branchSub32(Condition cond
, RegisterID src
, RegisterID dest
)
845 ASSERT((cond
== Overflow
) || (cond
== Signed
) || (cond
== Zero
) || (cond
== NonZero
));
846 m_assembler
.sub_S(dest
, dest
, src
);
847 return Jump(makeBranch(cond
));
850 Jump
branchSub32(Condition cond
, Imm32 imm
, RegisterID dest
)
852 ASSERT((cond
== Overflow
) || (cond
== Signed
) || (cond
== Zero
) || (cond
== NonZero
));
853 ARMThumbImmediate armImm
= ARMThumbImmediate::makeEncodedImm(imm
.m_value
);
854 if (armImm
.isValid())
855 m_assembler
.sub_S(dest
, dest
, armImm
);
857 move(imm
, dataTempRegister
);
858 m_assembler
.sub_S(dest
, dest
, dataTempRegister
);
860 return Jump(makeBranch(cond
));
864 // Miscellaneous operations:
873 moveFixedWidthEncoding(Imm32(0), dataTempRegister
);
874 return Call(m_assembler
.blx(dataTempRegister
), Call::LinkableNear
);
879 moveFixedWidthEncoding(Imm32(0), dataTempRegister
);
880 return Call(m_assembler
.blx(dataTempRegister
), Call::Linkable
);
883 Call
call(RegisterID target
)
885 return Call(m_assembler
.blx(target
), Call::None
);
888 Call
call(Address address
)
890 load32(address
, dataTempRegister
);
891 return Call(m_assembler
.blx(dataTempRegister
), Call::None
);
896 m_assembler
.bx(linkRegister
);
899 void set32(Condition cond
, RegisterID left
, RegisterID right
, RegisterID dest
)
901 m_assembler
.cmp(left
, right
);
902 m_assembler
.it(armV7Condition(cond
), false);
903 m_assembler
.mov(dest
, ARMThumbImmediate::makeUInt16(1));
904 m_assembler
.mov(dest
, ARMThumbImmediate::makeUInt16(0));
907 void set32(Condition cond
, RegisterID left
, Imm32 right
, RegisterID dest
)
909 compare32(left
, right
);
910 m_assembler
.it(armV7Condition(cond
), false);
911 m_assembler
.mov(dest
, ARMThumbImmediate::makeUInt16(1));
912 m_assembler
.mov(dest
, ARMThumbImmediate::makeUInt16(0));
916 // The mask should be optional... paerhaps the argument order should be
917 // dest-src, operations always have a dest? ... possibly not true, considering
918 // asm ops like test, or pseudo ops like pop().
919 void setTest32(Condition cond
, Address address
, Imm32 mask
, RegisterID dest
)
921 load32(address
, dataTempRegister
);
922 test32(dataTempRegister
, mask
);
923 m_assembler
.it(armV7Condition(cond
), false);
924 m_assembler
.mov(dest
, ARMThumbImmediate::makeUInt16(1));
925 m_assembler
.mov(dest
, ARMThumbImmediate::makeUInt16(0));
929 DataLabel32
moveWithPatch(Imm32 imm
, RegisterID dst
)
931 moveFixedWidthEncoding(imm
, dst
);
932 return DataLabel32(this);
935 DataLabelPtr
moveWithPatch(ImmPtr imm
, RegisterID dst
)
937 moveFixedWidthEncoding(Imm32(imm
), dst
);
938 return DataLabelPtr(this);
941 Jump
branchPtrWithPatch(Condition cond
, RegisterID left
, DataLabelPtr
& dataLabel
, ImmPtr initialRightValue
= ImmPtr(0))
943 dataLabel
= moveWithPatch(initialRightValue
, dataTempRegister
);
944 return branch32(cond
, left
, dataTempRegister
);
947 Jump
branchPtrWithPatch(Condition cond
, Address left
, DataLabelPtr
& dataLabel
, ImmPtr initialRightValue
= ImmPtr(0))
949 load32(left
, addressTempRegister
);
950 dataLabel
= moveWithPatch(initialRightValue
, dataTempRegister
);
951 return branch32(cond
, addressTempRegister
, dataTempRegister
);
954 DataLabelPtr
storePtrWithPatch(ImmPtr initialValue
, ImplicitAddress address
)
956 DataLabelPtr label
= moveWithPatch(initialValue
, dataTempRegister
);
957 store32(dataTempRegister
, address
);
960 DataLabelPtr
storePtrWithPatch(ImplicitAddress address
) { return storePtrWithPatch(ImmPtr(0), address
); }
963 Call
tailRecursiveCall()
965 // Like a normal call, but don't link.
966 moveFixedWidthEncoding(Imm32(0), dataTempRegister
);
967 return Call(m_assembler
.bx(dataTempRegister
), Call::Linkable
);
970 Call
makeTailRecursiveCall(Jump oldJump
)
973 return tailRecursiveCall();
978 ARMv7Assembler::JmpSrc
makeJump()
980 return m_assembler
.b();
983 ARMv7Assembler::JmpSrc
makeBranch(ARMv7Assembler::Condition cond
)
985 m_assembler
.it(cond
);
986 return m_assembler
.b();
988 ARMv7Assembler::JmpSrc
makeBranch(Condition cond
) { return makeBranch(armV7Condition(cond
)); }
989 ARMv7Assembler::JmpSrc
makeBranch(DoubleCondition cond
) { return makeBranch(armV7Condition(cond
)); }
991 ArmAddress
setupArmAddress(BaseIndex address
)
993 if (address
.offset
) {
994 ARMThumbImmediate imm
= ARMThumbImmediate::makeUInt12OrEncodedImm(address
.offset
);
996 m_assembler
.add(addressTempRegister
, address
.base
, imm
);
998 move(Imm32(address
.offset
), addressTempRegister
);
999 m_assembler
.add(addressTempRegister
, addressTempRegister
, address
.base
);
1002 return ArmAddress(addressTempRegister
, address
.index
, address
.scale
);
1004 return ArmAddress(address
.base
, address
.index
, address
.scale
);
1007 ArmAddress
setupArmAddress(Address address
)
1009 if ((address
.offset
>= -0xff) && (address
.offset
<= 0xfff))
1010 return ArmAddress(address
.base
, address
.offset
);
1012 move(Imm32(address
.offset
), addressTempRegister
);
1013 return ArmAddress(address
.base
, addressTempRegister
);
1016 ArmAddress
setupArmAddress(ImplicitAddress address
)
1018 if ((address
.offset
>= -0xff) && (address
.offset
<= 0xfff))
1019 return ArmAddress(address
.base
, address
.offset
);
1021 move(Imm32(address
.offset
), addressTempRegister
);
1022 return ArmAddress(address
.base
, addressTempRegister
);
1025 RegisterID
makeBaseIndexBase(BaseIndex address
)
1027 if (!address
.offset
)
1028 return address
.base
;
1030 ARMThumbImmediate imm
= ARMThumbImmediate::makeUInt12OrEncodedImm(address
.offset
);
1032 m_assembler
.add(addressTempRegister
, address
.base
, imm
);
1034 move(Imm32(address
.offset
), addressTempRegister
);
1035 m_assembler
.add(addressTempRegister
, addressTempRegister
, address
.base
);
1038 return addressTempRegister
;
1041 DataLabel32
moveFixedWidthEncoding(Imm32 imm
, RegisterID dst
)
1043 uint32_t value
= imm
.m_value
;
1044 m_assembler
.movT3(dst
, ARMThumbImmediate::makeUInt16(value
& 0xffff));
1045 m_assembler
.movt(dst
, ARMThumbImmediate::makeUInt16(value
>> 16));
1048 ARMv7Assembler::Condition
armV7Condition(Condition cond
)
1050 return static_cast<ARMv7Assembler::Condition
>(cond
);
1053 ARMv7Assembler::Condition
armV7Condition(DoubleCondition cond
)
1055 return static_cast<ARMv7Assembler::Condition
>(cond
);
1059 friend class LinkBuffer
;
1060 friend class RepatchBuffer
;
1062 static void linkCall(void* code
, Call call
, FunctionPtr function
)
1064 ARMv7Assembler::linkCall(code
, call
.m_jmp
, function
.value());
1067 static void repatchCall(CodeLocationCall call
, CodeLocationLabel destination
)
1069 ARMv7Assembler::relinkCall(call
.dataLocation(), destination
.executableAddress());
1072 static void repatchCall(CodeLocationCall call
, FunctionPtr destination
)
1074 ARMv7Assembler::relinkCall(call
.dataLocation(), destination
.executableAddress());
1080 #endif // ENABLE(ASSEMBLER)
1082 #endif // MacroAssemblerARMv7_h