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