• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 Apple Inc.
3  * Copyright (C) 2009, 2010 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 #if ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
32 
33 #include "ARMAssembler.h"
34 #include "AbstractMacroAssembler.h"
35 
36 namespace JSC {
37 
38 class MacroAssemblerARM : public AbstractMacroAssembler<ARMAssembler> {
39     static const int DoubleConditionMask = 0x0f;
40     static const int DoubleConditionBitSpecial = 0x10;
41     COMPILE_ASSERT(!(DoubleConditionBitSpecial & DoubleConditionMask), DoubleConditionBitSpecial_should_not_interfere_with_ARMAssembler_Condition_codes);
42 public:
43     typedef ARMRegisters::FPRegisterID FPRegisterID;
44 
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(TrustedImm32 imm,Address address)89     void add32(TrustedImm32 imm, Address address)
90     {
91         load32(address, ARMRegisters::S1);
92         add32(imm, ARMRegisters::S1);
93         store32(ARMRegisters::S1, address);
94     }
95 
add32(TrustedImm32 imm,RegisterID dest)96     void add32(TrustedImm32 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(TrustedImm32 imm,RegisterID dest)112     void and32(TrustedImm32 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(TrustedImm32 imm,RegisterID dest)130     void lshift32(TrustedImm32 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(TrustedImm32 imm,RegisterID src,RegisterID dest)144     void mul32(TrustedImm32 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(TrustedImm32 imm,RegisterID dest)165     void or32(TrustedImm32 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(TrustedImm32 imm,RegisterID dest)179     void rshift32(TrustedImm32 imm, RegisterID dest)
180     {
181         m_assembler.movs_r(dest, m_assembler.asr(dest, imm.m_value & 0x1f));
182     }
183 
urshift32(RegisterID shift_amount,RegisterID dest)184     void urshift32(RegisterID shift_amount, RegisterID dest)
185     {
186         ARMWord w = ARMAssembler::getOp2(0x1f);
187         ASSERT(w != ARMAssembler::INVALID_IMM);
188         m_assembler.and_r(ARMRegisters::S0, shift_amount, w);
189 
190         m_assembler.movs_r(dest, m_assembler.lsr_r(dest, ARMRegisters::S0));
191     }
192 
urshift32(TrustedImm32 imm,RegisterID dest)193     void urshift32(TrustedImm32 imm, RegisterID dest)
194     {
195         m_assembler.movs_r(dest, m_assembler.lsr(dest, imm.m_value & 0x1f));
196     }
197 
sub32(RegisterID src,RegisterID dest)198     void sub32(RegisterID src, RegisterID dest)
199     {
200         m_assembler.subs_r(dest, dest, src);
201     }
202 
sub32(TrustedImm32 imm,RegisterID dest)203     void sub32(TrustedImm32 imm, RegisterID dest)
204     {
205         m_assembler.subs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
206     }
207 
sub32(TrustedImm32 imm,Address address)208     void sub32(TrustedImm32 imm, Address address)
209     {
210         load32(address, ARMRegisters::S1);
211         sub32(imm, ARMRegisters::S1);
212         store32(ARMRegisters::S1, address);
213     }
214 
sub32(Address src,RegisterID dest)215     void sub32(Address src, RegisterID dest)
216     {
217         load32(src, ARMRegisters::S1);
218         sub32(ARMRegisters::S1, dest);
219     }
220 
xor32(RegisterID src,RegisterID dest)221     void xor32(RegisterID src, RegisterID dest)
222     {
223         m_assembler.eors_r(dest, dest, src);
224     }
225 
xor32(TrustedImm32 imm,RegisterID dest)226     void xor32(TrustedImm32 imm, RegisterID dest)
227     {
228         m_assembler.eors_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
229     }
230 
countLeadingZeros32(RegisterID src,RegisterID dest)231     void countLeadingZeros32(RegisterID src, RegisterID dest)
232     {
233 #if WTF_ARM_ARCH_AT_LEAST(5)
234         m_assembler.clz_r(dest, src);
235 #else
236         UNUSED_PARAM(src);
237         UNUSED_PARAM(dest);
238         ASSERT_NOT_REACHED();
239 #endif
240     }
241 
load8(ImplicitAddress address,RegisterID dest)242     void load8(ImplicitAddress address, RegisterID dest)
243     {
244         m_assembler.dataTransfer32(true, dest, address.base, address.offset, true);
245     }
246 
load32(ImplicitAddress address,RegisterID dest)247     void load32(ImplicitAddress address, RegisterID dest)
248     {
249         m_assembler.dataTransfer32(true, dest, address.base, address.offset);
250     }
251 
load32(BaseIndex address,RegisterID dest)252     void load32(BaseIndex address, RegisterID dest)
253     {
254         m_assembler.baseIndexTransfer32(true, dest, address.base, address.index, static_cast<int>(address.scale), address.offset);
255     }
256 
257 #if CPU(ARMV5_OR_LOWER)
258     void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest);
259 #else
load32WithUnalignedHalfWords(BaseIndex address,RegisterID dest)260     void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
261     {
262         load32(address, dest);
263     }
264 #endif
265 
load32WithAddressOffsetPatch(Address address,RegisterID dest)266     DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
267     {
268         DataLabel32 dataLabel(this);
269         m_assembler.ldr_un_imm(ARMRegisters::S0, 0);
270         m_assembler.dtr_ur(true, dest, address.base, ARMRegisters::S0);
271         return dataLabel;
272     }
273 
load16(BaseIndex address,RegisterID dest)274     void load16(BaseIndex address, RegisterID dest)
275     {
276         m_assembler.add_r(ARMRegisters::S1, address.base, m_assembler.lsl(address.index, address.scale));
277         load16(Address(ARMRegisters::S1, address.offset), dest);
278     }
279 
load16(ImplicitAddress address,RegisterID dest)280     void load16(ImplicitAddress address, RegisterID dest)
281     {
282         if (address.offset >= 0)
283             m_assembler.ldrh_u(dest, address.base, m_assembler.getOffsetForHalfwordDataTransfer(address.offset, ARMRegisters::S0));
284         else
285             m_assembler.ldrh_d(dest, address.base, m_assembler.getOffsetForHalfwordDataTransfer(-address.offset, ARMRegisters::S0));
286     }
287 
store32WithAddressOffsetPatch(RegisterID src,Address address)288     DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
289     {
290         DataLabel32 dataLabel(this);
291         m_assembler.ldr_un_imm(ARMRegisters::S0, 0);
292         m_assembler.dtr_ur(false, src, address.base, ARMRegisters::S0);
293         return dataLabel;
294     }
295 
store32(RegisterID src,ImplicitAddress address)296     void store32(RegisterID src, ImplicitAddress address)
297     {
298         m_assembler.dataTransfer32(false, src, address.base, address.offset);
299     }
300 
store32(RegisterID src,BaseIndex address)301     void store32(RegisterID src, BaseIndex address)
302     {
303         m_assembler.baseIndexTransfer32(false, src, address.base, address.index, static_cast<int>(address.scale), address.offset);
304     }
305 
store32(TrustedImm32 imm,ImplicitAddress address)306     void store32(TrustedImm32 imm, ImplicitAddress address)
307     {
308         if (imm.m_isPointer)
309             m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value);
310         else
311             move(imm, ARMRegisters::S1);
312         store32(ARMRegisters::S1, address);
313     }
314 
store32(RegisterID src,void * address)315     void store32(RegisterID src, void* address)
316     {
317         m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address));
318         m_assembler.dtr_u(false, src, ARMRegisters::S0, 0);
319     }
320 
store32(TrustedImm32 imm,void * address)321     void store32(TrustedImm32 imm, void* address)
322     {
323         m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address));
324         if (imm.m_isPointer)
325             m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value);
326         else
327             m_assembler.moveImm(imm.m_value, ARMRegisters::S1);
328         m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0);
329     }
330 
pop(RegisterID dest)331     void pop(RegisterID dest)
332     {
333         m_assembler.pop_r(dest);
334     }
335 
push(RegisterID src)336     void push(RegisterID src)
337     {
338         m_assembler.push_r(src);
339     }
340 
push(Address address)341     void push(Address address)
342     {
343         load32(address, ARMRegisters::S1);
344         push(ARMRegisters::S1);
345     }
346 
push(TrustedImm32 imm)347     void push(TrustedImm32 imm)
348     {
349         move(imm, ARMRegisters::S0);
350         push(ARMRegisters::S0);
351     }
352 
move(TrustedImm32 imm,RegisterID dest)353     void move(TrustedImm32 imm, RegisterID dest)
354     {
355         if (imm.m_isPointer)
356             m_assembler.ldr_un_imm(dest, imm.m_value);
357         else
358             m_assembler.moveImm(imm.m_value, dest);
359     }
360 
move(RegisterID src,RegisterID dest)361     void move(RegisterID src, RegisterID dest)
362     {
363         m_assembler.mov_r(dest, src);
364     }
365 
move(TrustedImmPtr imm,RegisterID dest)366     void move(TrustedImmPtr imm, RegisterID dest)
367     {
368         move(TrustedImm32(imm), dest);
369     }
370 
swap(RegisterID reg1,RegisterID reg2)371     void swap(RegisterID reg1, RegisterID reg2)
372     {
373         m_assembler.mov_r(ARMRegisters::S0, reg1);
374         m_assembler.mov_r(reg1, reg2);
375         m_assembler.mov_r(reg2, ARMRegisters::S0);
376     }
377 
signExtend32ToPtr(RegisterID src,RegisterID dest)378     void signExtend32ToPtr(RegisterID src, RegisterID dest)
379     {
380         if (src != dest)
381             move(src, dest);
382     }
383 
zeroExtend32ToPtr(RegisterID src,RegisterID dest)384     void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
385     {
386         if (src != dest)
387             move(src, dest);
388     }
389 
branch8(Condition cond,Address left,TrustedImm32 right)390     Jump branch8(Condition cond, Address left, TrustedImm32 right)
391     {
392         load8(left, ARMRegisters::S1);
393         return branch32(cond, ARMRegisters::S1, right);
394     }
395 
396     Jump branch32(Condition cond, RegisterID left, RegisterID right, int useConstantPool = 0)
397     {
398         m_assembler.cmp_r(left, right);
399         return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool));
400     }
401 
402     Jump branch32(Condition cond, RegisterID left, TrustedImm32 right, int useConstantPool = 0)
403     {
404         if (right.m_isPointer) {
405             m_assembler.ldr_un_imm(ARMRegisters::S0, right.m_value);
406             m_assembler.cmp_r(left, ARMRegisters::S0);
407         } else {
408             ARMWord tmp = m_assembler.getOp2(-right.m_value);
409             if (tmp != ARMAssembler::INVALID_IMM)
410                 m_assembler.cmn_r(left, tmp);
411             else
412                 m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0));
413         }
414         return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool));
415     }
416 
branch32(Condition cond,RegisterID left,Address right)417     Jump branch32(Condition cond, RegisterID left, Address right)
418     {
419         load32(right, ARMRegisters::S1);
420         return branch32(cond, left, ARMRegisters::S1);
421     }
422 
branch32(Condition cond,Address left,RegisterID right)423     Jump branch32(Condition cond, Address left, RegisterID right)
424     {
425         load32(left, ARMRegisters::S1);
426         return branch32(cond, ARMRegisters::S1, right);
427     }
428 
branch32(Condition cond,Address left,TrustedImm32 right)429     Jump branch32(Condition cond, Address left, TrustedImm32 right)
430     {
431         load32(left, ARMRegisters::S1);
432         return branch32(cond, ARMRegisters::S1, right);
433     }
434 
branch32(Condition cond,BaseIndex left,TrustedImm32 right)435     Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
436     {
437         load32(left, ARMRegisters::S1);
438         return branch32(cond, ARMRegisters::S1, right);
439     }
440 
branch32WithUnalignedHalfWords(Condition cond,BaseIndex left,TrustedImm32 right)441     Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
442     {
443         load32WithUnalignedHalfWords(left, ARMRegisters::S1);
444         return branch32(cond, ARMRegisters::S1, right);
445     }
446 
branch16(Condition cond,BaseIndex left,RegisterID right)447     Jump branch16(Condition cond, BaseIndex left, RegisterID right)
448     {
449         UNUSED_PARAM(cond);
450         UNUSED_PARAM(left);
451         UNUSED_PARAM(right);
452         ASSERT_NOT_REACHED();
453         return jump();
454     }
455 
branch16(Condition cond,BaseIndex left,TrustedImm32 right)456     Jump branch16(Condition cond, BaseIndex left, TrustedImm32 right)
457     {
458         load16(left, ARMRegisters::S0);
459         move(right, ARMRegisters::S1);
460         m_assembler.cmp_r(ARMRegisters::S0, ARMRegisters::S1);
461         return m_assembler.jmp(ARMCondition(cond));
462     }
463 
464     Jump branchTest8(Condition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
465     {
466         load8(address, ARMRegisters::S1);
467         return branchTest32(cond, ARMRegisters::S1, mask);
468     }
469 
branchTest32(Condition cond,RegisterID reg,RegisterID mask)470     Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask)
471     {
472         ASSERT((cond == Zero) || (cond == NonZero));
473         m_assembler.tst_r(reg, mask);
474         return Jump(m_assembler.jmp(ARMCondition(cond)));
475     }
476 
477     Jump branchTest32(Condition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
478     {
479         ASSERT((cond == Zero) || (cond == NonZero));
480         ARMWord w = m_assembler.getImm(mask.m_value, ARMRegisters::S0, true);
481         if (w & ARMAssembler::OP2_INV_IMM)
482             m_assembler.bics_r(ARMRegisters::S0, reg, w & ~ARMAssembler::OP2_INV_IMM);
483         else
484             m_assembler.tst_r(reg, w);
485         return Jump(m_assembler.jmp(ARMCondition(cond)));
486     }
487 
488     Jump branchTest32(Condition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
489     {
490         load32(address, ARMRegisters::S1);
491         return branchTest32(cond, ARMRegisters::S1, mask);
492     }
493 
494     Jump branchTest32(Condition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
495     {
496         load32(address, ARMRegisters::S1);
497         return branchTest32(cond, ARMRegisters::S1, mask);
498     }
499 
jump()500     Jump jump()
501     {
502         return Jump(m_assembler.jmp());
503     }
504 
jump(RegisterID target)505     void jump(RegisterID target)
506     {
507         m_assembler.bx(target);
508     }
509 
jump(Address address)510     void jump(Address address)
511     {
512         load32(address, ARMRegisters::pc);
513     }
514 
branchAdd32(Condition cond,RegisterID src,RegisterID dest)515     Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest)
516     {
517         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
518         add32(src, dest);
519         return Jump(m_assembler.jmp(ARMCondition(cond)));
520     }
521 
branchAdd32(Condition cond,TrustedImm32 imm,RegisterID dest)522     Jump branchAdd32(Condition cond, TrustedImm32 imm, RegisterID dest)
523     {
524         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
525         add32(imm, dest);
526         return Jump(m_assembler.jmp(ARMCondition(cond)));
527     }
528 
mull32(RegisterID src1,RegisterID src2,RegisterID dest)529     void mull32(RegisterID src1, RegisterID src2, RegisterID dest)
530     {
531         if (src1 == dest) {
532             move(src1, ARMRegisters::S0);
533             src1 = ARMRegisters::S0;
534         }
535         m_assembler.mull_r(ARMRegisters::S1, dest, src2, src1);
536         m_assembler.cmp_r(ARMRegisters::S1, m_assembler.asr(dest, 31));
537     }
538 
branchMul32(Condition cond,RegisterID src,RegisterID dest)539     Jump branchMul32(Condition cond, RegisterID src, RegisterID dest)
540     {
541         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
542         if (cond == Overflow) {
543             mull32(src, dest, dest);
544             cond = NonZero;
545         }
546         else
547             mul32(src, dest);
548         return Jump(m_assembler.jmp(ARMCondition(cond)));
549     }
550 
branchMul32(Condition cond,TrustedImm32 imm,RegisterID src,RegisterID dest)551     Jump branchMul32(Condition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
552     {
553         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
554         if (cond == Overflow) {
555             move(imm, ARMRegisters::S0);
556             mull32(ARMRegisters::S0, src, dest);
557             cond = NonZero;
558         }
559         else
560             mul32(imm, src, dest);
561         return Jump(m_assembler.jmp(ARMCondition(cond)));
562     }
563 
branchSub32(Condition cond,RegisterID src,RegisterID dest)564     Jump branchSub32(Condition cond, RegisterID src, RegisterID dest)
565     {
566         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
567         sub32(src, dest);
568         return Jump(m_assembler.jmp(ARMCondition(cond)));
569     }
570 
branchSub32(Condition cond,TrustedImm32 imm,RegisterID dest)571     Jump branchSub32(Condition cond, TrustedImm32 imm, RegisterID dest)
572     {
573         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
574         sub32(imm, dest);
575         return Jump(m_assembler.jmp(ARMCondition(cond)));
576     }
577 
branchNeg32(Condition cond,RegisterID srcDest)578     Jump branchNeg32(Condition cond, RegisterID srcDest)
579     {
580         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
581         neg32(srcDest);
582         return Jump(m_assembler.jmp(ARMCondition(cond)));
583     }
584 
branchOr32(Condition cond,RegisterID src,RegisterID dest)585     Jump branchOr32(Condition cond, RegisterID src, RegisterID dest)
586     {
587         ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero));
588         or32(src, dest);
589         return Jump(m_assembler.jmp(ARMCondition(cond)));
590     }
591 
breakpoint()592     void breakpoint()
593     {
594         m_assembler.bkpt(0);
595     }
596 
nearCall()597     Call nearCall()
598     {
599 #if WTF_ARM_ARCH_AT_LEAST(5)
600         ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord));
601         m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true);
602         return Call(m_assembler.blx(ARMRegisters::S1), Call::LinkableNear);
603 #else
604         prepareCall();
605         return Call(m_assembler.jmp(ARMAssembler::AL, true), Call::LinkableNear);
606 #endif
607     }
608 
call(RegisterID target)609     Call call(RegisterID target)
610     {
611         return Call(m_assembler.blx(target), Call::None);
612     }
613 
call(Address address)614     void call(Address address)
615     {
616         call32(address.base, address.offset);
617     }
618 
ret()619     void ret()
620     {
621         m_assembler.bx(linkRegister);
622     }
623 
set32Compare32(Condition cond,RegisterID left,RegisterID right,RegisterID dest)624     void set32Compare32(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
625     {
626         m_assembler.cmp_r(left, right);
627         m_assembler.mov_r(dest, ARMAssembler::getOp2(0));
628         m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond));
629     }
630 
set32Compare32(Condition cond,RegisterID left,TrustedImm32 right,RegisterID dest)631     void set32Compare32(Condition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
632     {
633         m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0));
634         m_assembler.mov_r(dest, ARMAssembler::getOp2(0));
635         m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond));
636     }
637 
set8Compare32(Condition cond,RegisterID left,RegisterID right,RegisterID dest)638     void set8Compare32(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
639     {
640         // ARM doesn't have byte registers
641         set32Compare32(cond, left, right, dest);
642     }
643 
set8Compare32(Condition cond,Address left,RegisterID right,RegisterID dest)644     void set8Compare32(Condition cond, Address left, RegisterID right, RegisterID dest)
645     {
646         // ARM doesn't have byte registers
647         load32(left, ARMRegisters::S1);
648         set32Compare32(cond, ARMRegisters::S1, right, dest);
649     }
650 
set8Compare32(Condition cond,RegisterID left,TrustedImm32 right,RegisterID dest)651     void set8Compare32(Condition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
652     {
653         // ARM doesn't have byte registers
654         set32Compare32(cond, left, right, dest);
655     }
656 
set32Test32(Condition cond,RegisterID reg,TrustedImm32 mask,RegisterID dest)657     void set32Test32(Condition cond, RegisterID reg, TrustedImm32 mask, RegisterID dest)
658     {
659         if (mask.m_value == -1)
660             m_assembler.cmp_r(0, reg);
661         else
662             m_assembler.tst_r(reg, m_assembler.getImm(mask.m_value, ARMRegisters::S0));
663         m_assembler.mov_r(dest, ARMAssembler::getOp2(0));
664         m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond));
665     }
666 
set32Test32(Condition cond,Address address,TrustedImm32 mask,RegisterID dest)667     void set32Test32(Condition cond, Address address, TrustedImm32 mask, RegisterID dest)
668     {
669         load32(address, ARMRegisters::S1);
670         set32Test32(cond, ARMRegisters::S1, mask, dest);
671     }
672 
set32Test8(Condition cond,Address address,TrustedImm32 mask,RegisterID dest)673     void set32Test8(Condition cond, Address address, TrustedImm32 mask, RegisterID dest)
674     {
675         load8(address, ARMRegisters::S1);
676         set32Test32(cond, ARMRegisters::S1, mask, dest);
677     }
678 
add32(TrustedImm32 imm,RegisterID src,RegisterID dest)679     void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
680     {
681         m_assembler.add_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
682     }
683 
add32(TrustedImm32 imm,AbsoluteAddress address)684     void add32(TrustedImm32 imm, AbsoluteAddress address)
685     {
686         m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast<ARMWord>(address.m_ptr));
687         m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0);
688         add32(imm, ARMRegisters::S1);
689         m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address.m_ptr));
690         m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0);
691     }
692 
sub32(TrustedImm32 imm,AbsoluteAddress address)693     void sub32(TrustedImm32 imm, AbsoluteAddress address)
694     {
695         m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast<ARMWord>(address.m_ptr));
696         m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0);
697         sub32(imm, ARMRegisters::S1);
698         m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address.m_ptr));
699         m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0);
700     }
701 
load32(const void * address,RegisterID dest)702     void load32(const void* address, RegisterID dest)
703     {
704         m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address));
705         m_assembler.dtr_u(true, dest, ARMRegisters::S0, 0);
706     }
707 
branch32(Condition cond,AbsoluteAddress left,RegisterID right)708     Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right)
709     {
710         load32(left.m_ptr, ARMRegisters::S1);
711         return branch32(cond, ARMRegisters::S1, right);
712     }
713 
branch32(Condition cond,AbsoluteAddress left,TrustedImm32 right)714     Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right)
715     {
716         load32(left.m_ptr, ARMRegisters::S1);
717         return branch32(cond, ARMRegisters::S1, right);
718     }
719 
relativeTableJump(RegisterID index,int scale)720     void relativeTableJump(RegisterID index, int scale)
721     {
722         ASSERT(scale >= 0 && scale <= 31);
723         m_assembler.add_r(ARMRegisters::pc, ARMRegisters::pc, m_assembler.lsl(index, scale));
724 
725         // NOP the default prefetching
726         m_assembler.mov_r(ARMRegisters::r0, ARMRegisters::r0);
727     }
728 
call()729     Call call()
730     {
731 #if WTF_ARM_ARCH_AT_LEAST(5)
732         ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord));
733         m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true);
734         return Call(m_assembler.blx(ARMRegisters::S1), Call::Linkable);
735 #else
736         prepareCall();
737         return Call(m_assembler.jmp(ARMAssembler::AL, true), Call::Linkable);
738 #endif
739     }
740 
tailRecursiveCall()741     Call tailRecursiveCall()
742     {
743         return Call::fromTailJump(jump());
744     }
745 
makeTailRecursiveCall(Jump oldJump)746     Call makeTailRecursiveCall(Jump oldJump)
747     {
748         return Call::fromTailJump(oldJump);
749     }
750 
moveWithPatch(TrustedImmPtr initialValue,RegisterID dest)751     DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
752     {
753         DataLabelPtr dataLabel(this);
754         m_assembler.ldr_un_imm(dest, reinterpret_cast<ARMWord>(initialValue.m_value));
755         return dataLabel;
756     }
757 
758     Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
759     {
760         dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S1);
761         Jump jump = branch32(cond, left, ARMRegisters::S1, true);
762         return jump;
763     }
764 
765     Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
766     {
767         load32(left, ARMRegisters::S1);
768         dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S0);
769         Jump jump = branch32(cond, ARMRegisters::S0, ARMRegisters::S1, true);
770         return jump;
771     }
772 
storePtrWithPatch(TrustedImmPtr initialValue,ImplicitAddress address)773     DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
774     {
775         DataLabelPtr dataLabel = moveWithPatch(initialValue, ARMRegisters::S1);
776         store32(ARMRegisters::S1, address);
777         return dataLabel;
778     }
779 
storePtrWithPatch(ImplicitAddress address)780     DataLabelPtr storePtrWithPatch(ImplicitAddress address)
781     {
782         return storePtrWithPatch(TrustedImmPtr(0), address);
783     }
784 
785     // Floating point operators
supportsFloatingPoint()786     bool supportsFloatingPoint() const
787     {
788         return s_isVFPPresent;
789     }
790 
supportsFloatingPointTruncate()791     bool supportsFloatingPointTruncate() const
792     {
793         return s_isVFPPresent;
794     }
795 
supportsFloatingPointSqrt()796     bool supportsFloatingPointSqrt() const
797     {
798         return s_isVFPPresent;
799     }
800 
loadDouble(ImplicitAddress address,FPRegisterID dest)801     void loadDouble(ImplicitAddress address, FPRegisterID dest)
802     {
803         m_assembler.doubleTransfer(true, dest, address.base, address.offset);
804     }
805 
loadDouble(const void * address,FPRegisterID dest)806     void loadDouble(const void* address, FPRegisterID dest)
807     {
808         m_assembler.ldr_un_imm(ARMRegisters::S0, (ARMWord)address);
809         m_assembler.fdtr_u(true, dest, ARMRegisters::S0, 0);
810     }
811 
storeDouble(FPRegisterID src,ImplicitAddress address)812     void storeDouble(FPRegisterID src, ImplicitAddress address)
813     {
814         m_assembler.doubleTransfer(false, src, address.base, address.offset);
815     }
816 
addDouble(FPRegisterID src,FPRegisterID dest)817     void addDouble(FPRegisterID src, FPRegisterID dest)
818     {
819         m_assembler.vadd_f64_r(dest, dest, src);
820     }
821 
addDouble(Address src,FPRegisterID dest)822     void addDouble(Address src, FPRegisterID dest)
823     {
824         loadDouble(src, ARMRegisters::SD0);
825         addDouble(ARMRegisters::SD0, dest);
826     }
827 
divDouble(FPRegisterID src,FPRegisterID dest)828     void divDouble(FPRegisterID src, FPRegisterID dest)
829     {
830         m_assembler.vdiv_f64_r(dest, dest, src);
831     }
832 
divDouble(Address src,FPRegisterID dest)833     void divDouble(Address src, FPRegisterID dest)
834     {
835         ASSERT_NOT_REACHED(); // Untested
836         loadDouble(src, ARMRegisters::SD0);
837         divDouble(ARMRegisters::SD0, dest);
838     }
839 
subDouble(FPRegisterID src,FPRegisterID dest)840     void subDouble(FPRegisterID src, FPRegisterID dest)
841     {
842         m_assembler.vsub_f64_r(dest, dest, src);
843     }
844 
subDouble(Address src,FPRegisterID dest)845     void subDouble(Address src, FPRegisterID dest)
846     {
847         loadDouble(src, ARMRegisters::SD0);
848         subDouble(ARMRegisters::SD0, dest);
849     }
850 
mulDouble(FPRegisterID src,FPRegisterID dest)851     void mulDouble(FPRegisterID src, FPRegisterID dest)
852     {
853         m_assembler.vmul_f64_r(dest, dest, src);
854     }
855 
mulDouble(Address src,FPRegisterID dest)856     void mulDouble(Address src, FPRegisterID dest)
857     {
858         loadDouble(src, ARMRegisters::SD0);
859         mulDouble(ARMRegisters::SD0, dest);
860     }
861 
sqrtDouble(FPRegisterID src,FPRegisterID dest)862     void sqrtDouble(FPRegisterID src, FPRegisterID dest)
863     {
864         m_assembler.vsqrt_f64_r(dest, src);
865     }
866 
convertInt32ToDouble(RegisterID src,FPRegisterID dest)867     void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
868     {
869         m_assembler.vmov_vfp_r(dest << 1, src);
870         m_assembler.vcvt_f64_s32_r(dest, dest << 1);
871     }
872 
convertInt32ToDouble(Address src,FPRegisterID dest)873     void convertInt32ToDouble(Address src, FPRegisterID dest)
874     {
875         ASSERT_NOT_REACHED(); // Untested
876         // flds does not worth the effort here
877         load32(src, ARMRegisters::S1);
878         convertInt32ToDouble(ARMRegisters::S1, dest);
879     }
880 
convertInt32ToDouble(AbsoluteAddress src,FPRegisterID dest)881     void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest)
882     {
883         ASSERT_NOT_REACHED(); // Untested
884         // flds does not worth the effort here
885         m_assembler.ldr_un_imm(ARMRegisters::S1, (ARMWord)src.m_ptr);
886         m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0);
887         convertInt32ToDouble(ARMRegisters::S1, dest);
888     }
889 
branchDouble(DoubleCondition cond,FPRegisterID left,FPRegisterID right)890     Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
891     {
892         m_assembler.vcmp_f64_r(left, right);
893         m_assembler.vmrs_apsr();
894         if (cond & DoubleConditionBitSpecial)
895             m_assembler.cmp_r(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::VS);
896         return Jump(m_assembler.jmp(static_cast<ARMAssembler::Condition>(cond & ~DoubleConditionMask)));
897     }
898 
899     // Truncates 'src' to an integer, and places the resulting 'dest'.
900     // If the result is not representable as a 32 bit value, branch.
901     // May also branch for some values that are representable in 32 bits
902     // (specifically, in this case, INT_MIN and INT_MAX).
branchTruncateDoubleToInt32(FPRegisterID src,RegisterID dest)903     Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest)
904     {
905         m_assembler.vcvtr_s32_f64_r(ARMRegisters::SD0 << 1, src);
906         // If VCVTR.S32.F64 can't fit the result into a 32-bit
907         // integer, it saturates at INT_MAX or INT_MIN. Testing this is
908         // probably quicker than testing FPSCR for exception.
909         m_assembler.vmov_arm_r(dest, ARMRegisters::SD0 << 1);
910         m_assembler.sub_r(ARMRegisters::S0, dest, ARMAssembler::getOp2(0x80000000));
911         m_assembler.cmn_r(ARMRegisters::S0, ARMAssembler::getOp2(1), ARMCondition(NotEqual));
912         return Jump(m_assembler.jmp(ARMCondition(Equal)));
913     }
914 
915     // Convert 'src' to an integer, and places the resulting 'dest'.
916     // If the result is not representable as a 32 bit value, branch.
917     // May also branch for some values that are representable in 32 bits
918     // (specifically, in this case, 0).
branchConvertDoubleToInt32(FPRegisterID src,RegisterID dest,JumpList & failureCases,FPRegisterID fpTemp)919     void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp)
920     {
921         m_assembler.vcvt_s32_f64_r(ARMRegisters::SD0 << 1, src);
922         m_assembler.vmov_arm_r(dest, ARMRegisters::SD0 << 1);
923 
924         // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
925         m_assembler.vcvt_f64_s32_r(ARMRegisters::SD0, ARMRegisters::SD0 << 1);
926         failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, ARMRegisters::SD0));
927 
928         // If the result is zero, it might have been -0.0, and 0.0 equals to -0.0
929         failureCases.append(branchTest32(Zero, dest));
930     }
931 
branchDoubleNonZero(FPRegisterID reg,FPRegisterID scratch)932     Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch)
933     {
934         m_assembler.mov_r(ARMRegisters::S0, ARMAssembler::getOp2(0));
935         convertInt32ToDouble(ARMRegisters::S0, scratch);
936         return branchDouble(DoubleNotEqual, reg, scratch);
937     }
938 
branchDoubleZeroOrNaN(FPRegisterID reg,FPRegisterID scratch)939     Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID scratch)
940     {
941         m_assembler.mov_r(ARMRegisters::S0, ARMAssembler::getOp2(0));
942         convertInt32ToDouble(ARMRegisters::S0, scratch);
943         return branchDouble(DoubleEqualOrUnordered, reg, scratch);
944     }
945 
946 protected:
ARMCondition(Condition cond)947     ARMAssembler::Condition ARMCondition(Condition cond)
948     {
949         return static_cast<ARMAssembler::Condition>(cond);
950     }
951 
ensureSpace(int insnSpace,int constSpace)952     void ensureSpace(int insnSpace, int constSpace)
953     {
954         m_assembler.ensureSpace(insnSpace, constSpace);
955     }
956 
sizeOfConstantPool()957     int sizeOfConstantPool()
958     {
959         return m_assembler.sizeOfConstantPool();
960     }
961 
prepareCall()962     void prepareCall()
963     {
964 #if WTF_ARM_ARCH_VERSION < 5
965         ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord));
966 
967         m_assembler.mov_r(linkRegister, ARMRegisters::pc);
968 #endif
969     }
970 
call32(RegisterID base,int32_t offset)971     void call32(RegisterID base, int32_t offset)
972     {
973 #if WTF_ARM_ARCH_AT_LEAST(5)
974         int targetReg = ARMRegisters::S1;
975 #else
976         int targetReg = ARMRegisters::pc;
977 #endif
978         int tmpReg = ARMRegisters::S1;
979 
980         if (base == ARMRegisters::sp)
981             offset += 4;
982 
983         if (offset >= 0) {
984             if (offset <= 0xfff) {
985                 prepareCall();
986                 m_assembler.dtr_u(true, targetReg, base, offset);
987             } else if (offset <= 0xfffff) {
988                 m_assembler.add_r(tmpReg, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8));
989                 prepareCall();
990                 m_assembler.dtr_u(true, targetReg, tmpReg, offset & 0xfff);
991             } else {
992                 m_assembler.moveImm(offset, tmpReg);
993                 prepareCall();
994                 m_assembler.dtr_ur(true, targetReg, base, tmpReg);
995             }
996         } else  {
997             offset = -offset;
998             if (offset <= 0xfff) {
999                 prepareCall();
1000                 m_assembler.dtr_d(true, targetReg, base, offset);
1001             } else if (offset <= 0xfffff) {
1002                 m_assembler.sub_r(tmpReg, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8));
1003                 prepareCall();
1004                 m_assembler.dtr_d(true, targetReg, tmpReg, offset & 0xfff);
1005             } else {
1006                 m_assembler.moveImm(offset, tmpReg);
1007                 prepareCall();
1008                 m_assembler.dtr_dr(true, targetReg, base, tmpReg);
1009             }
1010         }
1011 #if WTF_ARM_ARCH_AT_LEAST(5)
1012         m_assembler.blx(targetReg);
1013 #endif
1014     }
1015 
1016 private:
1017     friend class LinkBuffer;
1018     friend class RepatchBuffer;
1019 
linkCall(void * code,Call call,FunctionPtr function)1020     static void linkCall(void* code, Call call, FunctionPtr function)
1021     {
1022         ARMAssembler::linkCall(code, call.m_jmp, function.value());
1023     }
1024 
repatchCall(CodeLocationCall call,CodeLocationLabel destination)1025     static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
1026     {
1027         ARMAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
1028     }
1029 
repatchCall(CodeLocationCall call,FunctionPtr destination)1030     static void repatchCall(CodeLocationCall call, FunctionPtr destination)
1031     {
1032         ARMAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
1033     }
1034 
1035     static const bool s_isVFPPresent;
1036 };
1037 
1038 }
1039 
1040 #endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
1041 
1042 #endif // MacroAssemblerARM_h
1043