Merge "Save and re-bind previously bounded texture when using cairo_gl_surface_set_bi...
[framework/web/webkit-efl.git] / Source / JavaScriptCore / assembler / MacroAssemblerARM.h
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 RelationalCondition {
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     };
57
58     enum ResultCondition {
59         Overflow = ARMAssembler::VS,
60         Signed = ARMAssembler::MI,
61         Zero = ARMAssembler::EQ,
62         NonZero = ARMAssembler::NE
63     };
64
65     enum DoubleCondition {
66         // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
67         DoubleEqual = ARMAssembler::EQ,
68         DoubleNotEqual = ARMAssembler::NE | DoubleConditionBitSpecial,
69         DoubleGreaterThan = ARMAssembler::GT,
70         DoubleGreaterThanOrEqual = ARMAssembler::GE,
71         DoubleLessThan = ARMAssembler::CC,
72         DoubleLessThanOrEqual = ARMAssembler::LS,
73         // If either operand is NaN, these conditions always evaluate to true.
74         DoubleEqualOrUnordered = ARMAssembler::EQ | DoubleConditionBitSpecial,
75         DoubleNotEqualOrUnordered = ARMAssembler::NE,
76         DoubleGreaterThanOrUnordered = ARMAssembler::HI,
77         DoubleGreaterThanOrEqualOrUnordered = ARMAssembler::CS,
78         DoubleLessThanOrUnordered = ARMAssembler::LT,
79         DoubleLessThanOrEqualOrUnordered = ARMAssembler::LE,
80     };
81
82     static const RegisterID stackPointerRegister = ARMRegisters::sp;
83     static const RegisterID linkRegister = ARMRegisters::lr;
84
85     static const Scale ScalePtr = TimesFour;
86
87     void add32(RegisterID src, RegisterID dest)
88     {
89         m_assembler.adds_r(dest, dest, src);
90     }
91
92     void add32(RegisterID op1, RegisterID op2, RegisterID dest)
93     {
94         m_assembler.adds_r(dest, op1, op2);
95     }
96
97     void add32(TrustedImm32 imm, Address address)
98     {
99         load32(address, ARMRegisters::S1);
100         add32(imm, ARMRegisters::S1);
101         store32(ARMRegisters::S1, address);
102     }
103
104     void add32(TrustedImm32 imm, RegisterID dest)
105     {
106         m_assembler.adds_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
107     }
108
109     void add32(AbsoluteAddress src, RegisterID dest)
110     {
111         move(TrustedImmPtr(src.m_ptr), ARMRegisters::S1);
112         m_assembler.dtr_u(ARMAssembler::LoadUint32, ARMRegisters::S1, ARMRegisters::S1, 0);
113         add32(ARMRegisters::S1, dest);
114     }
115
116     void add32(Address src, RegisterID dest)
117     {
118         load32(src, ARMRegisters::S1);
119         add32(ARMRegisters::S1, dest);
120     }
121
122     void add32(RegisterID src, TrustedImm32 imm, RegisterID dest)
123     {
124         m_assembler.adds_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
125     }
126
127     void and32(RegisterID src, RegisterID dest)
128     {
129         m_assembler.ands_r(dest, dest, src);
130     }
131
132     void and32(RegisterID op1, RegisterID op2, RegisterID dest)
133     {
134         m_assembler.ands_r(dest, op1, op2);
135     }
136
137     void and32(TrustedImm32 imm, RegisterID dest)
138     {
139         ARMWord w = m_assembler.getImm(imm.m_value, ARMRegisters::S0, true);
140         if (w & ARMAssembler::OP2_INV_IMM)
141             m_assembler.bics_r(dest, dest, w & ~ARMAssembler::OP2_INV_IMM);
142         else
143             m_assembler.ands_r(dest, dest, w);
144     }
145
146     void and32(TrustedImm32 imm, RegisterID src, RegisterID dest)
147     {
148         ARMWord w = m_assembler.getImm(imm.m_value, ARMRegisters::S0, true);
149         if (w & ARMAssembler::OP2_INV_IMM)
150             m_assembler.bics_r(dest, src, w & ~ARMAssembler::OP2_INV_IMM);
151         else
152             m_assembler.ands_r(dest, src, w);
153     }
154
155     void lshift32(RegisterID shiftAmount, RegisterID dest)
156     {
157         lshift32(dest, shiftAmount, dest);
158     }
159
160     void lshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
161     {
162         ARMWord w = ARMAssembler::getOp2Byte(0x1f);
163         m_assembler.and_r(ARMRegisters::S0, shiftAmount, w);
164
165         m_assembler.movs_r(dest, m_assembler.lsl_r(src, ARMRegisters::S0));
166     }
167
168     void lshift32(TrustedImm32 imm, RegisterID dest)
169     {
170         m_assembler.movs_r(dest, m_assembler.lsl(dest, imm.m_value & 0x1f));
171     }
172
173     void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
174     {
175         m_assembler.movs_r(dest, m_assembler.lsl(src, imm.m_value & 0x1f));
176     }
177
178     void mul32(RegisterID op1, RegisterID op2, RegisterID dest)
179     {
180         if (op2 == dest) {
181             if (op1 == dest) {
182                 move(op2, ARMRegisters::S0);
183                 op2 = ARMRegisters::S0;
184             } else {
185                 // Swap the operands.
186                 RegisterID tmp = op1;
187                 op1 = op2;
188                 op2 = tmp;
189             }
190         }
191         m_assembler.muls_r(dest, op1, op2);
192     }
193
194     void mul32(RegisterID src, RegisterID dest)
195     {
196         mul32(src, dest, dest);
197     }
198
199     void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
200     {
201         move(imm, ARMRegisters::S0);
202         m_assembler.muls_r(dest, src, ARMRegisters::S0);
203     }
204
205     void neg32(RegisterID srcDest)
206     {
207         m_assembler.rsbs_r(srcDest, srcDest, ARMAssembler::getOp2Byte(0));
208     }
209
210     void or32(RegisterID src, RegisterID dest)
211     {
212         m_assembler.orrs_r(dest, dest, src);
213     }
214
215     void or32(TrustedImm32 imm, RegisterID dest)
216     {
217         m_assembler.orrs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
218     }
219
220     void or32(TrustedImm32 imm, RegisterID src, RegisterID dest)
221     {
222         m_assembler.orrs_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
223     }
224
225     void or32(RegisterID op1, RegisterID op2, RegisterID dest)
226     {
227         m_assembler.orrs_r(dest, op1, op2);
228     }
229
230     void rshift32(RegisterID shiftAmount, RegisterID dest)
231     {
232         rshift32(dest, shiftAmount, dest);
233     }
234
235     void rshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
236     {
237         ARMWord w = ARMAssembler::getOp2Byte(0x1f);
238         m_assembler.and_r(ARMRegisters::S0, shiftAmount, w);
239
240         m_assembler.movs_r(dest, m_assembler.asr_r(src, ARMRegisters::S0));
241     }
242
243     void rshift32(TrustedImm32 imm, RegisterID dest)
244     {
245         rshift32(dest, imm, dest);
246     }
247
248     void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
249     {
250         m_assembler.movs_r(dest, m_assembler.asr(src, imm.m_value & 0x1f));
251     }
252
253     void urshift32(RegisterID shiftAmount, RegisterID dest)
254     {
255         urshift32(dest, shiftAmount, dest);
256     }
257
258     void urshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
259     {
260         ARMWord w = ARMAssembler::getOp2Byte(0x1f);
261         m_assembler.and_r(ARMRegisters::S0, shiftAmount, w);
262
263         m_assembler.movs_r(dest, m_assembler.lsr_r(src, ARMRegisters::S0));
264     }
265
266     void urshift32(TrustedImm32 imm, RegisterID dest)
267     {
268         m_assembler.movs_r(dest, m_assembler.lsr(dest, imm.m_value & 0x1f));
269     }
270     
271     void urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
272     {
273         m_assembler.movs_r(dest, m_assembler.lsr(src, imm.m_value & 0x1f));
274     }
275
276     void sub32(RegisterID src, RegisterID dest)
277     {
278         m_assembler.subs_r(dest, dest, src);
279     }
280
281     void sub32(TrustedImm32 imm, RegisterID dest)
282     {
283         m_assembler.subs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
284     }
285
286     void sub32(TrustedImm32 imm, Address address)
287     {
288         load32(address, ARMRegisters::S1);
289         sub32(imm, ARMRegisters::S1);
290         store32(ARMRegisters::S1, address);
291     }
292
293     void sub32(Address src, RegisterID dest)
294     {
295         load32(src, ARMRegisters::S1);
296         sub32(ARMRegisters::S1, dest);
297     }
298
299     void sub32(RegisterID src, TrustedImm32 imm, RegisterID dest)
300     {
301         m_assembler.subs_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
302     }
303
304     void xor32(RegisterID src, RegisterID dest)
305     {
306         m_assembler.eors_r(dest, dest, src);
307     }
308
309     void xor32(RegisterID op1, RegisterID op2, RegisterID dest)
310     {
311         m_assembler.eors_r(dest, op1, op2);
312     }
313
314     void xor32(TrustedImm32 imm, RegisterID dest)
315     {
316         if (imm.m_value == -1)
317             m_assembler.mvns_r(dest, dest);
318         else
319             m_assembler.eors_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
320     }
321
322     void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest)
323     {
324         if (imm.m_value == -1)
325             m_assembler.mvns_r(dest, src);
326         else    
327             m_assembler.eors_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
328     }
329
330     void countLeadingZeros32(RegisterID src, RegisterID dest)
331     {
332 #if WTF_ARM_ARCH_AT_LEAST(5)
333         m_assembler.clz_r(dest, src);
334 #else
335         UNUSED_PARAM(src);
336         UNUSED_PARAM(dest);
337         ASSERT_NOT_REACHED();
338 #endif
339     }
340
341     void load8(ImplicitAddress address, RegisterID dest)
342     {
343         m_assembler.dataTransfer32(ARMAssembler::LoadUint8, dest, address.base, address.offset);
344     }
345
346     void load8(BaseIndex address, RegisterID dest)
347     {
348         m_assembler.baseIndexTransfer32(ARMAssembler::LoadUint8, dest, address.base, address.index, static_cast<int>(address.scale), address.offset);
349     }
350
351     void load8Signed(BaseIndex address, RegisterID dest)
352     {
353         m_assembler.baseIndexTransfer16(ARMAssembler::LoadInt8, dest, address.base, address.index, static_cast<int>(address.scale), address.offset);
354     }
355
356     void load16(ImplicitAddress address, RegisterID dest)
357     {
358         m_assembler.dataTransfer16(ARMAssembler::LoadUint16, dest, address.base, address.offset);
359     }
360
361     void load16(BaseIndex address, RegisterID dest)
362     {
363         m_assembler.baseIndexTransfer16(ARMAssembler::LoadUint16, dest, address.base, address.index, static_cast<int>(address.scale), address.offset);
364     }
365
366     void load16Signed(BaseIndex address, RegisterID dest)
367     {
368         m_assembler.baseIndexTransfer16(ARMAssembler::LoadInt16, dest, address.base, address.index, static_cast<int>(address.scale), address.offset);
369     }
370
371     void load32(ImplicitAddress address, RegisterID dest)
372     {
373         m_assembler.dataTransfer32(ARMAssembler::LoadUint32, dest, address.base, address.offset);
374     }
375
376     void load32(BaseIndex address, RegisterID dest)
377     {
378         m_assembler.baseIndexTransfer32(ARMAssembler::LoadUint32, dest, address.base, address.index, static_cast<int>(address.scale), address.offset);
379     }
380
381 #if CPU(ARMV5_OR_LOWER)
382     void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest);
383 #else
384     void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
385     {
386         load32(address, dest);
387     }
388 #endif
389
390     void load16Unaligned(BaseIndex address, RegisterID dest)
391     {
392         load16(address, dest);
393     }
394
395     ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest)
396     {
397         ConvertibleLoadLabel result(this);
398         ASSERT(address.offset >= 0 && address.offset <= 255);
399         m_assembler.dtr_u(ARMAssembler::LoadUint32, dest, address.base, address.offset);
400         return result;
401     }
402
403     DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
404     {
405         DataLabel32 dataLabel(this);
406         m_assembler.ldr_un_imm(ARMRegisters::S0, 0);
407         m_assembler.dtr_ur(ARMAssembler::LoadUint32, dest, address.base, ARMRegisters::S0);
408         return dataLabel;
409     }
410
411     static bool isCompactPtrAlignedAddressOffset(ptrdiff_t value)
412     {
413         return value >= -4095 && value <= 4095;
414     }
415
416     DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
417     {
418         DataLabelCompact dataLabel(this);
419         ASSERT(isCompactPtrAlignedAddressOffset(address.offset));
420         if (address.offset >= 0)
421             m_assembler.dtr_u(ARMAssembler::LoadUint32, dest, address.base, address.offset);
422         else
423             m_assembler.dtr_d(ARMAssembler::LoadUint32, dest, address.base, address.offset);
424         return dataLabel;
425     }
426
427     DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
428     {
429         DataLabel32 dataLabel(this);
430         m_assembler.ldr_un_imm(ARMRegisters::S0, 0);
431         m_assembler.dtr_ur(ARMAssembler::StoreUint32, src, address.base, ARMRegisters::S0);
432         return dataLabel;
433     }
434
435     void store8(RegisterID src, BaseIndex address)
436     {
437         m_assembler.baseIndexTransfer32(ARMAssembler::StoreUint8, src, address.base, address.index, static_cast<int>(address.scale), address.offset);
438     }
439
440     void store16(RegisterID src, BaseIndex address)
441     {
442         m_assembler.baseIndexTransfer16(ARMAssembler::StoreUint16, src, address.base, address.index, static_cast<int>(address.scale), address.offset);
443     }
444
445     void store32(RegisterID src, ImplicitAddress address)
446     {
447         m_assembler.dataTransfer32(ARMAssembler::StoreUint32, src, address.base, address.offset);
448     }
449
450     void store32(RegisterID src, BaseIndex address)
451     {
452         m_assembler.baseIndexTransfer32(ARMAssembler::StoreUint32, src, address.base, address.index, static_cast<int>(address.scale), address.offset);
453     }
454
455     void store32(TrustedImm32 imm, ImplicitAddress address)
456     {
457         move(imm, ARMRegisters::S1);
458         store32(ARMRegisters::S1, address);
459     }
460
461     void store32(TrustedImm32 imm, BaseIndex address)
462     {
463         move(imm, ARMRegisters::S1);
464         m_assembler.baseIndexTransfer32(ARMAssembler::StoreUint32, ARMRegisters::S1, address.base, address.index, static_cast<int>(address.scale), address.offset);
465     }
466
467     void store32(RegisterID src, void* address)
468     {
469         m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address));
470         m_assembler.dtr_u(ARMAssembler::StoreUint32, src, ARMRegisters::S0, 0);
471     }
472
473     void store32(TrustedImm32 imm, void* address)
474     {
475         m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address));
476         m_assembler.moveImm(imm.m_value, ARMRegisters::S1);
477         m_assembler.dtr_u(ARMAssembler::StoreUint32, ARMRegisters::S1, ARMRegisters::S0, 0);
478     }
479
480     void pop(RegisterID dest)
481     {
482         m_assembler.pop_r(dest);
483     }
484
485     void push(RegisterID src)
486     {
487         m_assembler.push_r(src);
488     }
489
490     void push(Address address)
491     {
492         load32(address, ARMRegisters::S1);
493         push(ARMRegisters::S1);
494     }
495
496     void push(TrustedImm32 imm)
497     {
498         move(imm, ARMRegisters::S0);
499         push(ARMRegisters::S0);
500     }
501
502     void move(TrustedImm32 imm, RegisterID dest)
503     {
504         m_assembler.moveImm(imm.m_value, dest);
505     }
506
507     void move(RegisterID src, RegisterID dest)
508     {
509         if (src != dest)
510             m_assembler.mov_r(dest, src);
511     }
512
513     void move(TrustedImmPtr imm, RegisterID dest)
514     {
515         move(TrustedImm32(imm), dest);
516     }
517
518     void swap(RegisterID reg1, RegisterID reg2)
519     {
520         m_assembler.mov_r(ARMRegisters::S0, reg1);
521         m_assembler.mov_r(reg1, reg2);
522         m_assembler.mov_r(reg2, ARMRegisters::S0);
523     }
524
525     void signExtend32ToPtr(RegisterID src, RegisterID dest)
526     {
527         if (src != dest)
528             move(src, dest);
529     }
530
531     void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
532     {
533         if (src != dest)
534             move(src, dest);
535     }
536
537     Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
538     {
539         load8(left, ARMRegisters::S1);
540         return branch32(cond, ARMRegisters::S1, right);
541     }
542
543     Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
544     {
545         ASSERT(!(right.m_value & 0xFFFFFF00));
546         load8(left, ARMRegisters::S1);
547         return branch32(cond, ARMRegisters::S1, right);
548     }
549
550     Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right, int useConstantPool = 0)
551     {
552         m_assembler.cmp_r(left, right);
553         return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool));
554     }
555
556     Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right, int useConstantPool = 0)
557     {
558 #if OS(TIZEN)
559         // In order to remove warning
560         ARMWord tmp = ((unsigned)right.m_value == 0x80000000) ? ARMAssembler::INVALID_IMM : m_assembler.getOp2(-right.m_value);
561 #else
562         ARMWord tmp = (right.m_value == 0x80000000) ? ARMAssembler::INVALID_IMM : m_assembler.getOp2(-right.m_value);
563 #endif
564         if (tmp != ARMAssembler::INVALID_IMM)
565             m_assembler.cmn_r(left, tmp);
566         else
567             m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0));
568         return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool));
569     }
570
571     Jump branch32(RelationalCondition cond, RegisterID left, Address right)
572     {
573         load32(right, ARMRegisters::S1);
574         return branch32(cond, left, ARMRegisters::S1);
575     }
576
577     Jump branch32(RelationalCondition cond, Address left, RegisterID right)
578     {
579         load32(left, ARMRegisters::S1);
580         return branch32(cond, ARMRegisters::S1, right);
581     }
582
583     Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
584     {
585         load32(left, ARMRegisters::S1);
586         return branch32(cond, ARMRegisters::S1, right);
587     }
588
589     Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
590     {
591         load32(left, ARMRegisters::S1);
592         return branch32(cond, ARMRegisters::S1, right);
593     }
594
595     Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
596     {
597         load32WithUnalignedHalfWords(left, ARMRegisters::S1);
598         return branch32(cond, ARMRegisters::S1, right);
599     }
600
601     Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
602     {
603         load8(address, ARMRegisters::S1);
604         return branchTest32(cond, ARMRegisters::S1, mask);
605     }
606
607     Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
608     {
609         move(TrustedImmPtr(address.m_ptr), ARMRegisters::S1);
610         load8(Address(ARMRegisters::S1), ARMRegisters::S1);
611         return branchTest32(cond, ARMRegisters::S1, mask);
612     }
613
614     Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
615     {
616         ASSERT((cond == Zero) || (cond == NonZero));
617         m_assembler.tst_r(reg, mask);
618         return Jump(m_assembler.jmp(ARMCondition(cond)));
619     }
620
621     Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
622     {
623         ASSERT((cond == Zero) || (cond == NonZero));
624         ARMWord w = m_assembler.getImm(mask.m_value, ARMRegisters::S0, true);
625         if (w & ARMAssembler::OP2_INV_IMM)
626             m_assembler.bics_r(ARMRegisters::S0, reg, w & ~ARMAssembler::OP2_INV_IMM);
627         else
628             m_assembler.tst_r(reg, w);
629         return Jump(m_assembler.jmp(ARMCondition(cond)));
630     }
631
632     Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
633     {
634         load32(address, ARMRegisters::S1);
635         return branchTest32(cond, ARMRegisters::S1, mask);
636     }
637
638     Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
639     {
640         load32(address, ARMRegisters::S1);
641         return branchTest32(cond, ARMRegisters::S1, mask);
642     }
643
644     Jump jump()
645     {
646         return Jump(m_assembler.jmp());
647     }
648
649     void jump(RegisterID target)
650     {
651         m_assembler.bx(target);
652     }
653
654     void jump(Address address)
655     {
656         load32(address, ARMRegisters::pc);
657     }
658
659     void jump(AbsoluteAddress address)
660     {
661         move(TrustedImmPtr(address.m_ptr), ARMRegisters::S0);
662         load32(Address(ARMRegisters::S0, 0), ARMRegisters::pc);
663     }
664
665     Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
666     {
667         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
668         add32(src, dest);
669         return Jump(m_assembler.jmp(ARMCondition(cond)));
670     }
671
672     Jump branchAdd32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
673     {
674         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
675         add32(op1, op2, dest);
676         return Jump(m_assembler.jmp(ARMCondition(cond)));
677     }
678
679     Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
680     {
681         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
682         add32(imm, dest);
683         return Jump(m_assembler.jmp(ARMCondition(cond)));
684     }
685
686     Jump branchAdd32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
687     {
688         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
689         add32(src, imm, dest);
690         return Jump(m_assembler.jmp(ARMCondition(cond)));
691     }
692
693     Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest)
694     {
695         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
696         add32(imm, dest);
697         return Jump(m_assembler.jmp(ARMCondition(cond)));
698     }
699
700     void mull32(RegisterID op1, RegisterID op2, RegisterID dest)
701     {
702         if (op2 == dest) {
703             if (op1 == dest) {
704                 move(op2, ARMRegisters::S0);
705                 op2 = ARMRegisters::S0;
706             } else {
707                 // Swap the operands.
708                 RegisterID tmp = op1;
709                 op1 = op2;
710                 op2 = tmp;
711             }
712         }
713         m_assembler.mull_r(ARMRegisters::S1, dest, op1, op2);
714         m_assembler.cmp_r(ARMRegisters::S1, m_assembler.asr(dest, 31));
715     }
716
717     Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
718     {
719         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
720         if (cond == Overflow) {
721             mull32(src1, src2, dest);
722             cond = NonZero;
723         }
724         else
725             mul32(src1, src2, dest);
726         return Jump(m_assembler.jmp(ARMCondition(cond)));
727     }
728
729     Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
730     {
731         return branchMul32(cond, src, dest, dest);
732     }
733
734     Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
735     {
736         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
737         if (cond == Overflow) {
738             move(imm, ARMRegisters::S0);
739             mull32(ARMRegisters::S0, src, dest);
740             cond = NonZero;
741         }
742         else
743             mul32(imm, src, dest);
744         return Jump(m_assembler.jmp(ARMCondition(cond)));
745     }
746
747     Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
748     {
749         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
750         sub32(src, dest);
751         return Jump(m_assembler.jmp(ARMCondition(cond)));
752     }
753
754     Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
755     {
756         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
757         sub32(imm, dest);
758         return Jump(m_assembler.jmp(ARMCondition(cond)));
759     }
760
761     Jump branchSub32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
762     {
763         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
764         sub32(src, imm, dest);
765         return Jump(m_assembler.jmp(ARMCondition(cond)));
766     }
767
768     Jump branchSub32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
769     {
770         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
771         m_assembler.subs_r(dest, op1, op2);
772         return Jump(m_assembler.jmp(ARMCondition(cond)));
773     }
774
775     Jump branchNeg32(ResultCondition cond, RegisterID srcDest)
776     {
777         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
778         neg32(srcDest);
779         return Jump(m_assembler.jmp(ARMCondition(cond)));
780     }
781
782     Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
783     {
784         ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero));
785         or32(src, dest);
786         return Jump(m_assembler.jmp(ARMCondition(cond)));
787     }
788
789     void breakpoint()
790     {
791         m_assembler.bkpt(0);
792     }
793
794     Call nearCall()
795     {
796         m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true);
797         return Call(m_assembler.blx(ARMRegisters::S1), Call::LinkableNear);
798     }
799
800     Call call(RegisterID target)
801     {
802         return Call(m_assembler.blx(target), Call::None);
803     }
804
805     void call(Address address)
806     {
807         call32(address.base, address.offset);
808     }
809
810     void ret()
811     {
812         m_assembler.bx(linkRegister);
813     }
814
815     void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
816     {
817         m_assembler.cmp_r(left, right);
818         m_assembler.mov_r(dest, ARMAssembler::getOp2Byte(0));
819         m_assembler.mov_r(dest, ARMAssembler::getOp2Byte(1), ARMCondition(cond));
820     }
821
822     void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
823     {
824         m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0));
825         m_assembler.mov_r(dest, ARMAssembler::getOp2Byte(0));
826         m_assembler.mov_r(dest, ARMAssembler::getOp2Byte(1), ARMCondition(cond));
827     }
828
829     void compare8(RelationalCondition cond, Address left, TrustedImm32 right, RegisterID dest)
830     {
831         load8(left, ARMRegisters::S1);
832         compare32(cond, ARMRegisters::S1, right, dest);
833     }
834
835     void test32(ResultCondition cond, RegisterID reg, TrustedImm32 mask, RegisterID dest)
836     {
837         if (mask.m_value == -1)
838             m_assembler.cmp_r(0, reg);
839         else
840             m_assembler.tst_r(reg, m_assembler.getImm(mask.m_value, ARMRegisters::S0));
841         m_assembler.mov_r(dest, ARMAssembler::getOp2Byte(0));
842         m_assembler.mov_r(dest, ARMAssembler::getOp2Byte(1), ARMCondition(cond));
843     }
844
845     void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
846     {
847         load32(address, ARMRegisters::S1);
848         test32(cond, ARMRegisters::S1, mask, dest);
849     }
850
851     void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
852     {
853         load8(address, ARMRegisters::S1);
854         test32(cond, ARMRegisters::S1, mask, dest);
855     }
856
857     void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
858     {
859         m_assembler.add_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
860     }
861
862     void add32(TrustedImm32 imm, AbsoluteAddress address)
863     {
864         m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast<ARMWord>(address.m_ptr));
865         m_assembler.dtr_u(ARMAssembler::LoadUint32, ARMRegisters::S1, ARMRegisters::S1, 0);
866         add32(imm, ARMRegisters::S1);
867         m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address.m_ptr));
868         m_assembler.dtr_u(ARMAssembler::StoreUint32, ARMRegisters::S1, ARMRegisters::S0, 0);
869     }
870
871     void sub32(TrustedImm32 imm, AbsoluteAddress address)
872     {
873         m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast<ARMWord>(address.m_ptr));
874         m_assembler.dtr_u(ARMAssembler::LoadUint32, ARMRegisters::S1, ARMRegisters::S1, 0);
875         sub32(imm, ARMRegisters::S1);
876         m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address.m_ptr));
877         m_assembler.dtr_u(ARMAssembler::StoreUint32, ARMRegisters::S1, ARMRegisters::S0, 0);
878     }
879
880     void load32(const void* address, RegisterID dest)
881     {
882         m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address));
883         m_assembler.dtr_u(ARMAssembler::LoadUint32, dest, ARMRegisters::S0, 0);
884     }
885
886     Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
887     {
888         load32(left.m_ptr, ARMRegisters::S1);
889         return branch32(cond, ARMRegisters::S1, right);
890     }
891
892     Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
893     {
894         load32(left.m_ptr, ARMRegisters::S1);
895         return branch32(cond, ARMRegisters::S1, right);
896     }
897
898     void relativeTableJump(RegisterID index, int scale)
899     {
900         ASSERT(scale >= 0 && scale <= 31);
901         m_assembler.add_r(ARMRegisters::pc, ARMRegisters::pc, m_assembler.lsl(index, scale));
902
903         // NOP the default prefetching
904         m_assembler.mov_r(ARMRegisters::r0, ARMRegisters::r0);
905     }
906
907     Call call()
908     {
909         ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord));
910         m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true);
911         return Call(m_assembler.blx(ARMRegisters::S1), Call::Linkable);
912     }
913
914     Call tailRecursiveCall()
915     {
916         return Call::fromTailJump(jump());
917     }
918
919     Call makeTailRecursiveCall(Jump oldJump)
920     {
921         return Call::fromTailJump(oldJump);
922     }
923
924     DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
925     {
926         DataLabelPtr dataLabel(this);
927         m_assembler.ldr_un_imm(dest, reinterpret_cast<ARMWord>(initialValue.m_value));
928         return dataLabel;
929     }
930
931     Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
932     {
933         dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S1);
934         Jump jump = branch32(cond, left, ARMRegisters::S1, true);
935         return jump;
936     }
937
938     Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
939     {
940         load32(left, ARMRegisters::S1);
941         dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S0);
942         Jump jump = branch32(cond, ARMRegisters::S0, ARMRegisters::S1, true);
943         return jump;
944     }
945
946     DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
947     {
948         DataLabelPtr dataLabel = moveWithPatch(initialValue, ARMRegisters::S1);
949         store32(ARMRegisters::S1, address);
950         return dataLabel;
951     }
952
953     DataLabelPtr storePtrWithPatch(ImplicitAddress address)
954     {
955         return storePtrWithPatch(TrustedImmPtr(0), address);
956     }
957
958     // Floating point operators
959     static bool supportsFloatingPoint()
960     {
961         return s_isVFPPresent;
962     }
963
964     static bool supportsFloatingPointTruncate()
965     {
966         return false;
967     }
968
969     static bool supportsFloatingPointSqrt()
970     {
971         return s_isVFPPresent;
972     }
973     static bool supportsFloatingPointAbs() { return false; }
974
975     void loadFloat(BaseIndex address, FPRegisterID dest)
976     {
977         m_assembler.baseIndexTransferFloat(ARMAssembler::LoadFloat, dest, address.base, address.index, static_cast<int>(address.scale), address.offset);
978     }
979
980     void loadDouble(ImplicitAddress address, FPRegisterID dest)
981     {
982         m_assembler.dataTransferFloat(ARMAssembler::LoadDouble, dest, address.base, address.offset);
983     }
984
985     void loadDouble(BaseIndex address, FPRegisterID dest)
986     {
987         m_assembler.baseIndexTransferFloat(ARMAssembler::LoadDouble, dest, address.base, address.index, static_cast<int>(address.scale), address.offset);
988     }
989
990     void loadDouble(const void* address, FPRegisterID dest)
991     {
992         move(TrustedImm32(reinterpret_cast<ARMWord>(address)), ARMRegisters::S0);
993         m_assembler.fdtr_u(ARMAssembler::LoadDouble, dest, ARMRegisters::S0, 0);
994     }
995
996     void storeFloat(FPRegisterID src, BaseIndex address)
997     {
998         m_assembler.baseIndexTransferFloat(ARMAssembler::StoreFloat, src, address.base, address.index, static_cast<int>(address.scale), address.offset);
999     }
1000
1001     void storeDouble(FPRegisterID src, ImplicitAddress address)
1002     {
1003         m_assembler.dataTransferFloat(ARMAssembler::StoreDouble, src, address.base, address.offset);
1004     }
1005
1006     void storeDouble(FPRegisterID src, BaseIndex address)
1007     {
1008         m_assembler.baseIndexTransferFloat(ARMAssembler::StoreDouble, src, address.base, address.index, static_cast<int>(address.scale), address.offset);
1009     }
1010
1011     void storeDouble(FPRegisterID src, const void* address)
1012     {
1013         move(TrustedImm32(reinterpret_cast<ARMWord>(address)), ARMRegisters::S0);
1014         m_assembler.dataTransferFloat(ARMAssembler::StoreDouble, src, ARMRegisters::S0, 0);
1015     }
1016
1017     void moveDouble(FPRegisterID src, FPRegisterID dest)
1018     {
1019         if (src != dest)
1020             m_assembler.vmov_f64_r(dest, src);
1021     }
1022
1023     void addDouble(FPRegisterID src, FPRegisterID dest)
1024     {
1025         m_assembler.vadd_f64_r(dest, dest, src);
1026     }
1027
1028     void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1029     {
1030         m_assembler.vadd_f64_r(dest, op1, op2);
1031     }
1032
1033     void addDouble(Address src, FPRegisterID dest)
1034     {
1035         loadDouble(src, ARMRegisters::SD0);
1036         addDouble(ARMRegisters::SD0, dest);
1037     }
1038
1039     void addDouble(AbsoluteAddress address, FPRegisterID dest)
1040     {
1041         loadDouble(address.m_ptr, ARMRegisters::SD0);
1042         addDouble(ARMRegisters::SD0, dest);
1043     }
1044
1045     void divDouble(FPRegisterID src, FPRegisterID dest)
1046     {
1047         m_assembler.vdiv_f64_r(dest, dest, src);
1048     }
1049
1050     void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1051     {
1052         m_assembler.vdiv_f64_r(dest, op1, op2);
1053     }
1054
1055     void divDouble(Address src, FPRegisterID dest)
1056     {
1057         ASSERT_NOT_REACHED(); // Untested
1058         loadDouble(src, ARMRegisters::SD0);
1059         divDouble(ARMRegisters::SD0, dest);
1060     }
1061
1062     void subDouble(FPRegisterID src, FPRegisterID dest)
1063     {
1064         m_assembler.vsub_f64_r(dest, dest, src);
1065     }
1066
1067     void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1068     {
1069         m_assembler.vsub_f64_r(dest, op1, op2);
1070     }
1071
1072     void subDouble(Address src, FPRegisterID dest)
1073     {
1074         loadDouble(src, ARMRegisters::SD0);
1075         subDouble(ARMRegisters::SD0, dest);
1076     }
1077
1078     void mulDouble(FPRegisterID src, FPRegisterID dest)
1079     {
1080         m_assembler.vmul_f64_r(dest, dest, src);
1081     }
1082
1083     void mulDouble(Address src, FPRegisterID dest)
1084     {
1085         loadDouble(src, ARMRegisters::SD0);
1086         mulDouble(ARMRegisters::SD0, dest);
1087     }
1088
1089     void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1090     {
1091         m_assembler.vmul_f64_r(dest, op1, op2);
1092     }
1093
1094     void sqrtDouble(FPRegisterID src, FPRegisterID dest)
1095     {
1096         m_assembler.vsqrt_f64_r(dest, src);
1097     }
1098     
1099     void absDouble(FPRegisterID src, FPRegisterID dest)
1100     {
1101         m_assembler.vabs_f64_r(dest, src);
1102     }
1103
1104     void negateDouble(FPRegisterID src, FPRegisterID dest)
1105     {
1106         m_assembler.vneg_f64_r(dest, src);
1107     }
1108
1109     void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
1110     {
1111         m_assembler.vmov_vfp32_r(dest << 1, src);
1112         m_assembler.vcvt_f64_s32_r(dest, dest << 1);
1113     }
1114
1115     void convertInt32ToDouble(Address src, FPRegisterID dest)
1116     {
1117         load32(src, ARMRegisters::S1);
1118         convertInt32ToDouble(ARMRegisters::S1, dest);
1119     }
1120
1121     void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest)
1122     {
1123         move(TrustedImmPtr(src.m_ptr), ARMRegisters::S1);
1124         load32(Address(ARMRegisters::S1), ARMRegisters::S1);
1125         convertInt32ToDouble(ARMRegisters::S1, dest);
1126     }
1127
1128     void convertFloatToDouble(FPRegisterID src, FPRegisterID dst)
1129     {
1130         m_assembler.vcvt_f64_f32_r(dst, src);
1131     }
1132
1133     void convertDoubleToFloat(FPRegisterID src, FPRegisterID dst)
1134     {
1135         m_assembler.vcvt_f32_f64_r(dst, src);
1136     }
1137
1138     Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
1139     {
1140         m_assembler.vcmp_f64_r(left, right);
1141         m_assembler.vmrs_apsr();
1142         if (cond & DoubleConditionBitSpecial)
1143             m_assembler.cmp_r(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::VS);
1144         return Jump(m_assembler.jmp(static_cast<ARMAssembler::Condition>(cond & ~DoubleConditionMask)));
1145     }
1146
1147     // Truncates 'src' to an integer, and places the resulting 'dest'.
1148     // If the result is not representable as a 32 bit value, branch.
1149     // May also branch for some values that are representable in 32 bits
1150     // (specifically, in this case, INT_MIN).
1151     enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful };
1152     Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
1153     {
1154         truncateDoubleToInt32(src, dest);
1155
1156         m_assembler.add_r(ARMRegisters::S0, dest, ARMAssembler::getOp2Byte(1));
1157         m_assembler.bic_r(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Byte(1));
1158
1159         ARMWord w = ARMAssembler::getOp2(0x80000000);
1160         ASSERT(w != ARMAssembler::INVALID_IMM);
1161         m_assembler.cmp_r(ARMRegisters::S0, w);
1162         return Jump(m_assembler.jmp(branchType == BranchIfTruncateFailed ? ARMAssembler::EQ : ARMAssembler::NE));
1163     }
1164
1165     Jump branchTruncateDoubleToUint32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
1166     {
1167         truncateDoubleToUint32(src, dest);
1168
1169         m_assembler.add_r(ARMRegisters::S0, dest, ARMAssembler::getOp2Byte(1));
1170         m_assembler.bic_r(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Byte(1));
1171
1172         m_assembler.cmp_r(ARMRegisters::S0, ARMAssembler::getOp2Byte(0));
1173         return Jump(m_assembler.jmp(branchType == BranchIfTruncateFailed ? ARMAssembler::EQ : ARMAssembler::NE));
1174     }
1175
1176     // Result is undefined if the value is outside of the integer range.
1177     void truncateDoubleToInt32(FPRegisterID src, RegisterID dest)
1178     {
1179         m_assembler.vcvt_s32_f64_r(ARMRegisters::SD0 << 1, src);
1180         m_assembler.vmov_arm32_r(dest, ARMRegisters::SD0 << 1);
1181     }
1182
1183     void truncateDoubleToUint32(FPRegisterID src, RegisterID dest)
1184     {
1185         m_assembler.vcvt_u32_f64_r(ARMRegisters::SD0 << 1, src);
1186         m_assembler.vmov_arm32_r(dest, ARMRegisters::SD0 << 1);
1187     }
1188
1189     // Convert 'src' to an integer, and places the resulting 'dest'.
1190     // If the result is not representable as a 32 bit value, branch.
1191     // May also branch for some values that are representable in 32 bits
1192     // (specifically, in this case, 0).
1193     void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp)
1194     {
1195         m_assembler.vcvt_s32_f64_r(ARMRegisters::SD0 << 1, src);
1196         m_assembler.vmov_arm32_r(dest, ARMRegisters::SD0 << 1);
1197
1198         // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
1199         m_assembler.vcvt_f64_s32_r(ARMRegisters::SD0, ARMRegisters::SD0 << 1);
1200         failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, ARMRegisters::SD0));
1201
1202         // If the result is zero, it might have been -0.0, and 0.0 equals to -0.0
1203         failureCases.append(branchTest32(Zero, dest));
1204     }
1205
1206     Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch)
1207     {
1208         m_assembler.mov_r(ARMRegisters::S0, ARMAssembler::getOp2Byte(0));
1209         convertInt32ToDouble(ARMRegisters::S0, scratch);
1210         return branchDouble(DoubleNotEqual, reg, scratch);
1211     }
1212
1213     Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID scratch)
1214     {
1215         m_assembler.mov_r(ARMRegisters::S0, ARMAssembler::getOp2Byte(0));
1216         convertInt32ToDouble(ARMRegisters::S0, scratch);
1217         return branchDouble(DoubleEqualOrUnordered, reg, scratch);
1218     }
1219
1220     // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc.
1221     static RelationalCondition invert(RelationalCondition cond)
1222     {
1223         ASSERT((static_cast<uint32_t>(cond & 0x0fffffff)) == 0 && static_cast<uint32_t>(cond) < static_cast<uint32_t>(ARMAssembler::AL));
1224         return static_cast<RelationalCondition>(cond ^ 0x10000000);
1225     }
1226
1227     void nop()
1228     {
1229         m_assembler.nop();
1230     }
1231
1232     static FunctionPtr readCallTarget(CodeLocationCall call)
1233     {
1234         return FunctionPtr(reinterpret_cast<void(*)()>(ARMAssembler::readCallTarget(call.dataLocation())));
1235     }
1236
1237     static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
1238     {
1239         ARMAssembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation());
1240     }
1241     
1242     static ptrdiff_t maxJumpReplacementSize()
1243     {
1244         ARMAssembler::maxJumpReplacementSize();
1245         return 0;
1246     }
1247
1248 protected:
1249     ARMAssembler::Condition ARMCondition(RelationalCondition cond)
1250     {
1251         return static_cast<ARMAssembler::Condition>(cond);
1252     }
1253
1254     ARMAssembler::Condition ARMCondition(ResultCondition cond)
1255     {
1256         return static_cast<ARMAssembler::Condition>(cond);
1257     }
1258
1259     void ensureSpace(int insnSpace, int constSpace)
1260     {
1261         m_assembler.ensureSpace(insnSpace, constSpace);
1262     }
1263
1264     int sizeOfConstantPool()
1265     {
1266         return m_assembler.sizeOfConstantPool();
1267     }
1268
1269     void call32(RegisterID base, int32_t offset)
1270     {
1271         load32(Address(base, offset), ARMRegisters::S1);
1272         m_assembler.blx(ARMRegisters::S1);
1273     }
1274
1275 private:
1276     friend class LinkBuffer;
1277     friend class RepatchBuffer;
1278
1279     static void linkCall(void* code, Call call, FunctionPtr function)
1280     {
1281         ARMAssembler::linkCall(code, call.m_label, function.value());
1282     }
1283
1284     static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
1285     {
1286         ARMAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
1287     }
1288
1289     static void repatchCall(CodeLocationCall call, FunctionPtr destination)
1290     {
1291         ARMAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
1292     }
1293
1294     static const bool s_isVFPPresent;
1295 };
1296
1297 }
1298
1299 #endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
1300
1301 #endif // MacroAssemblerARM_h