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) 2008 Apple Inc.
6 * Copyright (C) 2009, 2010 University of Szeged
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * ***** END LICENSE BLOCK ***** */
32 #ifndef MacroAssemblerARM_h
33 #define MacroAssemblerARM_h
35 #include "assembler/wtf/Platform.h"
37 #if ENABLE_ASSEMBLER && WTF_CPU_ARM_TRADITIONAL
39 #include "ARMAssembler.h"
40 #include "AbstractMacroAssembler.h"
44 class MacroAssemblerARM : public AbstractMacroAssembler<ARMAssembler> {
45 static const int DoubleConditionMask = 0x0f;
46 static const int DoubleConditionBitSpecial = 0x10;
47 COMPILE_ASSERT(!(DoubleConditionBitSpecial & DoubleConditionMask), DoubleConditionBitSpecial_should_not_interfere_with_ARMAssembler_Condition_codes);
50 Equal = ARMAssembler::EQ,
51 NotEqual = ARMAssembler::NE,
52 Above = ARMAssembler::HI,
53 AboveOrEqual = ARMAssembler::CS,
54 Below = ARMAssembler::CC,
55 BelowOrEqual = ARMAssembler::LS,
56 GreaterThan = ARMAssembler::GT,
57 GreaterThanOrEqual = ARMAssembler::GE,
58 LessThan = ARMAssembler::LT,
59 LessThanOrEqual = ARMAssembler::LE,
60 Overflow = ARMAssembler::VS,
61 Signed = ARMAssembler::MI,
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 linkRegister = ARMRegisters::lr;
86 static const Scale ScalePtr = TimesFour;
87 static const unsigned int TotalRegisters = 16;
89 void add32(RegisterID src, RegisterID dest)
91 m_assembler.adds_r(dest, dest, src);
94 void add32(Imm32 imm, Address address)
96 load32(address, ARMRegisters::S1);
97 add32(imm, ARMRegisters::S1);
98 store32(ARMRegisters::S1, address);
101 void add32(Imm32 imm, RegisterID dest)
103 m_assembler.adds_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
106 void add32(Address src, RegisterID dest)
108 load32(src, ARMRegisters::S1);
109 add32(ARMRegisters::S1, dest);
112 void and32(Address src, RegisterID dest)
114 load32(src, ARMRegisters::S1);
115 and32(ARMRegisters::S1, dest);
118 void and32(RegisterID src, RegisterID dest)
120 m_assembler.ands_r(dest, dest, src);
123 void and32(Imm32 imm, RegisterID dest)
125 ARMWord w = m_assembler.getImm(imm.m_value, ARMRegisters::S0, true);
126 if (w & ARMAssembler::OP2_INV_IMM)
127 m_assembler.bics_r(dest, dest, w & ~ARMAssembler::OP2_INV_IMM);
129 m_assembler.ands_r(dest, dest, w);
132 void lshift32(RegisterID shift_amount, RegisterID dest)
134 ARMWord w = ARMAssembler::getOp2(0x1f);
135 ASSERT(w != ARMAssembler::INVALID_IMM);
136 m_assembler.and_r(ARMRegisters::S0, shift_amount, w);
138 m_assembler.movs_r(dest, m_assembler.lsl_r(dest, ARMRegisters::S0));
141 void lshift32(Imm32 imm, RegisterID dest)
143 m_assembler.movs_r(dest, m_assembler.lsl(dest, imm.m_value & 0x1f));
146 void mul32(RegisterID src, RegisterID dest)
149 move(src, ARMRegisters::S0);
150 src = ARMRegisters::S0;
152 m_assembler.muls_r(dest, dest, src);
155 void mul32(Imm32 imm, RegisterID src, RegisterID dest)
157 move(imm, ARMRegisters::S0);
158 m_assembler.muls_r(dest, src, ARMRegisters::S0);
161 void neg32(RegisterID srcDest)
163 m_assembler.rsbs_r(srcDest, srcDest, ARMAssembler::getOp2(0));
166 void not32(RegisterID dest)
168 m_assembler.mvns_r(dest, dest);
171 void or32(RegisterID src, RegisterID dest)
173 m_assembler.orrs_r(dest, dest, src);
176 void or32(Imm32 imm, RegisterID dest)
178 m_assembler.orrs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
181 void rshift32(RegisterID shift_amount, RegisterID dest)
183 ARMWord w = ARMAssembler::getOp2(0x1f);
184 ASSERT(w != ARMAssembler::INVALID_IMM);
185 m_assembler.and_r(ARMRegisters::S0, shift_amount, w);
187 m_assembler.movs_r(dest, m_assembler.asr_r(dest, ARMRegisters::S0));
190 void rshift32(Imm32 imm, RegisterID dest)
192 m_assembler.movs_r(dest, m_assembler.asr(dest, imm.m_value & 0x1f));
195 void urshift32(RegisterID shift_amount, RegisterID dest)
197 ARMWord w = ARMAssembler::getOp2(0x1f);
198 ASSERT(w != ARMAssembler::INVALID_IMM);
199 m_assembler.and_r(ARMRegisters::S0, shift_amount, w);
201 m_assembler.movs_r(dest, m_assembler.lsr_r(dest, ARMRegisters::S0));
204 void urshift32(Imm32 imm, RegisterID dest)
206 m_assembler.movs_r(dest, m_assembler.lsr(dest, imm.m_value & 0x1f));
209 void sub32(RegisterID src, RegisterID dest)
211 m_assembler.subs_r(dest, dest, src);
214 void sub32(Imm32 imm, RegisterID dest)
216 m_assembler.subs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
219 void sub32(Imm32 imm, Address address)
221 load32(address, ARMRegisters::S1);
222 sub32(imm, ARMRegisters::S1);
223 store32(ARMRegisters::S1, address);
226 void sub32(Address src, RegisterID dest)
228 load32(src, ARMRegisters::S1);
229 sub32(ARMRegisters::S1, dest);
232 void or32(Address address, RegisterID dest)
234 load32(address, ARMRegisters::S1);
235 or32(ARMRegisters::S1, dest);
238 void xor32(RegisterID src, RegisterID dest)
240 m_assembler.eors_r(dest, dest, src);
243 void xor32(Imm32 imm, RegisterID dest)
245 m_assembler.eors_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
248 void xor32(Address src, RegisterID dest)
250 load32(src, ARMRegisters::S1);
251 m_assembler.eors_r(dest, dest, ARMRegisters::S1);
254 void load8(ImplicitAddress address, RegisterID dest)
256 m_assembler.dataTransfer8(true, dest, address.base, address.offset);
259 void load32(ImplicitAddress address, RegisterID dest)
261 m_assembler.dataTransfer32(true, dest, address.base, address.offset);
264 void load32(BaseIndex address, RegisterID dest)
266 m_assembler.baseIndexTransfer32(true, dest, address.base, address.index, static_cast<int>(address.scale), address.offset);
269 #if WTF_CPU_ARMV5_OR_LOWER
270 void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest);
272 void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
274 load32(address, dest);
278 DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
280 ASSERT(address.base != ARMRegisters::S0);
281 DataLabel32 dataLabel(this);
282 m_assembler.ldr_un_imm(ARMRegisters::S0, 0);
283 m_assembler.dtr_ur(true, dest, address.base, ARMRegisters::S0);
287 DataLabel32 load64WithAddressOffsetPatch(Address address, RegisterID hi, RegisterID lo)
289 ASSERT(address.base != ARMRegisters::S0);
290 ASSERT(lo != ARMRegisters::S0);
291 DataLabel32 dataLabel(this);
292 m_assembler.ldr_un_imm(ARMRegisters::S0, 0);
293 m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, address.base);
294 m_assembler.dtr_u(true, lo, ARMRegisters::S0, 0);
295 m_assembler.dtr_u(true, hi, ARMRegisters::S0, 4);
299 Label loadPtrWithPatchToLEA(Address address, RegisterID dest)
302 load32(address, dest);
306 void load16(BaseIndex address, RegisterID dest)
308 m_assembler.add_r(ARMRegisters::S1, address.base, m_assembler.lsl(address.index, address.scale));
309 load16(Address(ARMRegisters::S1, address.offset), dest);
312 void load16(ImplicitAddress address, RegisterID dest)
314 if (address.offset >= 0)
315 m_assembler.ldrh_u(dest, address.base, m_assembler.getOffsetForHalfwordDataTransfer(address.offset, ARMRegisters::S0));
317 m_assembler.ldrh_d(dest, address.base, m_assembler.getOffsetForHalfwordDataTransfer(-address.offset, ARMRegisters::S0));
320 DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
322 ASSERT(address.base != ARMRegisters::S0);
323 DataLabel32 dataLabel(this);
324 m_assembler.ldr_un_imm(ARMRegisters::S0, 0);
325 m_assembler.dtr_ur(false, src, address.base, ARMRegisters::S0);
329 DataLabel32 store64WithAddressOffsetPatch(RegisterID hi, RegisterID lo, Address address)
331 ASSERT(hi != ARMRegisters::S0);
332 ASSERT(lo != ARMRegisters::S0);
333 ASSERT(address.base != ARMRegisters::S0);
334 DataLabel32 dataLabel(this);
335 m_assembler.ldr_un_imm(ARMRegisters::S0, address.offset);
336 m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, address.base);
337 m_assembler.dtr_u(false, lo, ARMRegisters::S0, 0);
338 m_assembler.dtr_u(false, hi, ARMRegisters::S0, 4);
342 DataLabel32 store64WithAddressOffsetPatch(Imm32 hi, RegisterID lo, Address address)
344 ASSERT(lo != ARMRegisters::S0);
345 ASSERT(lo != ARMRegisters::S1);
346 ASSERT(lo != address.base);
347 ASSERT(address.base != ARMRegisters::S0);
348 ASSERT(address.base != ARMRegisters::S1);
349 DataLabel32 dataLabel(this);
350 m_assembler.ldr_un_imm(ARMRegisters::S0, address.offset);
351 m_assembler.moveImm(hi.m_value, ARMRegisters::S1);
352 m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, address.base);
353 m_assembler.dtr_u(false, lo, ARMRegisters::S0, 0);
354 m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 4);
358 DataLabel32 store64WithAddressOffsetPatch(Imm32 hi, Imm32 lo, Address address)
360 ASSERT(address.base != ARMRegisters::S0);
361 ASSERT(address.base != ARMRegisters::S1);
362 DataLabel32 dataLabel(this);
363 m_assembler.ldr_un_imm(ARMRegisters::S0, address.offset);
364 m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, address.base);
365 m_assembler.moveImm(lo.m_value, ARMRegisters::S1);
366 m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0);
367 /* TODO: improve this by getting another scratch register. */
368 m_assembler.moveImm(hi.m_value, ARMRegisters::S1);
369 m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 4);
373 void store32(RegisterID src, ImplicitAddress address)
375 m_assembler.dataTransfer32(false, src, address.base, address.offset);
378 void store32(RegisterID src, BaseIndex address)
380 m_assembler.baseIndexTransfer32(false, src, address.base, address.index, static_cast<int>(address.scale), address.offset);
383 void store32(Imm32 imm, BaseIndex address)
386 m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value);
388 move(imm, ARMRegisters::S1);
389 store32(ARMRegisters::S1, address);
392 void store32(Imm32 imm, ImplicitAddress address)
395 m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value);
397 move(imm, ARMRegisters::S1);
398 store32(ARMRegisters::S1, address);
401 void store32(RegisterID src, void* address)
403 m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address));
404 m_assembler.dtr_u(false, src, ARMRegisters::S0, 0);
407 void store32(Imm32 imm, void* address)
409 m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address));
411 m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value);
413 m_assembler.moveImm(imm.m_value, ARMRegisters::S1);
414 m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0);
417 void pop(RegisterID dest)
419 m_assembler.pop_r(dest);
422 void push(RegisterID src)
424 m_assembler.push_r(src);
427 void push(Address address)
429 load32(address, ARMRegisters::S1);
430 push(ARMRegisters::S1);
435 move(imm, ARMRegisters::S0);
436 push(ARMRegisters::S0);
439 void move(Imm32 imm, RegisterID dest)
442 m_assembler.ldr_un_imm(dest, imm.m_value);
444 m_assembler.moveImm(imm.m_value, dest);
447 void move(RegisterID src, RegisterID dest)
449 m_assembler.mov_r(dest, src);
452 void move(ImmPtr imm, RegisterID dest)
454 move(Imm32(imm), dest);
457 void swap(RegisterID reg1, RegisterID reg2)
459 m_assembler.mov_r(ARMRegisters::S0, reg1);
460 m_assembler.mov_r(reg1, reg2);
461 m_assembler.mov_r(reg2, ARMRegisters::S0);
464 void signExtend32ToPtr(RegisterID src, RegisterID dest)
470 void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
476 Jump branch8(Condition cond, Address left, Imm32 right)
478 load8(left, ARMRegisters::S1);
479 return branch32(cond, ARMRegisters::S1, right);
482 Jump branch32(Condition cond, RegisterID left, RegisterID right, int useConstantPool = 0)
484 m_assembler.cmp_r(left, right);
485 return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool));
488 Jump branch32(Condition cond, RegisterID left, Imm32 right, int useConstantPool = 0)
490 ASSERT(left != ARMRegisters::S0);
491 if (right.m_isPointer) {
492 m_assembler.ldr_un_imm(ARMRegisters::S0, right.m_value);
493 m_assembler.cmp_r(left, ARMRegisters::S0);
495 m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0));
496 return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool));
499 // Like branch32, but emit a consistently-structured sequence such that the
500 // number of instructions emitted is constant, regardless of the argument
501 // values. For ARM, this is identical to branch32WithPatch, except that it
502 // does not generate a DataLabel32.
503 Jump branch32FixedLength(Condition cond, RegisterID left, Imm32 right)
505 m_assembler.ldr_un_imm(ARMRegisters::S1, right.m_value);
506 return branch32(cond, left, ARMRegisters::S1, true);
509 // As branch32_force32, but allow the value ('right') to be patched.
510 Jump branch32WithPatch(Condition cond, RegisterID left, Imm32 right, DataLabel32 &dataLabel)
512 ASSERT(left != ARMRegisters::S1);
513 dataLabel = moveWithPatch(right, ARMRegisters::S1);
514 return branch32(cond, left, ARMRegisters::S1, true);
517 Jump branch32WithPatch(Condition cond, Address left, Imm32 right, DataLabel32 &dataLabel)
519 ASSERT(left.base != ARMRegisters::S1);
520 load32(left, ARMRegisters::S1);
521 dataLabel = moveWithPatch(right, ARMRegisters::S0);
522 return branch32(cond, ARMRegisters::S1, ARMRegisters::S0, true);
525 Jump branch32(Condition cond, RegisterID left, Address right)
527 load32(right, ARMRegisters::S1);
528 return branch32(cond, left, ARMRegisters::S1);
531 Jump branch32(Condition cond, Address left, RegisterID right)
533 load32(left, ARMRegisters::S1);
534 return branch32(cond, ARMRegisters::S1, right);
537 Jump branch32(Condition cond, Address left, Imm32 right)
539 load32(left, ARMRegisters::S1);
540 return branch32(cond, ARMRegisters::S1, right);
543 Jump branch32(Condition cond, BaseIndex left, Imm32 right)
545 load32(left, ARMRegisters::S1);
546 return branch32(cond, ARMRegisters::S1, right);
549 Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
551 load32WithUnalignedHalfWords(left, ARMRegisters::S1);
552 return branch32(cond, ARMRegisters::S1, right);
555 Jump branch16(Condition cond, BaseIndex left, RegisterID right)
560 ASSERT_NOT_REACHED();
564 Jump branch16(Condition cond, BaseIndex left, Imm32 right)
566 load16(left, ARMRegisters::S0);
567 move(right, ARMRegisters::S1);
568 m_assembler.cmp_r(ARMRegisters::S0, ARMRegisters::S1);
569 return m_assembler.jmp(ARMCondition(cond));
572 Jump branchTest8(Condition cond, Address address, Imm32 mask = Imm32(-1))
574 load8(address, ARMRegisters::S1);
575 return branchTest32(cond, ARMRegisters::S1, mask);
578 Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask)
580 ASSERT((cond == Zero) || (cond == NonZero));
581 m_assembler.tst_r(reg, mask);
582 return Jump(m_assembler.jmp(ARMCondition(cond)));
585 Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1))
587 ASSERT((cond == Zero) || (cond == NonZero));
588 ARMWord w = m_assembler.getImm(mask.m_value, ARMRegisters::S0, true);
589 if (w & ARMAssembler::OP2_INV_IMM)
590 m_assembler.bics_r(ARMRegisters::S0, reg, w & ~ARMAssembler::OP2_INV_IMM);
592 m_assembler.tst_r(reg, w);
593 return Jump(m_assembler.jmp(ARMCondition(cond)));
596 Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1))
598 load32(address, ARMRegisters::S1);
599 return branchTest32(cond, ARMRegisters::S1, mask);
602 Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1))
604 load32(address, ARMRegisters::S1);
605 return branchTest32(cond, ARMRegisters::S1, mask);
610 return Jump(m_assembler.jmp());
613 void jump(RegisterID target)
615 m_assembler.bx(target);
618 void jump(Address address)
620 load32(address, ARMRegisters::pc);
623 Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest)
625 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
627 return Jump(m_assembler.jmp(ARMCondition(cond)));
630 Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest)
632 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
634 return Jump(m_assembler.jmp(ARMCondition(cond)));
637 Jump branchAdd32(Condition cond, Address src, RegisterID dest)
639 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
641 return Jump(m_assembler.jmp(ARMCondition(cond)));
644 void mull32(RegisterID src1, RegisterID src2, RegisterID dest)
647 move(src1, ARMRegisters::S0);
648 src1 = ARMRegisters::S0;
650 m_assembler.mull_r(ARMRegisters::S1, dest, src2, src1);
651 m_assembler.cmp_r(ARMRegisters::S1, m_assembler.asr(dest, 31));
654 Jump branchMul32(Condition cond, RegisterID src, RegisterID dest)
656 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
657 if (cond == Overflow) {
658 mull32(src, dest, dest);
663 return Jump(m_assembler.jmp(ARMCondition(cond)));
666 Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest)
668 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
669 if (cond == Overflow) {
670 move(imm, ARMRegisters::S0);
671 mull32(ARMRegisters::S0, src, dest);
675 mul32(imm, src, dest);
676 return Jump(m_assembler.jmp(ARMCondition(cond)));
679 Jump branchSub32(Condition cond, RegisterID src, RegisterID dest)
681 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
683 return Jump(m_assembler.jmp(ARMCondition(cond)));
686 Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest)
688 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
690 return Jump(m_assembler.jmp(ARMCondition(cond)));
693 Jump branchSub32(Condition cond, Address src, RegisterID dest)
695 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
697 return Jump(m_assembler.jmp(ARMCondition(cond)));
700 Jump branchSub32(Condition cond, Imm32 imm, Address dest)
702 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
704 return Jump(m_assembler.jmp(ARMCondition(cond)));
707 Jump branchNeg32(Condition cond, RegisterID srcDest)
709 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
711 return Jump(m_assembler.jmp(ARMCondition(cond)));
714 Jump branchOr32(Condition cond, RegisterID src, RegisterID dest)
716 ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero));
718 return Jump(m_assembler.jmp(ARMCondition(cond)));
721 // Encode a NOP using "MOV rX, rX", where 'X' is defined by 'tag', and is
722 // in the range r0-r14.
725 ASSERT((tag >= 0) && (tag <= 14));
726 m_assembler.mov_r(tag, tag);
736 #if WTF_ARM_ARCH_VERSION >= 5
737 Call call(m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true), Call::LinkableNear);
738 m_assembler.blx(ARMRegisters::S1);
742 return Call(m_assembler.jmp(ARMAssembler::AL, true), Call::LinkableNear);
746 Call call(RegisterID target)
748 m_assembler.blx(target);
750 return Call(jmpSrc, Call::None);
753 void call(Address address)
755 call32(address.base, address.offset);
760 m_assembler.bx(linkRegister);
763 void set32(Condition cond, Address left, RegisterID right, RegisterID dest)
765 load32(left, ARMRegisters::S1);
766 set32(cond, ARMRegisters::S1, right, dest);
769 void set32(Condition cond, RegisterID left, Address right, RegisterID dest)
771 load32(right, ARMRegisters::S1);
772 set32(cond, left, ARMRegisters::S1, dest);
775 void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
777 m_assembler.cmp_r(left, right);
778 m_assembler.mov_r(dest, ARMAssembler::getOp2(0));
779 m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond));
782 void set32(Condition cond, RegisterID left, Imm32 right, RegisterID dest)
784 m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0));
785 m_assembler.mov_r(dest, ARMAssembler::getOp2(0));
786 m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond));
789 void set32(Condition cond, Address left, Imm32 right, RegisterID dest)
791 load32(left, ARMRegisters::S1);
792 set32(cond, ARMRegisters::S1, right, dest);
795 void set8(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
797 // ARM doesn't have byte registers
798 set32(cond, left, right, dest);
801 void set8(Condition cond, Address left, RegisterID right, RegisterID dest)
803 // ARM doesn't have byte registers
804 load32(left, ARMRegisters::S1);
805 set32(cond, ARMRegisters::S1, right, dest);
808 void set8(Condition cond, RegisterID left, Imm32 right, RegisterID dest)
810 // ARM doesn't have byte registers
811 set32(cond, left, right, dest);
814 void setTest32(Condition cond, Address address, Imm32 mask, RegisterID dest)
816 load32(address, ARMRegisters::S1);
817 if (mask.m_value == -1)
818 m_assembler.cmp_r(0, ARMRegisters::S1);
820 m_assembler.tst_r(ARMRegisters::S1, m_assembler.getImm(mask.m_value, ARMRegisters::S0));
821 m_assembler.mov_r(dest, ARMAssembler::getOp2(0));
822 m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond));
825 void setTest8(Condition cond, Address address, Imm32 mask, RegisterID dest)
827 // ARM doesn't have byte registers
828 setTest32(cond, address, mask, dest);
831 void add32(Imm32 imm, RegisterID src, RegisterID dest)
833 m_assembler.add_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
836 void lea(Address address, RegisterID dest)
838 m_assembler.add_r(dest, address.base, m_assembler.getImm(address.offset, ARMRegisters::S0));
841 void lea(BaseIndex address, RegisterID dest)
843 /* This could be better? */
844 move(address.index, ARMRegisters::S1);
845 if (address.scale != 0)
846 lshift32(Imm32(address.scale), ARMRegisters::S1);
848 add32(Imm32(address.offset), ARMRegisters::S1);
849 add32(address.base, ARMRegisters::S1);
850 move(ARMRegisters::S1, dest);
853 void add32(Imm32 imm, AbsoluteAddress address)
855 m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast<ARMWord>(address.m_ptr));
856 m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0);
857 add32(imm, ARMRegisters::S1);
858 m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address.m_ptr));
859 m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0);
862 void sub32(Imm32 imm, AbsoluteAddress address)
864 m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast<ARMWord>(address.m_ptr));
865 m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0);
866 sub32(imm, ARMRegisters::S1);
867 m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address.m_ptr));
868 m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0);
871 void load32(void* address, RegisterID dest)
873 m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address));
874 m_assembler.dtr_u(true, dest, ARMRegisters::S0, 0);
877 Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right)
879 load32(left.m_ptr, ARMRegisters::S1);
880 return branch32(cond, ARMRegisters::S1, right);
883 Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
885 load32(left.m_ptr, ARMRegisters::S1);
886 return branch32(cond, ARMRegisters::S1, right);
891 #if WTF_ARM_ARCH_VERSION >= 5
892 Call call(m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true), Call::Linkable);
893 m_assembler.blx(ARMRegisters::S1);
897 return Call(m_assembler.jmp(ARMAssembler::AL, true), Call::Linkable);
901 Call tailRecursiveCall()
903 return Call::fromTailJump(jump());
906 Call makeTailRecursiveCall(Jump oldJump)
908 return Call::fromTailJump(oldJump);
911 DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
913 DataLabelPtr dataLabel(this);
914 m_assembler.ldr_un_imm(dest, reinterpret_cast<ARMWord>(initialValue.m_value));
918 DataLabel32 moveWithPatch(Imm32 initialValue, RegisterID dest)
920 DataLabel32 dataLabel(this);
921 m_assembler.ldr_un_imm(dest, initialValue.m_value);
925 Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
927 dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S1);
928 Jump jump = branch32(cond, left, ARMRegisters::S1, true);
932 Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
934 load32(left, ARMRegisters::S1);
935 dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S0);
936 Jump jump = branch32(cond, ARMRegisters::S0, ARMRegisters::S1, true);
940 DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
942 DataLabelPtr dataLabel = moveWithPatch(initialValue, ARMRegisters::S1);
943 store32(ARMRegisters::S1, address);
947 DataLabelPtr storePtrWithPatch(ImplicitAddress address)
949 return storePtrWithPatch(ImmPtr(0), address);
952 // Floating point operators
953 bool supportsFloatingPoint() const
955 return s_isVFPPresent;
958 bool supportsFloatingPointTruncate() const
963 bool supportsFloatingPointSqrt() const
965 return s_isVFPPresent;
968 void moveDouble(FPRegisterID src, FPRegisterID dest)
970 m_assembler.fcpyd_r(dest, src);
973 void loadDouble(ImplicitAddress address, FPRegisterID dest)
975 m_assembler.doubleTransfer(true, dest, address.base, address.offset);
978 DataLabelPtr loadDouble(const void* address, FPRegisterID dest)
980 DataLabelPtr label = moveWithPatch(ImmPtr(address), ARMRegisters::S0);
981 m_assembler.fdtr_u(true, dest, ARMRegisters::S0, 0);
985 void storeDouble(FPRegisterID src, ImplicitAddress address)
987 m_assembler.doubleTransfer(false, src, address.base, address.offset);
990 void addDouble(FPRegisterID src, FPRegisterID dest)
992 m_assembler.faddd_r(dest, dest, src);
995 void addDouble(Address src, FPRegisterID dest)
997 loadDouble(src, ARMRegisters::SD0);
998 addDouble(ARMRegisters::SD0, dest);
1001 void divDouble(FPRegisterID src, FPRegisterID dest)
1003 m_assembler.fdivd_r(dest, dest, src);
1006 void divDouble(Address src, FPRegisterID dest)
1008 ASSERT_NOT_REACHED(); // Untested
1009 loadDouble(src, ARMRegisters::SD0);
1010 divDouble(ARMRegisters::SD0, dest);
1013 void subDouble(FPRegisterID src, FPRegisterID dest)
1015 m_assembler.fsubd_r(dest, dest, src);
1018 void subDouble(Address src, FPRegisterID dest)
1020 loadDouble(src, ARMRegisters::SD0);
1021 subDouble(ARMRegisters::SD0, dest);
1024 void mulDouble(FPRegisterID src, FPRegisterID dest)
1026 m_assembler.fmuld_r(dest, dest, src);
1029 void mulDouble(Address src, FPRegisterID dest)
1031 loadDouble(src, ARMRegisters::SD0);
1032 mulDouble(ARMRegisters::SD0, dest);
1035 void negDouble(FPRegisterID src, FPRegisterID dest)
1037 m_assembler.fnegd_r(dest, src);
1040 void sqrtDouble(FPRegisterID src, FPRegisterID dest)
1042 m_assembler.fsqrtd_r(dest, src);
1045 void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
1047 m_assembler.fmsr_r(dest, src);
1048 m_assembler.fsitod_r(dest, dest);
1051 void convertInt32ToDouble(Address src, FPRegisterID dest)
1053 // flds does not worth the effort here
1054 load32(src, ARMRegisters::S1);
1055 convertInt32ToDouble(ARMRegisters::S1, dest);
1058 void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest)
1060 ASSERT_NOT_REACHED(); // Untested
1061 // flds does not worth the effort here
1062 m_assembler.ldr_un_imm(ARMRegisters::S1, (ARMWord)src.m_ptr);
1063 m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0);
1064 convertInt32ToDouble(ARMRegisters::S1, dest);
1067 Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
1069 m_assembler.fcmpd_r(left, right);
1070 m_assembler.fmstat();
1071 if (cond & DoubleConditionBitSpecial)
1072 m_assembler.cmp_r(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::VS);
1073 return Jump(m_assembler.jmp(static_cast<ARMAssembler::Condition>(cond & ~DoubleConditionMask)));
1076 // Truncates 'src' to an integer, and places the resulting 'dest'.
1077 // If the result is not representable as a 32 bit value, branch.
1078 // May also branch for some values that are representable in 32 bits
1079 Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest)
1081 m_assembler.ftosizd_r(ARMRegisters::SD0, src);
1082 // If FTOSIZD (VCVT.S32.F64) can't fit the result into a 32-bit
1083 // integer, it saturates at INT_MAX or INT_MIN. Testing this is
1084 // probably quicker than testing FPSCR for exception.
1085 m_assembler.fmrs_r(dest, ARMRegisters::SD0);
1086 m_assembler.cmn_r(dest, ARMAssembler::getOp2(-0x7fffffff));
1087 m_assembler.cmp_r(dest, ARMAssembler::getOp2(0x80000000), ARMCondition(NonZero));
1088 return Jump(m_assembler.jmp(ARMCondition(Zero)));
1091 // Convert 'src' to an integer, and places the resulting 'dest'.
1092 // If the result is not representable as a 32 bit value, branch.
1093 // May also branch for some values that are representable in 32 bits
1094 // (specifically, in this case, 0).
1095 void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp)
1097 m_assembler.ftosid_r(ARMRegisters::SD0, src);
1098 m_assembler.fmrs_r(dest, ARMRegisters::SD0);
1100 // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
1101 m_assembler.fsitod_r(ARMRegisters::SD0, ARMRegisters::SD0);
1102 failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, ARMRegisters::SD0));
1104 // If the result is zero, it might have been -0.0, and 0.0 equals to -0.0
1105 failureCases.append(branchTest32(Zero, dest));
1108 void zeroDouble(FPRegisterID srcDest)
1110 m_assembler.mov_r(ARMRegisters::S0, ARMAssembler::getOp2(0));
1111 convertInt32ToDouble(ARMRegisters::S0, srcDest);
1114 void ensureSpace(int space)
1116 m_assembler.ensureSpace(space);
1119 void forceFlushConstantPool()
1121 m_assembler.forceFlushConstantPool();
1125 void allowPoolFlush(bool allowFlush)
1127 m_assembler.allowPoolFlush(allowFlush);
1132 ARMAssembler::Condition ARMCondition(Condition cond)
1134 return static_cast<ARMAssembler::Condition>(cond);
1137 void ensureSpace(int insnSpace, int constSpace)
1139 m_assembler.ensureSpace(insnSpace, constSpace);
1142 int sizeOfConstantPool()
1144 return m_assembler.sizeOfConstantPool();
1147 #if WTF_ARM_ARCH_VERSION < 5
1150 #if WTF_ARM_ARCH_VERSION < 5
1151 ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord));
1153 m_assembler.mov_r(linkRegister, ARMRegisters::pc);
1158 #if WTF_ARM_ARCH_VERSION < 5
1159 void call32(RegisterID base, int32_t offset)
1161 #if WTF_ARM_ARCH_VERSION >= 5
1162 int targetReg = ARMRegisters::S1;
1164 int targetReg = ARMRegisters::pc;
1166 int tmpReg = ARMRegisters::S1;
1168 if (base == ARMRegisters::sp)
1172 if (offset <= 0xfff) {
1174 m_assembler.dtr_u(true, targetReg, base, offset);
1175 } else if (offset <= 0xfffff) {
1176 m_assembler.add_r(tmpReg, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8));
1178 m_assembler.dtr_u(true, targetReg, tmpReg, offset & 0xfff);
1180 ARMWord reg = m_assembler.getImm(offset, tmpReg);
1182 m_assembler.dtr_ur(true, targetReg, base, reg);
1186 if (offset <= 0xfff) {
1188 m_assembler.dtr_d(true, targetReg, base, offset);
1189 } else if (offset <= 0xfffff) {
1190 m_assembler.sub_r(tmpReg, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8));
1192 m_assembler.dtr_d(true, targetReg, tmpReg, offset & 0xfff);
1194 ARMWord reg = m_assembler.getImm(offset, tmpReg);
1196 m_assembler.dtr_dr(true, targetReg, base, reg);
1199 #if WTF_ARM_ARCH_VERSION >= 5
1200 m_assembler.blx(targetReg);
1204 void call32(RegisterID base, int32_t offset)
1206 // TODO: Why is SP special?
1207 if (base == ARMRegisters::sp)
1210 // Branch to the address stored in base+offset, using one of the
1211 // following sequences:
1213 // LDR ip, [base, ±offset]
1216 // ADD/SUB ip, base, #(offset & 0xff000)
1217 // LDR ip, [ip, #(offset & 0xfff)]
1221 // LDR ip, [base, ±ip]
1225 if (offset <= 0xfff) {
1226 m_assembler.dtr_u(true, ARMRegisters::S0, base, offset);
1227 } else if (offset <= 0xfffff) {
1228 m_assembler.add_r(ARMRegisters::S0, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8));
1229 m_assembler.dtr_u(true, ARMRegisters::S0, ARMRegisters::S0, offset & 0xfff);
1231 m_assembler.moveImm(offset, ARMRegisters::S0);
1232 m_assembler.dtr_ur(true, ARMRegisters::S0, base, ARMRegisters::S0);
1236 if (offset <= 0xfff) {
1237 m_assembler.dtr_d(true, ARMRegisters::S0, base, offset);
1238 } else if (offset <= 0xfffff) {
1239 m_assembler.sub_r(ARMRegisters::S0, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8));
1240 m_assembler.dtr_d(true, ARMRegisters::S0, ARMRegisters::S0, offset & 0xfff);
1242 m_assembler.moveImm(offset, ARMRegisters::S0);
1243 m_assembler.dtr_dr(true, ARMRegisters::S0, base, ARMRegisters::S0);
1246 m_assembler.blx(ARMRegisters::S0);
1251 friend class LinkBuffer;
1252 friend class RepatchBuffer;
1254 static void linkCall(void* code, Call call, FunctionPtr function)
1256 ARMAssembler::linkCall(code, call.m_jmp, function.value());
1259 static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
1261 ARMAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
1264 static void repatchCall(CodeLocationCall call, FunctionPtr destination)
1266 ARMAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
1269 static const bool s_isVFPPresent;
1274 #endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
1276 #endif // MacroAssemblerARM_h