• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 Apple Inc.
3  * Copyright (C) 2009 University of Szeged
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #ifndef MacroAssemblerARM_h
29 #define MacroAssemblerARM_h
30 
31 #include <wtf/Platform.h>
32 
33 #if ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
34 
35 #include "ARMAssembler.h"
36 #include "AbstractMacroAssembler.h"
37 
38 namespace JSC {
39 
40 class MacroAssemblerARM : public AbstractMacroAssembler<ARMAssembler> {
41     static const int DoubleConditionMask = 0x0f;
42     static const int DoubleConditionBitSpecial = 0x10;
43     COMPILE_ASSERT(!(DoubleConditionBitSpecial & DoubleConditionMask), DoubleConditionBitSpecial_should_not_interfere_with_ARMAssembler_Condition_codes);
44 public:
45     enum Condition {
46         Equal = ARMAssembler::EQ,
47         NotEqual = ARMAssembler::NE,
48         Above = ARMAssembler::HI,
49         AboveOrEqual = ARMAssembler::CS,
50         Below = ARMAssembler::CC,
51         BelowOrEqual = ARMAssembler::LS,
52         GreaterThan = ARMAssembler::GT,
53         GreaterThanOrEqual = ARMAssembler::GE,
54         LessThan = ARMAssembler::LT,
55         LessThanOrEqual = ARMAssembler::LE,
56         Overflow = ARMAssembler::VS,
57         Signed = ARMAssembler::MI,
58         Zero = ARMAssembler::EQ,
59         NonZero = ARMAssembler::NE
60     };
61 
62     enum DoubleCondition {
63         // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
64         DoubleEqual = ARMAssembler::EQ,
65         DoubleNotEqual = ARMAssembler::NE | DoubleConditionBitSpecial,
66         DoubleGreaterThan = ARMAssembler::GT,
67         DoubleGreaterThanOrEqual = ARMAssembler::GE,
68         DoubleLessThan = ARMAssembler::CC,
69         DoubleLessThanOrEqual = ARMAssembler::LS,
70         // If either operand is NaN, these conditions always evaluate to true.
71         DoubleEqualOrUnordered = ARMAssembler::EQ | DoubleConditionBitSpecial,
72         DoubleNotEqualOrUnordered = ARMAssembler::NE,
73         DoubleGreaterThanOrUnordered = ARMAssembler::HI,
74         DoubleGreaterThanOrEqualOrUnordered = ARMAssembler::CS,
75         DoubleLessThanOrUnordered = ARMAssembler::LT,
76         DoubleLessThanOrEqualOrUnordered = ARMAssembler::LE,
77     };
78 
79     static const RegisterID stackPointerRegister = ARMRegisters::sp;
80     static const RegisterID linkRegister = ARMRegisters::lr;
81 
82     static const Scale ScalePtr = TimesFour;
83 
add32(RegisterID src,RegisterID dest)84     void add32(RegisterID src, RegisterID dest)
85     {
86         m_assembler.adds_r(dest, dest, src);
87     }
88 
add32(Imm32 imm,Address address)89     void add32(Imm32 imm, Address address)
90     {
91         load32(address, ARMRegisters::S1);
92         add32(imm, ARMRegisters::S1);
93         store32(ARMRegisters::S1, address);
94     }
95 
add32(Imm32 imm,RegisterID dest)96     void add32(Imm32 imm, RegisterID dest)
97     {
98         m_assembler.adds_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
99     }
100 
add32(Address src,RegisterID dest)101     void add32(Address src, RegisterID dest)
102     {
103         load32(src, ARMRegisters::S1);
104         add32(ARMRegisters::S1, dest);
105     }
106 
and32(RegisterID src,RegisterID dest)107     void and32(RegisterID src, RegisterID dest)
108     {
109         m_assembler.ands_r(dest, dest, src);
110     }
111 
and32(Imm32 imm,RegisterID dest)112     void and32(Imm32 imm, RegisterID dest)
113     {
114         ARMWord w = m_assembler.getImm(imm.m_value, ARMRegisters::S0, true);
115         if (w & ARMAssembler::OP2_INV_IMM)
116             m_assembler.bics_r(dest, dest, w & ~ARMAssembler::OP2_INV_IMM);
117         else
118             m_assembler.ands_r(dest, dest, w);
119     }
120 
lshift32(RegisterID shift_amount,RegisterID dest)121     void lshift32(RegisterID shift_amount, RegisterID dest)
122     {
123         ARMWord w = ARMAssembler::getOp2(0x1f);
124         ASSERT(w != ARMAssembler::INVALID_IMM);
125         m_assembler.and_r(ARMRegisters::S0, shift_amount, w);
126 
127         m_assembler.movs_r(dest, m_assembler.lsl_r(dest, ARMRegisters::S0));
128     }
129 
lshift32(Imm32 imm,RegisterID dest)130     void lshift32(Imm32 imm, RegisterID dest)
131     {
132         m_assembler.movs_r(dest, m_assembler.lsl(dest, imm.m_value & 0x1f));
133     }
134 
mul32(RegisterID src,RegisterID dest)135     void mul32(RegisterID src, RegisterID dest)
136     {
137         if (src == dest) {
138             move(src, ARMRegisters::S0);
139             src = ARMRegisters::S0;
140         }
141         m_assembler.muls_r(dest, dest, src);
142     }
143 
mul32(Imm32 imm,RegisterID src,RegisterID dest)144     void mul32(Imm32 imm, RegisterID src, RegisterID dest)
145     {
146         move(imm, ARMRegisters::S0);
147         m_assembler.muls_r(dest, src, ARMRegisters::S0);
148     }
149 
neg32(RegisterID srcDest)150     void neg32(RegisterID srcDest)
151     {
152         m_assembler.rsbs_r(srcDest, srcDest, ARMAssembler::getOp2(0));
153     }
154 
not32(RegisterID dest)155     void not32(RegisterID dest)
156     {
157         m_assembler.mvns_r(dest, dest);
158     }
159 
or32(RegisterID src,RegisterID dest)160     void or32(RegisterID src, RegisterID dest)
161     {
162         m_assembler.orrs_r(dest, dest, src);
163     }
164 
or32(Imm32 imm,RegisterID dest)165     void or32(Imm32 imm, RegisterID dest)
166     {
167         m_assembler.orrs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
168     }
169 
rshift32(RegisterID shift_amount,RegisterID dest)170     void rshift32(RegisterID shift_amount, RegisterID dest)
171     {
172         ARMWord w = ARMAssembler::getOp2(0x1f);
173         ASSERT(w != ARMAssembler::INVALID_IMM);
174         m_assembler.and_r(ARMRegisters::S0, shift_amount, w);
175 
176         m_assembler.movs_r(dest, m_assembler.asr_r(dest, ARMRegisters::S0));
177     }
178 
rshift32(Imm32 imm,RegisterID dest)179     void rshift32(Imm32 imm, RegisterID dest)
180     {
181         m_assembler.movs_r(dest, m_assembler.asr(dest, imm.m_value & 0x1f));
182     }
183 
sub32(RegisterID src,RegisterID dest)184     void sub32(RegisterID src, RegisterID dest)
185     {
186         m_assembler.subs_r(dest, dest, src);
187     }
188 
sub32(Imm32 imm,RegisterID dest)189     void sub32(Imm32 imm, RegisterID dest)
190     {
191         m_assembler.subs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
192     }
193 
sub32(Imm32 imm,Address address)194     void sub32(Imm32 imm, Address address)
195     {
196         load32(address, ARMRegisters::S1);
197         sub32(imm, ARMRegisters::S1);
198         store32(ARMRegisters::S1, address);
199     }
200 
sub32(Address src,RegisterID dest)201     void sub32(Address src, RegisterID dest)
202     {
203         load32(src, ARMRegisters::S1);
204         sub32(ARMRegisters::S1, dest);
205     }
206 
xor32(RegisterID src,RegisterID dest)207     void xor32(RegisterID src, RegisterID dest)
208     {
209         m_assembler.eors_r(dest, dest, src);
210     }
211 
xor32(Imm32 imm,RegisterID dest)212     void xor32(Imm32 imm, RegisterID dest)
213     {
214         m_assembler.eors_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
215     }
216 
load32(ImplicitAddress address,RegisterID dest)217     void load32(ImplicitAddress address, RegisterID dest)
218     {
219         m_assembler.dataTransfer32(true, dest, address.base, address.offset);
220     }
221 
load32(BaseIndex address,RegisterID dest)222     void load32(BaseIndex address, RegisterID dest)
223     {
224         m_assembler.baseIndexTransfer32(true, dest, address.base, address.index, static_cast<int>(address.scale), address.offset);
225     }
226 
227 #if CPU(ARMV5_OR_LOWER)
228     void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest);
229 #else
load32WithUnalignedHalfWords(BaseIndex address,RegisterID dest)230     void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
231     {
232         load32(address, dest);
233     }
234 #endif
235 
load32WithAddressOffsetPatch(Address address,RegisterID dest)236     DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
237     {
238         DataLabel32 dataLabel(this);
239         m_assembler.ldr_un_imm(ARMRegisters::S0, 0);
240         m_assembler.dtr_ur(true, dest, address.base, ARMRegisters::S0);
241         return dataLabel;
242     }
243 
loadPtrWithPatchToLEA(Address address,RegisterID dest)244     Label loadPtrWithPatchToLEA(Address address, RegisterID dest)
245     {
246         Label label(this);
247         load32(address, dest);
248         return label;
249     }
250 
load16(BaseIndex address,RegisterID dest)251     void load16(BaseIndex address, RegisterID dest)
252     {
253         m_assembler.add_r(ARMRegisters::S0, address.base, m_assembler.lsl(address.index, address.scale));
254         if (address.offset>=0)
255             m_assembler.ldrh_u(dest, ARMRegisters::S0, ARMAssembler::getOp2Byte(address.offset));
256         else
257             m_assembler.ldrh_d(dest, ARMRegisters::S0, ARMAssembler::getOp2Byte(-address.offset));
258     }
259 
store32WithAddressOffsetPatch(RegisterID src,Address address)260     DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
261     {
262         DataLabel32 dataLabel(this);
263         m_assembler.ldr_un_imm(ARMRegisters::S0, 0);
264         m_assembler.dtr_ur(false, src, address.base, ARMRegisters::S0);
265         return dataLabel;
266     }
267 
store32(RegisterID src,ImplicitAddress address)268     void store32(RegisterID src, ImplicitAddress address)
269     {
270         m_assembler.dataTransfer32(false, src, address.base, address.offset);
271     }
272 
store32(RegisterID src,BaseIndex address)273     void store32(RegisterID src, BaseIndex address)
274     {
275         m_assembler.baseIndexTransfer32(false, src, address.base, address.index, static_cast<int>(address.scale), address.offset);
276     }
277 
store32(Imm32 imm,ImplicitAddress address)278     void store32(Imm32 imm, ImplicitAddress address)
279     {
280         if (imm.m_isPointer)
281             m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value);
282         else
283             move(imm, ARMRegisters::S1);
284         store32(ARMRegisters::S1, address);
285     }
286 
store32(RegisterID src,void * address)287     void store32(RegisterID src, void* address)
288     {
289         m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address));
290         m_assembler.dtr_u(false, src, ARMRegisters::S0, 0);
291     }
292 
store32(Imm32 imm,void * address)293     void store32(Imm32 imm, void* address)
294     {
295         m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address));
296         if (imm.m_isPointer)
297             m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value);
298         else
299             m_assembler.moveImm(imm.m_value, ARMRegisters::S1);
300         m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0);
301     }
302 
pop(RegisterID dest)303     void pop(RegisterID dest)
304     {
305         m_assembler.pop_r(dest);
306     }
307 
push(RegisterID src)308     void push(RegisterID src)
309     {
310         m_assembler.push_r(src);
311     }
312 
push(Address address)313     void push(Address address)
314     {
315         load32(address, ARMRegisters::S1);
316         push(ARMRegisters::S1);
317     }
318 
push(Imm32 imm)319     void push(Imm32 imm)
320     {
321         move(imm, ARMRegisters::S0);
322         push(ARMRegisters::S0);
323     }
324 
move(Imm32 imm,RegisterID dest)325     void move(Imm32 imm, RegisterID dest)
326     {
327         if (imm.m_isPointer)
328             m_assembler.ldr_un_imm(dest, imm.m_value);
329         else
330             m_assembler.moveImm(imm.m_value, dest);
331     }
332 
move(RegisterID src,RegisterID dest)333     void move(RegisterID src, RegisterID dest)
334     {
335         m_assembler.mov_r(dest, src);
336     }
337 
move(ImmPtr imm,RegisterID dest)338     void move(ImmPtr imm, RegisterID dest)
339     {
340         move(Imm32(imm), dest);
341     }
342 
swap(RegisterID reg1,RegisterID reg2)343     void swap(RegisterID reg1, RegisterID reg2)
344     {
345         m_assembler.mov_r(ARMRegisters::S0, reg1);
346         m_assembler.mov_r(reg1, reg2);
347         m_assembler.mov_r(reg2, ARMRegisters::S0);
348     }
349 
signExtend32ToPtr(RegisterID src,RegisterID dest)350     void signExtend32ToPtr(RegisterID src, RegisterID dest)
351     {
352         if (src != dest)
353             move(src, dest);
354     }
355 
zeroExtend32ToPtr(RegisterID src,RegisterID dest)356     void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
357     {
358         if (src != dest)
359             move(src, dest);
360     }
361 
362     Jump branch32(Condition cond, RegisterID left, RegisterID right, int useConstantPool = 0)
363     {
364         m_assembler.cmp_r(left, right);
365         return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool));
366     }
367 
368     Jump branch32(Condition cond, RegisterID left, Imm32 right, int useConstantPool = 0)
369     {
370         if (right.m_isPointer) {
371             m_assembler.ldr_un_imm(ARMRegisters::S0, right.m_value);
372             m_assembler.cmp_r(left, ARMRegisters::S0);
373         } else
374             m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0));
375         return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool));
376     }
377 
branch32(Condition cond,RegisterID left,Address right)378     Jump branch32(Condition cond, RegisterID left, Address right)
379     {
380         load32(right, ARMRegisters::S1);
381         return branch32(cond, left, ARMRegisters::S1);
382     }
383 
branch32(Condition cond,Address left,RegisterID right)384     Jump branch32(Condition cond, Address left, RegisterID right)
385     {
386         load32(left, ARMRegisters::S1);
387         return branch32(cond, ARMRegisters::S1, right);
388     }
389 
branch32(Condition cond,Address left,Imm32 right)390     Jump branch32(Condition cond, Address left, Imm32 right)
391     {
392         load32(left, ARMRegisters::S1);
393         return branch32(cond, ARMRegisters::S1, right);
394     }
395 
branch32(Condition cond,BaseIndex left,Imm32 right)396     Jump branch32(Condition cond, BaseIndex left, Imm32 right)
397     {
398         load32(left, ARMRegisters::S1);
399         return branch32(cond, ARMRegisters::S1, right);
400     }
401 
branch32WithUnalignedHalfWords(Condition cond,BaseIndex left,Imm32 right)402     Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
403     {
404         load32WithUnalignedHalfWords(left, ARMRegisters::S1);
405         return branch32(cond, ARMRegisters::S1, right);
406     }
407 
branch16(Condition cond,BaseIndex left,RegisterID right)408     Jump branch16(Condition cond, BaseIndex left, RegisterID right)
409     {
410         UNUSED_PARAM(cond);
411         UNUSED_PARAM(left);
412         UNUSED_PARAM(right);
413         ASSERT_NOT_REACHED();
414         return jump();
415     }
416 
branch16(Condition cond,BaseIndex left,Imm32 right)417     Jump branch16(Condition cond, BaseIndex left, Imm32 right)
418     {
419         load16(left, ARMRegisters::S0);
420         move(right, ARMRegisters::S1);
421         m_assembler.cmp_r(ARMRegisters::S0, ARMRegisters::S1);
422         return m_assembler.jmp(ARMCondition(cond));
423     }
424 
branchTest32(Condition cond,RegisterID reg,RegisterID mask)425     Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask)
426     {
427         ASSERT((cond == Zero) || (cond == NonZero));
428         m_assembler.tst_r(reg, mask);
429         return Jump(m_assembler.jmp(ARMCondition(cond)));
430     }
431 
432     Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1))
433     {
434         ASSERT((cond == Zero) || (cond == NonZero));
435         ARMWord w = m_assembler.getImm(mask.m_value, ARMRegisters::S0, true);
436         if (w & ARMAssembler::OP2_INV_IMM)
437             m_assembler.bics_r(ARMRegisters::S0, reg, w & ~ARMAssembler::OP2_INV_IMM);
438         else
439             m_assembler.tst_r(reg, w);
440         return Jump(m_assembler.jmp(ARMCondition(cond)));
441     }
442 
443     Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1))
444     {
445         load32(address, ARMRegisters::S1);
446         return branchTest32(cond, ARMRegisters::S1, mask);
447     }
448 
449     Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1))
450     {
451         load32(address, ARMRegisters::S1);
452         return branchTest32(cond, ARMRegisters::S1, mask);
453     }
454 
jump()455     Jump jump()
456     {
457         return Jump(m_assembler.jmp());
458     }
459 
jump(RegisterID target)460     void jump(RegisterID target)
461     {
462         move(target, ARMRegisters::pc);
463     }
464 
jump(Address address)465     void jump(Address address)
466     {
467         load32(address, ARMRegisters::pc);
468     }
469 
branchAdd32(Condition cond,RegisterID src,RegisterID dest)470     Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest)
471     {
472         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
473         add32(src, dest);
474         return Jump(m_assembler.jmp(ARMCondition(cond)));
475     }
476 
branchAdd32(Condition cond,Imm32 imm,RegisterID dest)477     Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest)
478     {
479         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
480         add32(imm, dest);
481         return Jump(m_assembler.jmp(ARMCondition(cond)));
482     }
483 
mull32(RegisterID src1,RegisterID src2,RegisterID dest)484     void mull32(RegisterID src1, RegisterID src2, RegisterID dest)
485     {
486         if (src1 == dest) {
487             move(src1, ARMRegisters::S0);
488             src1 = ARMRegisters::S0;
489         }
490         m_assembler.mull_r(ARMRegisters::S1, dest, src2, src1);
491         m_assembler.cmp_r(ARMRegisters::S1, m_assembler.asr(dest, 31));
492     }
493 
branchMul32(Condition cond,RegisterID src,RegisterID dest)494     Jump branchMul32(Condition cond, RegisterID src, RegisterID dest)
495     {
496         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
497         if (cond == Overflow) {
498             mull32(src, dest, dest);
499             cond = NonZero;
500         }
501         else
502             mul32(src, dest);
503         return Jump(m_assembler.jmp(ARMCondition(cond)));
504     }
505 
branchMul32(Condition cond,Imm32 imm,RegisterID src,RegisterID dest)506     Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest)
507     {
508         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
509         if (cond == Overflow) {
510             move(imm, ARMRegisters::S0);
511             mull32(ARMRegisters::S0, src, dest);
512             cond = NonZero;
513         }
514         else
515             mul32(imm, src, dest);
516         return Jump(m_assembler.jmp(ARMCondition(cond)));
517     }
518 
branchSub32(Condition cond,RegisterID src,RegisterID dest)519     Jump branchSub32(Condition cond, RegisterID src, RegisterID dest)
520     {
521         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
522         sub32(src, dest);
523         return Jump(m_assembler.jmp(ARMCondition(cond)));
524     }
525 
branchSub32(Condition cond,Imm32 imm,RegisterID dest)526     Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest)
527     {
528         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
529         sub32(imm, dest);
530         return Jump(m_assembler.jmp(ARMCondition(cond)));
531     }
532 
branchOr32(Condition cond,RegisterID src,RegisterID dest)533     Jump branchOr32(Condition cond, RegisterID src, RegisterID dest)
534     {
535         ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero));
536         or32(src, dest);
537         return Jump(m_assembler.jmp(ARMCondition(cond)));
538     }
539 
breakpoint()540     void breakpoint()
541     {
542         m_assembler.bkpt(0);
543     }
544 
nearCall()545     Call nearCall()
546     {
547         prepareCall();
548         return Call(m_assembler.jmp(ARMAssembler::AL, true), Call::LinkableNear);
549     }
550 
call(RegisterID target)551     Call call(RegisterID target)
552     {
553         prepareCall();
554         move(ARMRegisters::pc, target);
555         JmpSrc jmpSrc;
556         return Call(jmpSrc, Call::None);
557     }
558 
call(Address address)559     void call(Address address)
560     {
561         call32(address.base, address.offset);
562     }
563 
ret()564     void ret()
565     {
566         m_assembler.mov_r(ARMRegisters::pc, linkRegister);
567     }
568 
set32(Condition cond,RegisterID left,RegisterID right,RegisterID dest)569     void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
570     {
571         m_assembler.cmp_r(left, right);
572         m_assembler.mov_r(dest, ARMAssembler::getOp2(0));
573         m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond));
574     }
575 
set32(Condition cond,RegisterID left,Imm32 right,RegisterID dest)576     void set32(Condition cond, RegisterID left, Imm32 right, RegisterID dest)
577     {
578         m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0));
579         m_assembler.mov_r(dest, ARMAssembler::getOp2(0));
580         m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond));
581     }
582 
set8(Condition cond,RegisterID left,RegisterID right,RegisterID dest)583     void set8(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
584     {
585         // ARM doesn't have byte registers
586         set32(cond, left, right, dest);
587     }
588 
set8(Condition cond,Address left,RegisterID right,RegisterID dest)589     void set8(Condition cond, Address left, RegisterID right, RegisterID dest)
590     {
591         // ARM doesn't have byte registers
592         load32(left, ARMRegisters::S1);
593         set32(cond, ARMRegisters::S1, right, dest);
594     }
595 
set8(Condition cond,RegisterID left,Imm32 right,RegisterID dest)596     void set8(Condition cond, RegisterID left, Imm32 right, RegisterID dest)
597     {
598         // ARM doesn't have byte registers
599         set32(cond, left, right, dest);
600     }
601 
setTest32(Condition cond,Address address,Imm32 mask,RegisterID dest)602     void setTest32(Condition cond, Address address, Imm32 mask, RegisterID dest)
603     {
604         load32(address, ARMRegisters::S1);
605         if (mask.m_value == -1)
606             m_assembler.cmp_r(0, ARMRegisters::S1);
607         else
608             m_assembler.tst_r(ARMRegisters::S1, m_assembler.getImm(mask.m_value, ARMRegisters::S0));
609         m_assembler.mov_r(dest, ARMAssembler::getOp2(0));
610         m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond));
611     }
612 
setTest8(Condition cond,Address address,Imm32 mask,RegisterID dest)613     void setTest8(Condition cond, Address address, Imm32 mask, RegisterID dest)
614     {
615         // ARM doesn't have byte registers
616         setTest32(cond, address, mask, dest);
617     }
618 
add32(Imm32 imm,RegisterID src,RegisterID dest)619     void add32(Imm32 imm, RegisterID src, RegisterID dest)
620     {
621         m_assembler.add_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
622     }
623 
add32(Imm32 imm,AbsoluteAddress address)624     void add32(Imm32 imm, AbsoluteAddress address)
625     {
626         m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast<ARMWord>(address.m_ptr));
627         m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0);
628         add32(imm, ARMRegisters::S1);
629         m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address.m_ptr));
630         m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0);
631     }
632 
sub32(Imm32 imm,AbsoluteAddress address)633     void sub32(Imm32 imm, AbsoluteAddress address)
634     {
635         m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast<ARMWord>(address.m_ptr));
636         m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0);
637         sub32(imm, ARMRegisters::S1);
638         m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address.m_ptr));
639         m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0);
640     }
641 
load32(void * address,RegisterID dest)642     void load32(void* address, RegisterID dest)
643     {
644         m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address));
645         m_assembler.dtr_u(true, dest, ARMRegisters::S0, 0);
646     }
647 
branch32(Condition cond,AbsoluteAddress left,RegisterID right)648     Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right)
649     {
650         load32(left.m_ptr, ARMRegisters::S1);
651         return branch32(cond, ARMRegisters::S1, right);
652     }
653 
branch32(Condition cond,AbsoluteAddress left,Imm32 right)654     Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
655     {
656         load32(left.m_ptr, ARMRegisters::S1);
657         return branch32(cond, ARMRegisters::S1, right);
658     }
659 
call()660     Call call()
661     {
662         prepareCall();
663         return Call(m_assembler.jmp(ARMAssembler::AL, true), Call::Linkable);
664     }
665 
tailRecursiveCall()666     Call tailRecursiveCall()
667     {
668         return Call::fromTailJump(jump());
669     }
670 
makeTailRecursiveCall(Jump oldJump)671     Call makeTailRecursiveCall(Jump oldJump)
672     {
673         return Call::fromTailJump(oldJump);
674     }
675 
moveWithPatch(ImmPtr initialValue,RegisterID dest)676     DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
677     {
678         DataLabelPtr dataLabel(this);
679         m_assembler.ldr_un_imm(dest, reinterpret_cast<ARMWord>(initialValue.m_value));
680         return dataLabel;
681     }
682 
683     Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
684     {
685         dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S1);
686         Jump jump = branch32(cond, left, ARMRegisters::S1, true);
687         return jump;
688     }
689 
690     Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
691     {
692         load32(left, ARMRegisters::S1);
693         dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S0);
694         Jump jump = branch32(cond, ARMRegisters::S0, ARMRegisters::S1, true);
695         return jump;
696     }
697 
storePtrWithPatch(ImmPtr initialValue,ImplicitAddress address)698     DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
699     {
700         DataLabelPtr dataLabel = moveWithPatch(initialValue, ARMRegisters::S1);
701         store32(ARMRegisters::S1, address);
702         return dataLabel;
703     }
704 
storePtrWithPatch(ImplicitAddress address)705     DataLabelPtr storePtrWithPatch(ImplicitAddress address)
706     {
707         return storePtrWithPatch(ImmPtr(0), address);
708     }
709 
710     // Floating point operators
supportsFloatingPoint()711     bool supportsFloatingPoint() const
712     {
713         return s_isVFPPresent;
714     }
715 
supportsFloatingPointTruncate()716     bool supportsFloatingPointTruncate() const
717     {
718         return false;
719     }
720 
loadDouble(ImplicitAddress address,FPRegisterID dest)721     void loadDouble(ImplicitAddress address, FPRegisterID dest)
722     {
723         m_assembler.doubleTransfer(true, dest, address.base, address.offset);
724     }
725 
loadDouble(void * address,FPRegisterID dest)726     void loadDouble(void* address, FPRegisterID dest)
727     {
728         m_assembler.ldr_un_imm(ARMRegisters::S0, (ARMWord)address);
729         m_assembler.fdtr_u(true, dest, ARMRegisters::S0, 0);
730     }
731 
storeDouble(FPRegisterID src,ImplicitAddress address)732     void storeDouble(FPRegisterID src, ImplicitAddress address)
733     {
734         m_assembler.doubleTransfer(false, src, address.base, address.offset);
735     }
736 
addDouble(FPRegisterID src,FPRegisterID dest)737     void addDouble(FPRegisterID src, FPRegisterID dest)
738     {
739         m_assembler.faddd_r(dest, dest, src);
740     }
741 
addDouble(Address src,FPRegisterID dest)742     void addDouble(Address src, FPRegisterID dest)
743     {
744         loadDouble(src, ARMRegisters::SD0);
745         addDouble(ARMRegisters::SD0, dest);
746     }
747 
divDouble(FPRegisterID src,FPRegisterID dest)748     void divDouble(FPRegisterID src, FPRegisterID dest)
749     {
750         m_assembler.fdivd_r(dest, dest, src);
751     }
752 
divDouble(Address src,FPRegisterID dest)753     void divDouble(Address src, FPRegisterID dest)
754     {
755         ASSERT_NOT_REACHED(); // Untested
756         loadDouble(src, ARMRegisters::SD0);
757         divDouble(ARMRegisters::SD0, dest);
758     }
759 
subDouble(FPRegisterID src,FPRegisterID dest)760     void subDouble(FPRegisterID src, FPRegisterID dest)
761     {
762         m_assembler.fsubd_r(dest, dest, src);
763     }
764 
subDouble(Address src,FPRegisterID dest)765     void subDouble(Address src, FPRegisterID dest)
766     {
767         loadDouble(src, ARMRegisters::SD0);
768         subDouble(ARMRegisters::SD0, dest);
769     }
770 
mulDouble(FPRegisterID src,FPRegisterID dest)771     void mulDouble(FPRegisterID src, FPRegisterID dest)
772     {
773         m_assembler.fmuld_r(dest, dest, src);
774     }
775 
mulDouble(Address src,FPRegisterID dest)776     void mulDouble(Address src, FPRegisterID dest)
777     {
778         loadDouble(src, ARMRegisters::SD0);
779         mulDouble(ARMRegisters::SD0, dest);
780     }
781 
convertInt32ToDouble(RegisterID src,FPRegisterID dest)782     void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
783     {
784         m_assembler.fmsr_r(dest, src);
785         m_assembler.fsitod_r(dest, dest);
786     }
787 
convertInt32ToDouble(Address src,FPRegisterID dest)788     void convertInt32ToDouble(Address src, FPRegisterID dest)
789     {
790         ASSERT_NOT_REACHED(); // Untested
791         // flds does not worth the effort here
792         load32(src, ARMRegisters::S1);
793         convertInt32ToDouble(ARMRegisters::S1, dest);
794     }
795 
convertInt32ToDouble(AbsoluteAddress src,FPRegisterID dest)796     void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest)
797     {
798         ASSERT_NOT_REACHED(); // Untested
799         // flds does not worth the effort here
800         m_assembler.ldr_un_imm(ARMRegisters::S1, (ARMWord)src.m_ptr);
801         m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0);
802         convertInt32ToDouble(ARMRegisters::S1, dest);
803     }
804 
branchDouble(DoubleCondition cond,FPRegisterID left,FPRegisterID right)805     Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
806     {
807         m_assembler.fcmpd_r(left, right);
808         m_assembler.fmstat();
809         if (cond & DoubleConditionBitSpecial)
810             m_assembler.cmp_r(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::VS);
811         return Jump(m_assembler.jmp(static_cast<ARMAssembler::Condition>(cond & ~DoubleConditionMask)));
812     }
813 
814     // Truncates 'src' to an integer, and places the resulting 'dest'.
815     // If the result is not representable as a 32 bit value, branch.
816     // May also branch for some values that are representable in 32 bits
817     // (specifically, in this case, INT_MIN).
branchTruncateDoubleToInt32(FPRegisterID src,RegisterID dest)818     Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest)
819     {
820         UNUSED_PARAM(src);
821         UNUSED_PARAM(dest);
822         ASSERT_NOT_REACHED();
823         return jump();
824     }
825 
826     // Convert 'src' to an integer, and places the resulting 'dest'.
827     // If the result is not representable as a 32 bit value, branch.
828     // May also branch for some values that are representable in 32 bits
829     // (specifically, in this case, 0).
branchConvertDoubleToInt32(FPRegisterID src,RegisterID dest,JumpList & failureCases,FPRegisterID fpTemp)830     void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp)
831     {
832         m_assembler.ftosid_r(ARMRegisters::SD0, src);
833         m_assembler.fmrs_r(dest, ARMRegisters::SD0);
834 
835         // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
836         m_assembler.fsitod_r(ARMRegisters::SD0, ARMRegisters::SD0);
837         failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, ARMRegisters::SD0));
838 
839         // If the result is zero, it might have been -0.0, and 0.0 equals to -0.0
840         failureCases.append(branchTest32(Zero, dest));
841     }
842 
zeroDouble(FPRegisterID srcDest)843     void zeroDouble(FPRegisterID srcDest)
844     {
845         m_assembler.mov_r(ARMRegisters::S0, ARMAssembler::getOp2(0));
846         convertInt32ToDouble(ARMRegisters::S0, srcDest);
847     }
848 
849 protected:
ARMCondition(Condition cond)850     ARMAssembler::Condition ARMCondition(Condition cond)
851     {
852         return static_cast<ARMAssembler::Condition>(cond);
853     }
854 
ensureSpace(int insnSpace,int constSpace)855     void ensureSpace(int insnSpace, int constSpace)
856     {
857         m_assembler.ensureSpace(insnSpace, constSpace);
858     }
859 
sizeOfConstantPool()860     int sizeOfConstantPool()
861     {
862         return m_assembler.sizeOfConstantPool();
863     }
864 
prepareCall()865     void prepareCall()
866     {
867         ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord));
868 
869         m_assembler.mov_r(linkRegister, ARMRegisters::pc);
870     }
871 
call32(RegisterID base,int32_t offset)872     void call32(RegisterID base, int32_t offset)
873     {
874         if (base == ARMRegisters::sp)
875             offset += 4;
876 
877         if (offset >= 0) {
878             if (offset <= 0xfff) {
879                 prepareCall();
880                 m_assembler.dtr_u(true, ARMRegisters::pc, base, offset);
881             } else if (offset <= 0xfffff) {
882                 m_assembler.add_r(ARMRegisters::S0, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8));
883                 prepareCall();
884                 m_assembler.dtr_u(true, ARMRegisters::pc, ARMRegisters::S0, offset & 0xfff);
885             } else {
886                 ARMWord reg = m_assembler.getImm(offset, ARMRegisters::S0);
887                 prepareCall();
888                 m_assembler.dtr_ur(true, ARMRegisters::pc, base, reg);
889             }
890         } else  {
891             offset = -offset;
892             if (offset <= 0xfff) {
893                 prepareCall();
894                 m_assembler.dtr_d(true, ARMRegisters::pc, base, offset);
895             } else if (offset <= 0xfffff) {
896                 m_assembler.sub_r(ARMRegisters::S0, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8));
897                 prepareCall();
898                 m_assembler.dtr_d(true, ARMRegisters::pc, ARMRegisters::S0, offset & 0xfff);
899             } else {
900                 ARMWord reg = m_assembler.getImm(offset, ARMRegisters::S0);
901                 prepareCall();
902                 m_assembler.dtr_dr(true, ARMRegisters::pc, base, reg);
903             }
904         }
905     }
906 
907 private:
908     friend class LinkBuffer;
909     friend class RepatchBuffer;
910 
linkCall(void * code,Call call,FunctionPtr function)911     static void linkCall(void* code, Call call, FunctionPtr function)
912     {
913         ARMAssembler::linkCall(code, call.m_jmp, function.value());
914     }
915 
repatchCall(CodeLocationCall call,CodeLocationLabel destination)916     static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
917     {
918         ARMAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
919     }
920 
repatchCall(CodeLocationCall call,FunctionPtr destination)921     static void repatchCall(CodeLocationCall call, FunctionPtr destination)
922     {
923         ARMAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
924     }
925 
926     static const bool s_isVFPPresent;
927 };
928 
929 }
930 
931 #endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
932 
933 #endif // MacroAssemblerARM_h
934