1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=79:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Copyright (C) 2009 Apple Inc. All rights reserved.
6 * Copyright (C) 2010 University of Szeged
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * ***** END LICENSE BLOCK ***** */
31 #ifndef MacroAssemblerARMv7_h
32 #define MacroAssemblerARMv7_h
34 #include "assembler/wtf/Platform.h"
38 #include "ARMv7Assembler.h"
39 #include "AbstractMacroAssembler.h"
43 class MacroAssemblerARMv7 : public AbstractMacroAssembler<ARMv7Assembler> {
44 // FIXME: switch dataTempRegister & addressTempRegister, or possibly use r7?
45 // - dTR is likely used more than aTR, and we'll get better instruction
46 // encoding if it's in the low 8 registers.
47 static const ARMRegisters::RegisterID dataTempRegister = ARMRegisters::ip;
48 static const RegisterID addressTempRegister = ARMRegisters::r3;
49 static const FPRegisterID fpTempRegister = ARMRegisters::d7;
50 static const unsigned int TotalRegisters = 16;
66 explicit ArmAddress(RegisterID base, int32_t offset = 0)
73 explicit ArmAddress(RegisterID base, RegisterID index, Scale scale = TimesOne)
84 static const Scale ScalePtr = TimesFour;
87 Equal = ARMv7Assembler::ConditionEQ,
88 NotEqual = ARMv7Assembler::ConditionNE,
89 Above = ARMv7Assembler::ConditionHI,
90 AboveOrEqual = ARMv7Assembler::ConditionHS,
91 Below = ARMv7Assembler::ConditionLO,
92 BelowOrEqual = ARMv7Assembler::ConditionLS,
93 GreaterThan = ARMv7Assembler::ConditionGT,
94 GreaterThanOrEqual = ARMv7Assembler::ConditionGE,
95 LessThan = ARMv7Assembler::ConditionLT,
96 LessThanOrEqual = ARMv7Assembler::ConditionLE,
97 Overflow = ARMv7Assembler::ConditionVS,
98 Signed = ARMv7Assembler::ConditionMI,
99 Zero = ARMv7Assembler::ConditionEQ,
100 NonZero = ARMv7Assembler::ConditionNE
102 enum DoubleCondition {
103 // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
104 DoubleEqual = ARMv7Assembler::ConditionEQ,
105 DoubleNotEqual = ARMv7Assembler::ConditionVC, // Not the right flag! check for this & handle differently.
106 DoubleGreaterThan = ARMv7Assembler::ConditionGT,
107 DoubleGreaterThanOrEqual = ARMv7Assembler::ConditionGE,
108 DoubleLessThan = ARMv7Assembler::ConditionLO,
109 DoubleLessThanOrEqual = ARMv7Assembler::ConditionLS,
110 // If either operand is NaN, these conditions always evaluate to true.
111 DoubleEqualOrUnordered = ARMv7Assembler::ConditionVS, // Not the right flag! check for this & handle differently.
112 DoubleNotEqualOrUnordered = ARMv7Assembler::ConditionNE,
113 DoubleGreaterThanOrUnordered = ARMv7Assembler::ConditionHI,
114 DoubleGreaterThanOrEqualOrUnordered = ARMv7Assembler::ConditionHS,
115 DoubleLessThanOrUnordered = ARMv7Assembler::ConditionLT,
116 DoubleLessThanOrEqualOrUnordered = ARMv7Assembler::ConditionLE,
119 static const RegisterID stackPointerRegister = ARMRegisters::sp;
120 static const RegisterID linkRegister = ARMRegisters::lr;
122 // Integer arithmetic operations:
124 // Operations are typically two operand - operation(source, srcDst)
125 // For many operations the source may be an Imm32, the srcDst operand
126 // may often be a memory location (explictly described using an Address
129 void add32(RegisterID src, RegisterID dest)
131 m_assembler.add(dest, dest, src);
134 void add32(Imm32 imm, RegisterID dest)
136 add32(imm, dest, dest);
139 void add32(Imm32 imm, RegisterID src, RegisterID dest)
141 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
142 if (armImm.isValid())
143 m_assembler.add(dest, src, armImm);
145 move(imm, dataTempRegister);
146 m_assembler.add(dest, src, dataTempRegister);
150 void add32(Imm32 imm, Address address)
152 load32(address, dataTempRegister);
154 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
155 if (armImm.isValid())
156 m_assembler.add(dataTempRegister, dataTempRegister, armImm);
158 // Hrrrm, since dataTempRegister holds the data loaded,
159 // use addressTempRegister to hold the immediate.
160 move(imm, addressTempRegister);
161 m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister);
164 store32(dataTempRegister, address);
167 void add32(Address src, RegisterID dest)
169 load32(src, dataTempRegister);
170 add32(dataTempRegister, dest);
173 void add32(Imm32 imm, AbsoluteAddress address)
175 load32(address.m_ptr, dataTempRegister);
177 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
178 if (armImm.isValid())
179 m_assembler.add(dataTempRegister, dataTempRegister, armImm);
181 // Hrrrm, since dataTempRegister holds the data loaded,
182 // use addressTempRegister to hold the immediate.
183 move(imm, addressTempRegister);
184 m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister);
187 store32(dataTempRegister, address.m_ptr);
190 void and32(RegisterID src, RegisterID dest)
192 m_assembler.ARM_and(dest, dest, src);
195 void and32(Imm32 imm, RegisterID dest)
197 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
198 if (armImm.isValid())
199 m_assembler.ARM_and(dest, dest, armImm);
201 move(imm, dataTempRegister);
202 m_assembler.ARM_and(dest, dest, dataTempRegister);
206 void lshift32(RegisterID shift_amount, RegisterID dest)
208 // Clamp the shift to the range 0..31
209 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
210 ASSERT(armImm.isValid());
211 m_assembler.ARM_and(dataTempRegister, shift_amount, armImm);
213 m_assembler.lsl(dest, dest, dataTempRegister);
216 void lshift32(Imm32 imm, RegisterID dest)
218 m_assembler.lsl(dest, dest, imm.m_value & 0x1f);
221 void mul32(RegisterID src, RegisterID dest)
223 m_assembler.smull(dest, dataTempRegister, dest, src);
226 void mul32(Imm32 imm, RegisterID src, RegisterID dest)
228 move(imm, dataTempRegister);
229 m_assembler.smull(dest, dataTempRegister, src, dataTempRegister);
232 void not32(RegisterID srcDest)
234 m_assembler.mvn(srcDest, srcDest);
237 void or32(RegisterID src, RegisterID dest)
239 m_assembler.orr(dest, dest, src);
242 void or32(Imm32 imm, RegisterID dest)
244 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
245 if (armImm.isValid())
246 m_assembler.orr(dest, dest, armImm);
248 move(imm, dataTempRegister);
249 m_assembler.orr(dest, dest, dataTempRegister);
253 void rshift32(RegisterID shift_amount, RegisterID dest)
255 // Clamp the shift to the range 0..31
256 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
257 ASSERT(armImm.isValid());
258 m_assembler.ARM_and(dataTempRegister, shift_amount, armImm);
260 m_assembler.asr(dest, dest, dataTempRegister);
263 void rshift32(Imm32 imm, RegisterID dest)
265 m_assembler.asr(dest, dest, imm.m_value & 0x1f);
268 void urshift32(RegisterID shift_amount, RegisterID dest)
270 // Clamp the shift to the range 0..31
271 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
272 ASSERT(armImm.isValid());
273 m_assembler.ARM_and(dataTempRegister, shift_amount, armImm);
275 m_assembler.lsr(dest, dest, dataTempRegister);
278 void urshift32(Imm32 imm, RegisterID dest)
280 m_assembler.lsr(dest, dest, imm.m_value & 0x1f);
283 void sub32(RegisterID src, RegisterID dest)
285 m_assembler.sub(dest, dest, src);
288 void sub32(Imm32 imm, RegisterID dest)
290 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
291 if (armImm.isValid())
292 m_assembler.sub(dest, dest, armImm);
294 move(imm, dataTempRegister);
295 m_assembler.sub(dest, dest, dataTempRegister);
299 void sub32(Imm32 imm, Address address)
301 load32(address, dataTempRegister);
303 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
304 if (armImm.isValid())
305 m_assembler.sub(dataTempRegister, dataTempRegister, armImm);
307 // Hrrrm, since dataTempRegister holds the data loaded,
308 // use addressTempRegister to hold the immediate.
309 move(imm, addressTempRegister);
310 m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister);
313 store32(dataTempRegister, address);
316 void sub32(Address src, RegisterID dest)
318 load32(src, dataTempRegister);
319 sub32(dataTempRegister, dest);
322 void sub32(Imm32 imm, AbsoluteAddress address)
324 load32(address.m_ptr, dataTempRegister);
326 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
327 if (armImm.isValid())
328 m_assembler.sub(dataTempRegister, dataTempRegister, armImm);
330 // Hrrrm, since dataTempRegister holds the data loaded,
331 // use addressTempRegister to hold the immediate.
332 move(imm, addressTempRegister);
333 m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister);
336 store32(dataTempRegister, address.m_ptr);
339 void xor32(RegisterID src, RegisterID dest)
341 m_assembler.eor(dest, dest, src);
344 void xor32(Imm32 imm, RegisterID dest)
346 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
347 if (armImm.isValid())
348 m_assembler.eor(dest, dest, armImm);
350 move(imm, dataTempRegister);
351 m_assembler.eor(dest, dest, dataTempRegister);
356 // Memory access operations:
358 // Loads are of the form load(address, destination) and stores of the form
359 // store(source, address). The source for a store may be an Imm32. Address
360 // operand objects to loads and store will be implicitly constructed if a
361 // register is passed.
364 void load32(ArmAddress address, RegisterID dest)
366 if (address.type == ArmAddress::HasIndex)
367 m_assembler.ldr(dest, address.base, address.u.index, address.u.scale);
368 else if (address.u.offset >= 0) {
369 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
370 ASSERT(armImm.isValid());
371 m_assembler.ldr(dest, address.base, armImm);
373 ASSERT(address.u.offset >= -255);
374 m_assembler.ldr(dest, address.base, address.u.offset, true, false);
378 void load16(ArmAddress address, RegisterID dest)
380 if (address.type == ArmAddress::HasIndex)
381 m_assembler.ldrh(dest, address.base, address.u.index, address.u.scale);
382 else if (address.u.offset >= 0) {
383 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
384 ASSERT(armImm.isValid());
385 m_assembler.ldrh(dest, address.base, armImm);
387 ASSERT(address.u.offset >= -255);
388 m_assembler.ldrh(dest, address.base, address.u.offset, true, false);
392 void load8(ArmAddress address, RegisterID dest)
394 if (address.type == ArmAddress::HasIndex)
395 m_assembler.ldrb(dest, address.base, address.u.index, address.u.scale);
396 else if (address.u.offset >= 0) {
397 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
398 ASSERT(armImm.isValid());
399 m_assembler.ldrb(dest, address.base, armImm);
401 ASSERT(address.u.offset >= -255);
402 m_assembler.ldrb(dest, address.base, address.u.offset, true, false);
406 void store32(RegisterID src, ArmAddress address)
408 if (address.type == ArmAddress::HasIndex)
409 m_assembler.str(src, address.base, address.u.index, address.u.scale);
410 else if (address.u.offset >= 0) {
411 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
412 ASSERT(armImm.isValid());
413 m_assembler.str(src, address.base, armImm);
415 ASSERT(address.u.offset >= -255);
416 m_assembler.str(src, address.base, address.u.offset, true, false);
421 void load32(ImplicitAddress address, RegisterID dest)
423 load32(setupArmAddress(address), dest);
426 void load32(BaseIndex address, RegisterID dest)
428 load32(setupArmAddress(address), dest);
431 void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
433 load32(setupArmAddress(address), dest);
436 void load32(void* address, RegisterID dest)
438 move(ImmPtr(address), addressTempRegister);
439 m_assembler.ldr(dest, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
442 void load8(ImplicitAddress address, RegisterID dest)
444 load8(setupArmAddress(address), dest);
447 DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
449 DataLabel32 label = moveWithPatch(Imm32(address.offset), dataTempRegister);
450 load32(ArmAddress(address.base, dataTempRegister), dest);
454 Label loadPtrWithPatchToLEA(Address address, RegisterID dest)
457 moveFixedWidthEncoding(Imm32(address.offset), dataTempRegister);
458 load32(ArmAddress(address.base, dataTempRegister), dest);
462 void load16(BaseIndex address, RegisterID dest)
464 m_assembler.ldrh(dest, makeBaseIndexBase(address), address.index, address.scale);
467 void load16(ImplicitAddress address, RegisterID dest)
469 m_assembler.ldrh(dest, address.base, address.offset);
472 DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
474 DataLabel32 label = moveWithPatch(Imm32(address.offset), dataTempRegister);
475 store32(src, ArmAddress(address.base, dataTempRegister));
479 void store32(RegisterID src, ImplicitAddress address)
481 store32(src, setupArmAddress(address));
484 void store32(RegisterID src, BaseIndex address)
486 store32(src, setupArmAddress(address));
489 void store32(Imm32 imm, ImplicitAddress address)
491 move(imm, dataTempRegister);
492 store32(dataTempRegister, setupArmAddress(address));
495 void store32(RegisterID src, void* address)
497 move(ImmPtr(address), addressTempRegister);
498 m_assembler.str(src, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
501 void store32(Imm32 imm, void* address)
503 move(imm, dataTempRegister);
504 store32(dataTempRegister, address);
508 // Floating-point operations:
510 bool supportsFloatingPoint() const { return true; }
511 // On x86(_64) the MacroAssembler provides an interface to truncate a double to an integer.
512 // If a value is not representable as an integer, and possibly for some values that are,
513 // (on x86 INT_MIN, since this is indistinguishable from results for out-of-range/NaN input)
514 // a branch will be taken. It is not clear whether this interface will be well suited to
515 // other platforms. On ARMv7 the hardware truncation operation produces multiple possible
516 // failure values (saturates to INT_MIN & INT_MAX, NaN reulsts in a value of 0). This is a
517 // temporary solution while we work out what this interface should be. Either we need to
518 // decide to make this interface work on all platforms, rework the interface to make it more
519 // generic, or decide that the MacroAssembler cannot practically be used to abstracted these
520 // operations, and make clients go directly to the m_assembler to plant truncation instructions.
522 bool supportsFloatingPointTruncate() const { return false; }
524 bool supportsFloatingPointSqrt() const
529 void loadDouble(ImplicitAddress address, FPRegisterID dest)
531 RegisterID base = address.base;
532 int32_t offset = address.offset;
534 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
535 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
536 add32(Imm32(offset), base, addressTempRegister);
537 base = addressTempRegister;
541 m_assembler.vldr(dest, base, offset);
544 void storeDouble(FPRegisterID src, ImplicitAddress address)
546 RegisterID base = address.base;
547 int32_t offset = address.offset;
549 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
550 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
551 add32(Imm32(offset), base, addressTempRegister);
552 base = addressTempRegister;
556 m_assembler.vstr(src, base, offset);
559 void addDouble(FPRegisterID src, FPRegisterID dest)
561 m_assembler.vadd_F64(dest, dest, src);
564 void addDouble(Address src, FPRegisterID dest)
566 loadDouble(src, fpTempRegister);
567 addDouble(fpTempRegister, dest);
570 void subDouble(FPRegisterID src, FPRegisterID dest)
572 m_assembler.vsub_F64(dest, dest, src);
575 void subDouble(Address src, FPRegisterID dest)
577 loadDouble(src, fpTempRegister);
578 subDouble(fpTempRegister, dest);
581 void mulDouble(FPRegisterID src, FPRegisterID dest)
583 m_assembler.vmul_F64(dest, dest, src);
586 void mulDouble(Address src, FPRegisterID dest)
588 loadDouble(src, fpTempRegister);
589 mulDouble(fpTempRegister, dest);
592 void sqrtDouble(FPRegisterID, FPRegisterID)
594 ASSERT_NOT_REACHED();
597 void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
599 m_assembler.vmov(fpTempRegister, src);
600 m_assembler.vcvt_F64_S32(dest, fpTempRegister);
603 Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
605 m_assembler.vcmp_F64(left, right);
606 m_assembler.vmrs_APSR_nzcv_FPSCR();
608 if (cond == DoubleNotEqual) {
609 // ConditionNE jumps if NotEqual *or* unordered - force the unordered cases not to jump.
610 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
611 Jump result = makeBranch(ARMv7Assembler::ConditionNE);
612 unordered.link(this);
615 if (cond == DoubleEqualOrUnordered) {
616 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
617 Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
618 unordered.link(this);
619 // We get here if either unordered, or equal.
620 Jump result = makeJump();
624 return makeBranch(cond);
627 Jump branchTruncateDoubleToInt32(FPRegisterID, RegisterID)
629 ASSERT_NOT_REACHED();
634 // Stack manipulation operations:
636 // The ABI is assumed to provide a stack abstraction to memory,
637 // containing machine word sized units of data. Push and pop
638 // operations add and remove a single register sized unit of data
639 // to or from the stack. Peek and poke operations read or write
640 // values on the stack, without moving the current stack position.
642 void pop(RegisterID dest)
644 // store postindexed with writeback
645 m_assembler.ldr(dest, ARMRegisters::sp, sizeof(void*), false, true);
648 void push(RegisterID src)
650 // store preindexed with writeback
651 m_assembler.str(src, ARMRegisters::sp, -sizeof(void*), true, true);
654 void push(Address address)
656 load32(address, dataTempRegister);
657 push(dataTempRegister);
662 move(imm, dataTempRegister);
663 push(dataTempRegister);
666 // Register move operations:
668 // Move values in registers.
670 void move(Imm32 imm, RegisterID dest)
672 uint32_t value = imm.m_value;
675 moveFixedWidthEncoding(imm, dest);
677 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(value);
679 if (armImm.isValid())
680 m_assembler.mov(dest, armImm);
681 else if ((armImm = ARMThumbImmediate::makeEncodedImm(~value)).isValid())
682 m_assembler.mvn(dest, armImm);
684 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(value));
685 if (value & 0xffff0000)
686 m_assembler.movt(dest, ARMThumbImmediate::makeUInt16(value >> 16));
691 void move(RegisterID src, RegisterID dest)
693 m_assembler.mov(dest, src);
696 void move(ImmPtr imm, RegisterID dest)
698 move(Imm32(imm), dest);
701 void swap(RegisterID reg1, RegisterID reg2)
703 move(reg1, dataTempRegister);
705 move(dataTempRegister, reg2);
708 void signExtend32ToPtr(RegisterID src, RegisterID dest)
714 void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
721 // Forwards / external control flow operations:
723 // This set of jump and conditional branch operations return a Jump
724 // object which may linked at a later point, allow forwards jump,
725 // or jumps that will require external linkage (after the code has been
728 // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
729 // respecitvely, for unsigned comparisons the names b, a, be, and ae are
730 // used (representing the names 'below' and 'above').
732 // Operands to the comparision are provided in the expected order, e.g.
733 // jle32(reg1, Imm32(5)) will branch if the value held in reg1, when
734 // treated as a signed 32bit value, is less than or equal to 5.
736 // jz and jnz test whether the first operand is equal to zero, and take
737 // an optional second operand of a mask under which to perform the test.
740 // Should we be using TEQ for equal/not-equal?
741 void compare32(RegisterID left, Imm32 right)
743 int32_t imm = right.m_value;
745 m_assembler.tst(left, left);
747 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
748 if (armImm.isValid())
749 m_assembler.cmp(left, armImm);
750 if ((armImm = ARMThumbImmediate::makeEncodedImm(-imm)).isValid())
751 m_assembler.cmn(left, armImm);
753 move(Imm32(imm), dataTempRegister);
754 m_assembler.cmp(left, dataTempRegister);
759 void test32(RegisterID reg, Imm32 mask)
761 int32_t imm = mask.m_value;
764 m_assembler.tst(reg, reg);
766 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
767 if (armImm.isValid())
768 m_assembler.tst(reg, armImm);
770 move(mask, dataTempRegister);
771 m_assembler.tst(reg, dataTempRegister);
777 Jump branch32(Condition cond, RegisterID left, RegisterID right)
779 m_assembler.cmp(left, right);
780 return Jump(makeBranch(cond));
783 Jump branch32(Condition cond, RegisterID left, Imm32 right)
785 compare32(left, right);
786 return Jump(makeBranch(cond));
789 Jump branch32(Condition cond, RegisterID left, Address right)
791 load32(right, dataTempRegister);
792 return branch32(cond, left, dataTempRegister);
795 Jump branch32(Condition cond, Address left, RegisterID right)
797 load32(left, dataTempRegister);
798 return branch32(cond, dataTempRegister, right);
801 Jump branch32(Condition cond, Address left, Imm32 right)
803 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
804 load32(left, addressTempRegister);
805 return branch32(cond, addressTempRegister, right);
808 Jump branch32(Condition cond, BaseIndex left, Imm32 right)
810 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
811 load32(left, addressTempRegister);
812 return branch32(cond, addressTempRegister, right);
815 Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
817 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
818 load32WithUnalignedHalfWords(left, addressTempRegister);
819 return branch32(cond, addressTempRegister, right);
822 Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right)
824 load32(left.m_ptr, dataTempRegister);
825 return branch32(cond, dataTempRegister, right);
828 Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
830 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
831 load32(left.m_ptr, addressTempRegister);
832 return branch32(cond, addressTempRegister, right);
835 Jump branch16(Condition cond, BaseIndex left, RegisterID right)
837 load16(left, dataTempRegister);
838 m_assembler.lsl(addressTempRegister, right, 16);
839 m_assembler.lsl(dataTempRegister, dataTempRegister, 16);
840 return branch32(cond, dataTempRegister, addressTempRegister);
843 Jump branch16(Condition cond, BaseIndex left, Imm32 right)
845 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
846 load16(left, addressTempRegister);
847 m_assembler.lsl(addressTempRegister, addressTempRegister, 16);
848 return branch32(cond, addressTempRegister, Imm32(right.m_value << 16));
851 Jump branch8(Condition cond, RegisterID left, Imm32 right)
853 compare32(left, right);
854 return Jump(makeBranch(cond));
857 Jump branch8(Condition cond, Address left, Imm32 right)
859 // use addressTempRegister incase the branch8 we call uses dataTempRegister. :-/
860 load8(left, addressTempRegister);
861 return branch8(cond, addressTempRegister, right);
864 Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask)
866 ASSERT((cond == Zero) || (cond == NonZero));
867 m_assembler.tst(reg, mask);
868 return Jump(makeBranch(cond));
871 Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1))
873 ASSERT((cond == Zero) || (cond == NonZero));
875 return Jump(makeBranch(cond));
878 Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1))
880 ASSERT((cond == Zero) || (cond == NonZero));
881 // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
882 load32(address, addressTempRegister);
883 return branchTest32(cond, addressTempRegister, mask);
886 Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1))
888 ASSERT((cond == Zero) || (cond == NonZero));
889 // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
890 load32(address, addressTempRegister);
891 return branchTest32(cond, addressTempRegister, mask);
894 Jump branchTest8(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1))
896 ASSERT((cond == Zero) || (cond == NonZero));
898 return Jump(makeBranch(cond));
901 Jump branchTest8(Condition cond, Address address, Imm32 mask = Imm32(-1))
903 ASSERT((cond == Zero) || (cond == NonZero));
904 // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
905 load8(address, addressTempRegister);
906 return branchTest8(cond, addressTempRegister, mask);
911 return Jump(makeJump());
914 void jump(RegisterID target)
916 m_assembler.bx(target);
919 // Address is a memory location containing the address to jump to
920 void jump(Address address)
922 load32(address, dataTempRegister);
923 m_assembler.bx(dataTempRegister);
927 // Arithmetic control flow operations:
929 // This set of conditional branch operations branch based
930 // on the result of an arithmetic operation. The operation
931 // is performed as normal, storing the result.
933 // * jz operations branch if the result is zero.
934 // * jo operations branch if the (signed) arithmetic
935 // operation caused an overflow to occur.
937 Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest)
939 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
940 m_assembler.add_S(dest, dest, src);
941 return Jump(makeBranch(cond));
944 Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest)
946 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
947 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
948 if (armImm.isValid())
949 m_assembler.add_S(dest, dest, armImm);
951 move(imm, dataTempRegister);
952 m_assembler.add_S(dest, dest, dataTempRegister);
954 return Jump(makeBranch(cond));
957 Jump branchMul32(Condition cond, RegisterID src, RegisterID dest)
959 ASSERT(cond == Overflow);
960 m_assembler.smull(dest, dataTempRegister, dest, src);
961 m_assembler.asr(addressTempRegister, dest, 31);
962 return branch32(NotEqual, addressTempRegister, dataTempRegister);
965 Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest)
967 ASSERT(cond == Overflow);
968 move(imm, dataTempRegister);
969 m_assembler.smull(dest, dataTempRegister, src, dataTempRegister);
970 m_assembler.asr(addressTempRegister, dest, 31);
971 return branch32(NotEqual, addressTempRegister, dataTempRegister);
974 Jump branchSub32(Condition cond, RegisterID src, RegisterID dest)
976 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
977 m_assembler.sub_S(dest, dest, src);
978 return Jump(makeBranch(cond));
981 Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest)
983 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
984 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
985 if (armImm.isValid())
986 m_assembler.sub_S(dest, dest, armImm);
988 move(imm, dataTempRegister);
989 m_assembler.sub_S(dest, dest, dataTempRegister);
991 return Jump(makeBranch(cond));
995 // Miscellaneous operations:
1004 moveFixedWidthEncoding(Imm32(0), dataTempRegister);
1005 return Call(m_assembler.blx(dataTempRegister), Call::LinkableNear);
1010 moveFixedWidthEncoding(Imm32(0), dataTempRegister);
1011 return Call(m_assembler.blx(dataTempRegister), Call::Linkable);
1014 Call call(RegisterID target)
1016 return Call(m_assembler.blx(target), Call::None);
1019 Call call(Address address)
1021 load32(address, dataTempRegister);
1022 return Call(m_assembler.blx(dataTempRegister), Call::None);
1027 m_assembler.bx(linkRegister);
1030 void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
1032 m_assembler.cmp(left, right);
1033 m_assembler.it(armV7Condition(cond), false);
1034 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1035 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1038 void set32(Condition cond, RegisterID left, Imm32 right, RegisterID dest)
1040 compare32(left, right);
1041 m_assembler.it(armV7Condition(cond), false);
1042 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1043 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1047 // The mask should be optional... paerhaps the argument order should be
1048 // dest-src, operations always have a dest? ... possibly not true, considering
1049 // asm ops like test, or pseudo ops like pop().
1050 void setTest32(Condition cond, Address address, Imm32 mask, RegisterID dest)
1052 load32(address, dataTempRegister);
1053 test32(dataTempRegister, mask);
1054 m_assembler.it(armV7Condition(cond), false);
1055 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1056 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1059 void setTest8(Condition cond, Address address, Imm32 mask, RegisterID dest)
1061 load8(address, dataTempRegister);
1062 test32(dataTempRegister, mask);
1063 m_assembler.it(armV7Condition(cond), false);
1064 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1065 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1068 DataLabel32 moveWithPatch(Imm32 imm, RegisterID dst)
1070 moveFixedWidthEncoding(imm, dst);
1071 return DataLabel32(this);
1074 DataLabelPtr moveWithPatch(ImmPtr imm, RegisterID dst)
1076 moveFixedWidthEncoding(Imm32(imm), dst);
1077 return DataLabelPtr(this);
1080 Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
1082 dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1083 return branch32(cond, left, dataTempRegister);
1086 Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
1088 load32(left, addressTempRegister);
1089 dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1090 return branch32(cond, addressTempRegister, dataTempRegister);
1093 DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
1095 DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister);
1096 store32(dataTempRegister, address);
1099 DataLabelPtr storePtrWithPatch(ImplicitAddress address) { return storePtrWithPatch(ImmPtr(0), address); }
1102 Call tailRecursiveCall()
1104 // Like a normal call, but don't link.
1105 moveFixedWidthEncoding(Imm32(0), dataTempRegister);
1106 return Call(m_assembler.bx(dataTempRegister), Call::Linkable);
1109 Call makeTailRecursiveCall(Jump oldJump)
1112 return tailRecursiveCall();
1117 ARMv7Assembler::JmpSrc makeJump()
1119 moveFixedWidthEncoding(Imm32(0), dataTempRegister);
1120 return m_assembler.bx(dataTempRegister);
1123 ARMv7Assembler::JmpSrc makeBranch(ARMv7Assembler::Condition cond)
1125 m_assembler.it(cond, true, true);
1126 moveFixedWidthEncoding(Imm32(0), dataTempRegister);
1127 return m_assembler.bx(dataTempRegister);
1129 ARMv7Assembler::JmpSrc makeBranch(Condition cond) { return makeBranch(armV7Condition(cond)); }
1130 ARMv7Assembler::JmpSrc makeBranch(DoubleCondition cond) { return makeBranch(armV7Condition(cond)); }
1132 ArmAddress setupArmAddress(BaseIndex address)
1134 if (address.offset) {
1135 ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
1137 m_assembler.add(addressTempRegister, address.base, imm);
1139 move(Imm32(address.offset), addressTempRegister);
1140 m_assembler.add(addressTempRegister, addressTempRegister, address.base);
1143 return ArmAddress(addressTempRegister, address.index, address.scale);
1145 return ArmAddress(address.base, address.index, address.scale);
1148 ArmAddress setupArmAddress(Address address)
1150 if ((address.offset >= -0xff) && (address.offset <= 0xfff))
1151 return ArmAddress(address.base, address.offset);
1153 move(Imm32(address.offset), addressTempRegister);
1154 return ArmAddress(address.base, addressTempRegister);
1157 ArmAddress setupArmAddress(ImplicitAddress address)
1159 if ((address.offset >= -0xff) && (address.offset <= 0xfff))
1160 return ArmAddress(address.base, address.offset);
1162 move(Imm32(address.offset), addressTempRegister);
1163 return ArmAddress(address.base, addressTempRegister);
1166 RegisterID makeBaseIndexBase(BaseIndex address)
1168 if (!address.offset)
1169 return address.base;
1171 ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
1173 m_assembler.add(addressTempRegister, address.base, imm);
1175 move(Imm32(address.offset), addressTempRegister);
1176 m_assembler.add(addressTempRegister, addressTempRegister, address.base);
1179 return addressTempRegister;
1182 void moveFixedWidthEncoding(Imm32 imm, RegisterID dst)
1184 uint32_t value = imm.m_value;
1185 m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff));
1186 m_assembler.movt(dst, ARMThumbImmediate::makeUInt16(value >> 16));
1189 ARMv7Assembler::Condition armV7Condition(Condition cond)
1191 return static_cast<ARMv7Assembler::Condition>(cond);
1194 ARMv7Assembler::Condition armV7Condition(DoubleCondition cond)
1196 return static_cast<ARMv7Assembler::Condition>(cond);
1200 friend class LinkBuffer;
1201 friend class RepatchBuffer;
1203 static void linkCall(void* code, Call call, FunctionPtr function)
1205 ARMv7Assembler::linkCall(code, call.m_jmp, function.value());
1208 static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
1210 ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
1213 static void repatchCall(CodeLocationCall call, FunctionPtr destination)
1215 ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
1221 #endif // ENABLE(ASSEMBLER)
1223 #endif // MacroAssemblerARMv7_h