Merge "Save and re-bind previously bounded texture when using cairo_gl_surface_set_bi...
[framework/web/webkit-efl.git] / Source / JavaScriptCore / assembler / MacroAssemblerX86Common.h
1 /*
2  * Copyright (C) 2008 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #ifndef MacroAssemblerX86Common_h
27 #define MacroAssemblerX86Common_h
28
29 #if ENABLE(ASSEMBLER)
30
31 #include "X86Assembler.h"
32 #include "AbstractMacroAssembler.h"
33
34 namespace JSC {
35
36 class MacroAssemblerX86Common : public AbstractMacroAssembler<X86Assembler> {
37 protected:
38 #if CPU(X86_64)
39     static const X86Registers::RegisterID scratchRegister = X86Registers::r11;
40 #endif
41
42     static const int DoubleConditionBitInvert = 0x10;
43     static const int DoubleConditionBitSpecial = 0x20;
44     static const int DoubleConditionBits = DoubleConditionBitInvert | DoubleConditionBitSpecial;
45
46 public:
47     typedef X86Assembler::FPRegisterID FPRegisterID;
48     typedef X86Assembler::XMMRegisterID XMMRegisterID;
49     
50     static bool isCompactPtrAlignedAddressOffset(ptrdiff_t value)
51     {
52         return value >= -128 && value <= 127;
53     }
54
55     enum RelationalCondition {
56         Equal = X86Assembler::ConditionE,
57         NotEqual = X86Assembler::ConditionNE,
58         Above = X86Assembler::ConditionA,
59         AboveOrEqual = X86Assembler::ConditionAE,
60         Below = X86Assembler::ConditionB,
61         BelowOrEqual = X86Assembler::ConditionBE,
62         GreaterThan = X86Assembler::ConditionG,
63         GreaterThanOrEqual = X86Assembler::ConditionGE,
64         LessThan = X86Assembler::ConditionL,
65         LessThanOrEqual = X86Assembler::ConditionLE
66     };
67
68     enum ResultCondition {
69         Overflow = X86Assembler::ConditionO,
70         Signed = X86Assembler::ConditionS,
71         Zero = X86Assembler::ConditionE,
72         NonZero = X86Assembler::ConditionNE
73     };
74
75     enum DoubleCondition {
76         // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
77         DoubleEqual = X86Assembler::ConditionE | DoubleConditionBitSpecial,
78         DoubleNotEqual = X86Assembler::ConditionNE,
79         DoubleGreaterThan = X86Assembler::ConditionA,
80         DoubleGreaterThanOrEqual = X86Assembler::ConditionAE,
81         DoubleLessThan = X86Assembler::ConditionA | DoubleConditionBitInvert,
82         DoubleLessThanOrEqual = X86Assembler::ConditionAE | DoubleConditionBitInvert,
83         // If either operand is NaN, these conditions always evaluate to true.
84         DoubleEqualOrUnordered = X86Assembler::ConditionE,
85         DoubleNotEqualOrUnordered = X86Assembler::ConditionNE | DoubleConditionBitSpecial,
86         DoubleGreaterThanOrUnordered = X86Assembler::ConditionB | DoubleConditionBitInvert,
87         DoubleGreaterThanOrEqualOrUnordered = X86Assembler::ConditionBE | DoubleConditionBitInvert,
88         DoubleLessThanOrUnordered = X86Assembler::ConditionB,
89         DoubleLessThanOrEqualOrUnordered = X86Assembler::ConditionBE,
90     };
91     COMPILE_ASSERT(
92         !((X86Assembler::ConditionE | X86Assembler::ConditionNE | X86Assembler::ConditionA | X86Assembler::ConditionAE | X86Assembler::ConditionB | X86Assembler::ConditionBE) & DoubleConditionBits),
93         DoubleConditionBits_should_not_interfere_with_X86Assembler_Condition_codes);
94
95     static const RegisterID stackPointerRegister = X86Registers::esp;
96
97 #if ENABLE(JIT_CONSTANT_BLINDING)
98     static bool shouldBlindForSpecificArch(uint32_t value) { return value >= 0x00ffffff; }
99 #if CPU(X86_64)
100     static bool shouldBlindForSpecificArch(uintptr_t value) { return value >= 0x00ffffff; }
101 #endif
102 #endif
103
104     // Integer arithmetic operations:
105     //
106     // Operations are typically two operand - operation(source, srcDst)
107     // For many operations the source may be an TrustedImm32, the srcDst operand
108     // may often be a memory location (explictly described using an Address
109     // object).
110
111     void add32(RegisterID src, RegisterID dest)
112     {
113         m_assembler.addl_rr(src, dest);
114     }
115
116     void add32(TrustedImm32 imm, Address address)
117     {
118         m_assembler.addl_im(imm.m_value, address.offset, address.base);
119     }
120
121     void add32(TrustedImm32 imm, RegisterID dest)
122     {
123         m_assembler.addl_ir(imm.m_value, dest);
124     }
125     
126     void add32(Address src, RegisterID dest)
127     {
128         m_assembler.addl_mr(src.offset, src.base, dest);
129     }
130
131     void add32(RegisterID src, Address dest)
132     {
133         m_assembler.addl_rm(src, dest.offset, dest.base);
134     }
135
136     void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
137     {
138         m_assembler.leal_mr(imm.m_value, src, dest);
139     }
140     
141     void and32(RegisterID src, RegisterID dest)
142     {
143         m_assembler.andl_rr(src, dest);
144     }
145
146     void and32(TrustedImm32 imm, RegisterID dest)
147     {
148         m_assembler.andl_ir(imm.m_value, dest);
149     }
150
151     void and32(RegisterID src, Address dest)
152     {
153         m_assembler.andl_rm(src, dest.offset, dest.base);
154     }
155
156     void and32(Address src, RegisterID dest)
157     {
158         m_assembler.andl_mr(src.offset, src.base, dest);
159     }
160
161     void and32(TrustedImm32 imm, Address address)
162     {
163         m_assembler.andl_im(imm.m_value, address.offset, address.base);
164     }
165
166     void and32(RegisterID op1, RegisterID op2, RegisterID dest)
167     {
168         if (op1 == op2)
169             zeroExtend32ToPtr(op1, dest);
170         else if (op1 == dest)
171             and32(op2, dest);
172         else {
173             move(op2, dest);
174             and32(op1, dest);
175         }
176     }
177
178     void and32(TrustedImm32 imm, RegisterID src, RegisterID dest)
179     {
180         move(src, dest);
181         and32(imm, dest);
182     }
183
184     void lshift32(RegisterID shift_amount, RegisterID dest)
185     {
186         ASSERT(shift_amount != dest);
187
188         if (shift_amount == X86Registers::ecx)
189             m_assembler.shll_CLr(dest);
190         else {
191             // On x86 we can only shift by ecx; if asked to shift by another register we'll
192             // need rejig the shift amount into ecx first, and restore the registers afterwards.
193             // If we dest is ecx, then shift the swapped register!
194             swap(shift_amount, X86Registers::ecx);
195             m_assembler.shll_CLr(dest == X86Registers::ecx ? shift_amount : dest);
196             swap(shift_amount, X86Registers::ecx);
197         }
198     }
199
200     void lshift32(RegisterID src, RegisterID shift_amount, RegisterID dest)
201     {
202         ASSERT(shift_amount != dest);
203
204         if (src != dest)
205             move(src, dest);
206         lshift32(shift_amount, dest);
207     }
208
209     void lshift32(TrustedImm32 imm, RegisterID dest)
210     {
211         m_assembler.shll_i8r(imm.m_value, dest);
212     }
213     
214     void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
215     {
216         if (src != dest)
217             move(src, dest);
218         lshift32(imm, dest);
219     }
220     
221     void mul32(RegisterID src, RegisterID dest)
222     {
223         m_assembler.imull_rr(src, dest);
224     }
225
226     void mul32(Address src, RegisterID dest)
227     {
228         m_assembler.imull_mr(src.offset, src.base, dest);
229     }
230     
231     void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
232     {
233         m_assembler.imull_i32r(src, imm.m_value, dest);
234     }
235
236     void neg32(RegisterID srcDest)
237     {
238         m_assembler.negl_r(srcDest);
239     }
240
241     void neg32(Address srcDest)
242     {
243         m_assembler.negl_m(srcDest.offset, srcDest.base);
244     }
245
246     void or32(RegisterID src, RegisterID dest)
247     {
248         m_assembler.orl_rr(src, dest);
249     }
250
251     void or32(TrustedImm32 imm, RegisterID dest)
252     {
253         m_assembler.orl_ir(imm.m_value, dest);
254     }
255
256     void or32(RegisterID src, Address dest)
257     {
258         m_assembler.orl_rm(src, dest.offset, dest.base);
259     }
260
261     void or32(Address src, RegisterID dest)
262     {
263         m_assembler.orl_mr(src.offset, src.base, dest);
264     }
265
266     void or32(TrustedImm32 imm, Address address)
267     {
268         m_assembler.orl_im(imm.m_value, address.offset, address.base);
269     }
270
271     void or32(RegisterID op1, RegisterID op2, RegisterID dest)
272     {
273         if (op1 == op2)
274             zeroExtend32ToPtr(op1, dest);
275         else if (op1 == dest)
276             or32(op2, dest);
277         else {
278             move(op2, dest);
279             or32(op1, dest);
280         }
281     }
282
283     void or32(TrustedImm32 imm, RegisterID src, RegisterID dest)
284     {
285         move(src, dest);
286         or32(imm, dest);
287     }
288
289     void rshift32(RegisterID shift_amount, RegisterID dest)
290     {
291         ASSERT(shift_amount != dest);
292
293         if (shift_amount == X86Registers::ecx)
294             m_assembler.sarl_CLr(dest);
295         else {
296             // On x86 we can only shift by ecx; if asked to shift by another register we'll
297             // need rejig the shift amount into ecx first, and restore the registers afterwards.
298             // If we dest is ecx, then shift the swapped register!
299             swap(shift_amount, X86Registers::ecx);
300             m_assembler.sarl_CLr(dest == X86Registers::ecx ? shift_amount : dest);
301             swap(shift_amount, X86Registers::ecx);
302         }
303     }
304
305     void rshift32(RegisterID src, RegisterID shift_amount, RegisterID dest)
306     {
307         ASSERT(shift_amount != dest);
308
309         if (src != dest)
310             move(src, dest);
311         rshift32(shift_amount, dest);
312     }
313
314     void rshift32(TrustedImm32 imm, RegisterID dest)
315     {
316         m_assembler.sarl_i8r(imm.m_value, dest);
317     }
318     
319     void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
320     {
321         if (src != dest)
322             move(src, dest);
323         rshift32(imm, dest);
324     }
325     
326     void urshift32(RegisterID shift_amount, RegisterID dest)
327     {
328         ASSERT(shift_amount != dest);
329
330         if (shift_amount == X86Registers::ecx)
331             m_assembler.shrl_CLr(dest);
332         else {
333             // On x86 we can only shift by ecx; if asked to shift by another register we'll
334             // need rejig the shift amount into ecx first, and restore the registers afterwards.
335             // If we dest is ecx, then shift the swapped register!
336             swap(shift_amount, X86Registers::ecx);
337             m_assembler.shrl_CLr(dest == X86Registers::ecx ? shift_amount : dest);
338             swap(shift_amount, X86Registers::ecx);
339         }
340     }
341
342     void urshift32(RegisterID src, RegisterID shift_amount, RegisterID dest)
343     {
344         ASSERT(shift_amount != dest);
345
346         if (src != dest)
347             move(src, dest);
348         urshift32(shift_amount, dest);
349     }
350
351     void urshift32(TrustedImm32 imm, RegisterID dest)
352     {
353         m_assembler.shrl_i8r(imm.m_value, dest);
354     }
355     
356     void urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
357     {
358         if (src != dest)
359             move(src, dest);
360         urshift32(imm, dest);
361     }
362     
363     void sub32(RegisterID src, RegisterID dest)
364     {
365         m_assembler.subl_rr(src, dest);
366     }
367     
368     void sub32(TrustedImm32 imm, RegisterID dest)
369     {
370         m_assembler.subl_ir(imm.m_value, dest);
371     }
372     
373     void sub32(TrustedImm32 imm, Address address)
374     {
375         m_assembler.subl_im(imm.m_value, address.offset, address.base);
376     }
377
378     void sub32(Address src, RegisterID dest)
379     {
380         m_assembler.subl_mr(src.offset, src.base, dest);
381     }
382
383     void sub32(RegisterID src, Address dest)
384     {
385         m_assembler.subl_rm(src, dest.offset, dest.base);
386     }
387
388     void xor32(RegisterID src, RegisterID dest)
389     {
390         m_assembler.xorl_rr(src, dest);
391     }
392
393     void xor32(TrustedImm32 imm, Address dest)
394     {
395         if (imm.m_value == -1)
396             m_assembler.notl_m(dest.offset, dest.base);
397         else
398             m_assembler.xorl_im(imm.m_value, dest.offset, dest.base);
399     }
400
401     void xor32(TrustedImm32 imm, RegisterID dest)
402     {
403         if (imm.m_value == -1)
404         m_assembler.notl_r(dest);
405         else
406         m_assembler.xorl_ir(imm.m_value, dest);
407     }
408
409     void xor32(RegisterID src, Address dest)
410     {
411         m_assembler.xorl_rm(src, dest.offset, dest.base);
412     }
413
414     void xor32(Address src, RegisterID dest)
415     {
416         m_assembler.xorl_mr(src.offset, src.base, dest);
417     }
418     
419     void xor32(RegisterID op1, RegisterID op2, RegisterID dest)
420     {
421         if (op1 == op2)
422             move(TrustedImm32(0), dest);
423         else if (op1 == dest)
424             xor32(op2, dest);
425         else {
426             move(op2, dest);
427             xor32(op1, dest);
428         }
429     }
430
431     void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest)
432     {
433         move(src, dest);
434         xor32(imm, dest);
435     }
436
437     void sqrtDouble(FPRegisterID src, FPRegisterID dst)
438     {
439         m_assembler.sqrtsd_rr(src, dst);
440     }
441
442     void absDouble(FPRegisterID src, FPRegisterID dst)
443     {
444         ASSERT(src != dst);
445         static const double negativeZeroConstant = -0.0;
446         loadDouble(&negativeZeroConstant, dst);
447         m_assembler.andnpd_rr(src, dst);
448     }
449
450     void negateDouble(FPRegisterID src, FPRegisterID dst)
451     {
452         ASSERT(src != dst);
453         static const double negativeZeroConstant = -0.0;
454         loadDouble(&negativeZeroConstant, dst);
455         m_assembler.xorpd_rr(src, dst);
456     }
457
458
459     // Memory access operations:
460     //
461     // Loads are of the form load(address, destination) and stores of the form
462     // store(source, address).  The source for a store may be an TrustedImm32.  Address
463     // operand objects to loads and store will be implicitly constructed if a
464     // register is passed.
465
466     void load32(ImplicitAddress address, RegisterID dest)
467     {
468         m_assembler.movl_mr(address.offset, address.base, dest);
469     }
470
471     void load32(BaseIndex address, RegisterID dest)
472     {
473         m_assembler.movl_mr(address.offset, address.base, address.index, address.scale, dest);
474     }
475
476     void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
477     {
478         load32(address, dest);
479     }
480
481     void load16Unaligned(BaseIndex address, RegisterID dest)
482     {
483         load16(address, dest);
484     }
485
486     DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
487     {
488         m_assembler.movl_mr_disp32(address.offset, address.base, dest);
489         return DataLabel32(this);
490     }
491     
492     DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
493     {
494         m_assembler.movl_mr_disp8(address.offset, address.base, dest);
495         return DataLabelCompact(this);
496     }
497     
498     static void repatchCompact(CodeLocationDataLabelCompact dataLabelCompact, int32_t value)
499     {
500         ASSERT(isCompactPtrAlignedAddressOffset(value));
501         AssemblerType_T::repatchCompact(dataLabelCompact.dataLocation(), value);
502     }
503     
504     DataLabelCompact loadCompactWithAddressOffsetPatch(Address address, RegisterID dest)
505     {
506         m_assembler.movl_mr_disp8(address.offset, address.base, dest);
507         return DataLabelCompact(this);
508     }
509
510     void load8(BaseIndex address, RegisterID dest)
511     {
512         m_assembler.movzbl_mr(address.offset, address.base, address.index, address.scale, dest);
513     }
514
515     void load8(ImplicitAddress address, RegisterID dest)
516     {
517         m_assembler.movzbl_mr(address.offset, address.base, dest);
518     }
519     
520     void load8Signed(BaseIndex address, RegisterID dest)
521     {
522         m_assembler.movsbl_mr(address.offset, address.base, address.index, address.scale, dest);
523     }
524
525     void load8Signed(ImplicitAddress address, RegisterID dest)
526     {
527         m_assembler.movsbl_mr(address.offset, address.base, dest);
528     }
529     
530     void load16(BaseIndex address, RegisterID dest)
531     {
532         m_assembler.movzwl_mr(address.offset, address.base, address.index, address.scale, dest);
533     }
534     
535     void load16(Address address, RegisterID dest)
536     {
537         m_assembler.movzwl_mr(address.offset, address.base, dest);
538     }
539
540     void load16Signed(BaseIndex address, RegisterID dest)
541     {
542         m_assembler.movswl_mr(address.offset, address.base, address.index, address.scale, dest);
543     }
544     
545     void load16Signed(Address address, RegisterID dest)
546     {
547         m_assembler.movswl_mr(address.offset, address.base, dest);
548     }
549
550     DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
551     {
552         m_assembler.movl_rm_disp32(src, address.offset, address.base);
553         return DataLabel32(this);
554     }
555
556     void store32(RegisterID src, ImplicitAddress address)
557     {
558         m_assembler.movl_rm(src, address.offset, address.base);
559     }
560
561     void store32(RegisterID src, BaseIndex address)
562     {
563         m_assembler.movl_rm(src, address.offset, address.base, address.index, address.scale);
564     }
565
566     void store32(TrustedImm32 imm, ImplicitAddress address)
567     {
568         m_assembler.movl_i32m(imm.m_value, address.offset, address.base);
569     }
570     
571     void store32(TrustedImm32 imm, BaseIndex address)
572     {
573         m_assembler.movl_i32m(imm.m_value, address.offset, address.base, address.index, address.scale);
574     }
575
576     void store8(TrustedImm32 imm, Address address)
577     {
578         ASSERT(-128 <= imm.m_value && imm.m_value < 128);
579         m_assembler.movb_i8m(imm.m_value, address.offset, address.base);
580     }
581
582     void store8(TrustedImm32 imm, BaseIndex address)
583     {
584         ASSERT(-128 <= imm.m_value && imm.m_value < 128);
585         m_assembler.movb_i8m(imm.m_value, address.offset, address.base, address.index, address.scale);
586     }
587     
588     void store8(RegisterID src, BaseIndex address)
589     {
590 #if CPU(X86)
591         // On 32-bit x86 we can only store from the first 4 registers;
592         // esp..edi are mapped to the 'h' registers!
593         if (src >= 4) {
594             // Pick a temporary register.
595             RegisterID temp;
596             if (address.base != X86Registers::eax && address.index != X86Registers::eax)
597                 temp = X86Registers::eax;
598             else if (address.base != X86Registers::ebx && address.index != X86Registers::ebx)
599                 temp = X86Registers::ebx;
600             else {
601                 ASSERT(address.base != X86Registers::ecx && address.index != X86Registers::ecx);
602                 temp = X86Registers::ecx;
603             }
604
605             // Swap to the temporary register to perform the store.
606             swap(src, temp);
607             m_assembler.movb_rm(temp, address.offset, address.base, address.index, address.scale);
608             swap(src, temp);
609             return;
610         }
611 #endif
612         m_assembler.movb_rm(src, address.offset, address.base, address.index, address.scale);
613     }
614
615     void store16(RegisterID src, BaseIndex address)
616     {
617 #if CPU(X86)
618         // On 32-bit x86 we can only store from the first 4 registers;
619         // esp..edi are mapped to the 'h' registers!
620         if (src >= 4) {
621             // Pick a temporary register.
622             RegisterID temp;
623             if (address.base != X86Registers::eax && address.index != X86Registers::eax)
624                 temp = X86Registers::eax;
625             else if (address.base != X86Registers::ebx && address.index != X86Registers::ebx)
626                 temp = X86Registers::ebx;
627             else {
628                 ASSERT(address.base != X86Registers::ecx && address.index != X86Registers::ecx);
629                 temp = X86Registers::ecx;
630             }
631             
632             // Swap to the temporary register to perform the store.
633             swap(src, temp);
634             m_assembler.movw_rm(temp, address.offset, address.base, address.index, address.scale);
635             swap(src, temp);
636             return;
637         }
638 #endif
639         m_assembler.movw_rm(src, address.offset, address.base, address.index, address.scale);
640     }
641
642
643     // Floating-point operation:
644     //
645     // Presently only supports SSE, not x87 floating point.
646
647     void moveDouble(FPRegisterID src, FPRegisterID dest)
648     {
649         ASSERT(isSSE2Present());
650         if (src != dest)
651             m_assembler.movsd_rr(src, dest);
652     }
653
654     void loadDouble(const void* address, FPRegisterID dest)
655     {
656 #if CPU(X86)
657         ASSERT(isSSE2Present());
658         m_assembler.movsd_mr(address, dest);
659 #else
660         move(TrustedImmPtr(address), scratchRegister);
661         loadDouble(scratchRegister, dest);
662 #endif
663     }
664
665     void loadDouble(ImplicitAddress address, FPRegisterID dest)
666     {
667         ASSERT(isSSE2Present());
668         m_assembler.movsd_mr(address.offset, address.base, dest);
669     }
670     
671     void loadDouble(BaseIndex address, FPRegisterID dest)
672     {
673         ASSERT(isSSE2Present());
674         m_assembler.movsd_mr(address.offset, address.base, address.index, address.scale, dest);
675     }
676     void loadFloat(BaseIndex address, FPRegisterID dest)
677     {
678         ASSERT(isSSE2Present());
679         m_assembler.movss_mr(address.offset, address.base, address.index, address.scale, dest);
680     }
681
682     void storeDouble(FPRegisterID src, ImplicitAddress address)
683     {
684         ASSERT(isSSE2Present());
685         m_assembler.movsd_rm(src, address.offset, address.base);
686     }
687     
688     void storeDouble(FPRegisterID src, BaseIndex address)
689     {
690         ASSERT(isSSE2Present());
691         m_assembler.movsd_rm(src, address.offset, address.base, address.index, address.scale);
692     }
693     
694     void storeFloat(FPRegisterID src, BaseIndex address)
695     {
696         ASSERT(isSSE2Present());
697         m_assembler.movss_rm(src, address.offset, address.base, address.index, address.scale);
698     }
699     
700     void convertDoubleToFloat(FPRegisterID src, FPRegisterID dst)
701     {
702         ASSERT(isSSE2Present());
703         m_assembler.cvtsd2ss_rr(src, dst);
704     }
705
706     void convertFloatToDouble(FPRegisterID src, FPRegisterID dst)
707     {
708         ASSERT(isSSE2Present());
709         m_assembler.cvtss2sd_rr(src, dst);
710     }
711
712     void addDouble(FPRegisterID src, FPRegisterID dest)
713     {
714         ASSERT(isSSE2Present());
715         m_assembler.addsd_rr(src, dest);
716     }
717
718     void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
719     {
720         ASSERT(isSSE2Present());
721         if (op1 == dest)
722             addDouble(op2, dest);
723         else {
724             moveDouble(op2, dest);
725             addDouble(op1, dest);
726         }
727     }
728
729     void addDouble(Address src, FPRegisterID dest)
730     {
731         ASSERT(isSSE2Present());
732         m_assembler.addsd_mr(src.offset, src.base, dest);
733     }
734
735     void divDouble(FPRegisterID src, FPRegisterID dest)
736     {
737         ASSERT(isSSE2Present());
738         m_assembler.divsd_rr(src, dest);
739     }
740
741     void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
742     {
743         // B := A / B is invalid.
744         ASSERT(op1 == dest || op2 != dest);
745
746         moveDouble(op1, dest);
747         divDouble(op2, dest);
748     }
749
750     void divDouble(Address src, FPRegisterID dest)
751     {
752         ASSERT(isSSE2Present());
753         m_assembler.divsd_mr(src.offset, src.base, dest);
754     }
755
756     void subDouble(FPRegisterID src, FPRegisterID dest)
757     {
758         ASSERT(isSSE2Present());
759         m_assembler.subsd_rr(src, dest);
760     }
761
762     void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
763     {
764         // B := A - B is invalid.
765         ASSERT(op1 == dest || op2 != dest);
766
767         moveDouble(op1, dest);
768         subDouble(op2, dest);
769     }
770
771     void subDouble(Address src, FPRegisterID dest)
772     {
773         ASSERT(isSSE2Present());
774         m_assembler.subsd_mr(src.offset, src.base, dest);
775     }
776
777     void mulDouble(FPRegisterID src, FPRegisterID dest)
778     {
779         ASSERT(isSSE2Present());
780         m_assembler.mulsd_rr(src, dest);
781     }
782
783     void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
784     {
785         ASSERT(isSSE2Present());
786         if (op1 == dest)
787             mulDouble(op2, dest);
788         else {
789             moveDouble(op2, dest);
790             mulDouble(op1, dest);
791         }
792     }
793
794     void mulDouble(Address src, FPRegisterID dest)
795     {
796         ASSERT(isSSE2Present());
797         m_assembler.mulsd_mr(src.offset, src.base, dest);
798     }
799
800     void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
801     {
802         ASSERT(isSSE2Present());
803         m_assembler.cvtsi2sd_rr(src, dest);
804     }
805
806     void convertInt32ToDouble(Address src, FPRegisterID dest)
807     {
808         ASSERT(isSSE2Present());
809         m_assembler.cvtsi2sd_mr(src.offset, src.base, dest);
810     }
811
812     Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
813     {
814         ASSERT(isSSE2Present());
815
816         if (cond & DoubleConditionBitInvert)
817             m_assembler.ucomisd_rr(left, right);
818         else
819             m_assembler.ucomisd_rr(right, left);
820
821         if (cond == DoubleEqual) {
822             Jump isUnordered(m_assembler.jp());
823             Jump result = Jump(m_assembler.je());
824             isUnordered.link(this);
825             return result;
826         } else if (cond == DoubleNotEqualOrUnordered) {
827             Jump isUnordered(m_assembler.jp());
828             Jump isEqual(m_assembler.je());
829             isUnordered.link(this);
830             Jump result = jump();
831             isEqual.link(this);
832             return result;
833         }
834
835         ASSERT(!(cond & DoubleConditionBitSpecial));
836         return Jump(m_assembler.jCC(static_cast<X86Assembler::Condition>(cond & ~DoubleConditionBits)));
837     }
838
839     // Truncates 'src' to an integer, and places the resulting 'dest'.
840     // If the result is not representable as a 32 bit value, branch.
841     // May also branch for some values that are representable in 32 bits
842     // (specifically, in this case, INT_MIN).
843     enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful };
844     Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
845     {
846         ASSERT(isSSE2Present());
847         m_assembler.cvttsd2si_rr(src, dest);
848         return branch32(branchType ? NotEqual : Equal, dest, TrustedImm32(0x80000000));
849     }
850
851     Jump branchTruncateDoubleToUint32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
852     {
853         ASSERT(isSSE2Present());
854         m_assembler.cvttsd2si_rr(src, dest);
855         return branch32(branchType ? GreaterThanOrEqual : LessThan, dest, TrustedImm32(0));
856     }
857
858     void truncateDoubleToInt32(FPRegisterID src, RegisterID dest)
859     {
860         ASSERT(isSSE2Present());
861         m_assembler.cvttsd2si_rr(src, dest);
862     }
863     
864 #if CPU(X86_64)
865     void truncateDoubleToUint32(FPRegisterID src, RegisterID dest)
866     {
867         ASSERT(isSSE2Present());
868         m_assembler.cvttsd2siq_rr(src, dest);
869     }
870 #endif
871     
872     // Convert 'src' to an integer, and places the resulting 'dest'.
873     // If the result is not representable as a 32 bit value, branch.
874     // May also branch for some values that are representable in 32 bits
875     // (specifically, in this case, 0).
876     void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp)
877     {
878         ASSERT(isSSE2Present());
879         m_assembler.cvttsd2si_rr(src, dest);
880
881         // If the result is zero, it might have been -0.0, and the double comparison won't catch this!
882         failureCases.append(branchTest32(Zero, dest));
883
884         // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
885         convertInt32ToDouble(dest, fpTemp);
886         m_assembler.ucomisd_rr(fpTemp, src);
887         failureCases.append(m_assembler.jp());
888         failureCases.append(m_assembler.jne());
889     }
890
891     Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch)
892     {
893         ASSERT(isSSE2Present());
894         m_assembler.xorpd_rr(scratch, scratch);
895         return branchDouble(DoubleNotEqual, reg, scratch);
896     }
897
898     Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID scratch)
899     {
900         ASSERT(isSSE2Present());
901         m_assembler.xorpd_rr(scratch, scratch);
902         return branchDouble(DoubleEqualOrUnordered, reg, scratch);
903     }
904
905     void lshiftPacked(TrustedImm32 imm, XMMRegisterID reg)
906     {
907         ASSERT(isSSE2Present());
908         m_assembler.psllq_i8r(imm.m_value, reg);
909     }
910
911     void rshiftPacked(TrustedImm32 imm, XMMRegisterID reg)
912     {
913         ASSERT(isSSE2Present());
914         m_assembler.psrlq_i8r(imm.m_value, reg);
915     }
916
917     void orPacked(XMMRegisterID src, XMMRegisterID dst)
918     {
919         ASSERT(isSSE2Present());
920         m_assembler.por_rr(src, dst);
921     }
922
923     void moveInt32ToPacked(RegisterID src, XMMRegisterID dst)
924     {
925         ASSERT(isSSE2Present());
926         m_assembler.movd_rr(src, dst);
927     }
928
929     void movePackedToInt32(XMMRegisterID src, RegisterID dst)
930     {
931         ASSERT(isSSE2Present());
932         m_assembler.movd_rr(src, dst);
933     }
934
935     // Stack manipulation operations:
936     //
937     // The ABI is assumed to provide a stack abstraction to memory,
938     // containing machine word sized units of data.  Push and pop
939     // operations add and remove a single register sized unit of data
940     // to or from the stack.  Peek and poke operations read or write
941     // values on the stack, without moving the current stack position.
942     
943     void pop(RegisterID dest)
944     {
945         m_assembler.pop_r(dest);
946     }
947
948     void push(RegisterID src)
949     {
950         m_assembler.push_r(src);
951     }
952
953     void push(Address address)
954     {
955         m_assembler.push_m(address.offset, address.base);
956     }
957
958     void push(TrustedImm32 imm)
959     {
960         m_assembler.push_i32(imm.m_value);
961     }
962
963
964     // Register move operations:
965     //
966     // Move values in registers.
967
968     void move(TrustedImm32 imm, RegisterID dest)
969     {
970         // Note: on 64-bit the TrustedImm32 value is zero extended into the register, it
971         // may be useful to have a separate version that sign extends the value?
972         if (!imm.m_value)
973             m_assembler.xorl_rr(dest, dest);
974         else
975             m_assembler.movl_i32r(imm.m_value, dest);
976     }
977
978 #if CPU(X86_64)
979     void move(RegisterID src, RegisterID dest)
980     {
981         // Note: on 64-bit this is is a full register move; perhaps it would be
982         // useful to have separate move32 & movePtr, with move32 zero extending?
983         if (src != dest)
984             m_assembler.movq_rr(src, dest);
985     }
986
987     void move(TrustedImmPtr imm, RegisterID dest)
988     {
989         m_assembler.movq_i64r(imm.asIntptr(), dest);
990     }
991
992     void swap(RegisterID reg1, RegisterID reg2)
993     {
994         if (reg1 != reg2)
995             m_assembler.xchgq_rr(reg1, reg2);
996     }
997
998     void signExtend32ToPtr(RegisterID src, RegisterID dest)
999     {
1000         m_assembler.movsxd_rr(src, dest);
1001     }
1002
1003     void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
1004     {
1005         m_assembler.movl_rr(src, dest);
1006     }
1007 #else
1008     void move(RegisterID src, RegisterID dest)
1009     {
1010         if (src != dest)
1011             m_assembler.movl_rr(src, dest);
1012     }
1013
1014     void move(TrustedImmPtr imm, RegisterID dest)
1015     {
1016         m_assembler.movl_i32r(imm.asIntptr(), dest);
1017     }
1018
1019     void swap(RegisterID reg1, RegisterID reg2)
1020     {
1021         if (reg1 != reg2)
1022             m_assembler.xchgl_rr(reg1, reg2);
1023     }
1024
1025     void signExtend32ToPtr(RegisterID src, RegisterID dest)
1026     {
1027         move(src, dest);
1028     }
1029
1030     void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
1031     {
1032         move(src, dest);
1033     }
1034 #endif
1035
1036
1037     // Forwards / external control flow operations:
1038     //
1039     // This set of jump and conditional branch operations return a Jump
1040     // object which may linked at a later point, allow forwards jump,
1041     // or jumps that will require external linkage (after the code has been
1042     // relocated).
1043     //
1044     // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
1045     // respecitvely, for unsigned comparisons the names b, a, be, and ae are
1046     // used (representing the names 'below' and 'above').
1047     //
1048     // Operands to the comparision are provided in the expected order, e.g.
1049     // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
1050     // treated as a signed 32bit value, is less than or equal to 5.
1051     //
1052     // jz and jnz test whether the first operand is equal to zero, and take
1053     // an optional second operand of a mask under which to perform the test.
1054
1055 public:
1056     Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
1057     {
1058         m_assembler.cmpb_im(right.m_value, left.offset, left.base);
1059         return Jump(m_assembler.jCC(x86Condition(cond)));
1060     }
1061
1062     Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
1063     {
1064         m_assembler.cmpl_rr(right, left);
1065         return Jump(m_assembler.jCC(x86Condition(cond)));
1066     }
1067
1068     Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1069     {
1070         if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
1071             m_assembler.testl_rr(left, left);
1072         else
1073             m_assembler.cmpl_ir(right.m_value, left);
1074         return Jump(m_assembler.jCC(x86Condition(cond)));
1075     }
1076     
1077     Jump branch32(RelationalCondition cond, RegisterID left, Address right)
1078     {
1079         m_assembler.cmpl_mr(right.offset, right.base, left);
1080         return Jump(m_assembler.jCC(x86Condition(cond)));
1081     }
1082     
1083     Jump branch32(RelationalCondition cond, Address left, RegisterID right)
1084     {
1085         m_assembler.cmpl_rm(right, left.offset, left.base);
1086         return Jump(m_assembler.jCC(x86Condition(cond)));
1087     }
1088
1089     Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
1090     {
1091         m_assembler.cmpl_im(right.m_value, left.offset, left.base);
1092         return Jump(m_assembler.jCC(x86Condition(cond)));
1093     }
1094
1095     Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1096     {
1097         m_assembler.cmpl_im(right.m_value, left.offset, left.base, left.index, left.scale);
1098         return Jump(m_assembler.jCC(x86Condition(cond)));
1099     }
1100
1101     Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1102     {
1103         return branch32(cond, left, right);
1104     }
1105
1106     Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
1107     {
1108         m_assembler.testl_rr(reg, mask);
1109         return Jump(m_assembler.jCC(x86Condition(cond)));
1110     }
1111
1112     Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1113     {
1114         // if we are only interested in the low seven bits, this can be tested with a testb
1115         if (mask.m_value == -1)
1116             m_assembler.testl_rr(reg, reg);
1117         else
1118             m_assembler.testl_i32r(mask.m_value, reg);
1119         return Jump(m_assembler.jCC(x86Condition(cond)));
1120     }
1121
1122     Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1123     {
1124         if (mask.m_value == -1)
1125             m_assembler.cmpl_im(0, address.offset, address.base);
1126         else
1127             m_assembler.testl_i32m(mask.m_value, address.offset, address.base);
1128         return Jump(m_assembler.jCC(x86Condition(cond)));
1129     }
1130
1131     Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
1132     {
1133         if (mask.m_value == -1)
1134             m_assembler.cmpl_im(0, address.offset, address.base, address.index, address.scale);
1135         else
1136             m_assembler.testl_i32m(mask.m_value, address.offset, address.base, address.index, address.scale);
1137         return Jump(m_assembler.jCC(x86Condition(cond)));
1138     }
1139     
1140     Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1141     {
1142         // Byte in TrustedImm32 is not well defined, so be a little permisive here, but don't accept nonsense values.
1143         ASSERT(mask.m_value >= -128 && mask.m_value <= 255);
1144         if (mask.m_value == -1)
1145             m_assembler.cmpb_im(0, address.offset, address.base);
1146         else
1147             m_assembler.testb_im(mask.m_value, address.offset, address.base);
1148         return Jump(m_assembler.jCC(x86Condition(cond)));
1149     }
1150     
1151     Jump branchTest8(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
1152     {
1153         // Byte in TrustedImm32 is not well defined, so be a little permisive here, but don't accept nonsense values.
1154         ASSERT(mask.m_value >= -128 && mask.m_value <= 255);
1155         if (mask.m_value == -1)
1156             m_assembler.cmpb_im(0, address.offset, address.base, address.index, address.scale);
1157         else
1158             m_assembler.testb_im(mask.m_value, address.offset, address.base, address.index, address.scale);
1159         return Jump(m_assembler.jCC(x86Condition(cond)));
1160     }
1161
1162     Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1163     {
1164         ASSERT(!(right.m_value & 0xFFFFFF00));
1165
1166         m_assembler.cmpb_im(right.m_value, left.offset, left.base, left.index, left.scale);
1167         return Jump(m_assembler.jCC(x86Condition(cond)));
1168     }
1169
1170     Jump jump()
1171     {
1172         return Jump(m_assembler.jmp());
1173     }
1174
1175     void jump(RegisterID target)
1176     {
1177         m_assembler.jmp_r(target);
1178     }
1179
1180     // Address is a memory location containing the address to jump to
1181     void jump(Address address)
1182     {
1183         m_assembler.jmp_m(address.offset, address.base);
1184     }
1185
1186
1187     // Arithmetic control flow operations:
1188     //
1189     // This set of conditional branch operations branch based
1190     // on the result of an arithmetic operation.  The operation
1191     // is performed as normal, storing the result.
1192     //
1193     // * jz operations branch if the result is zero.
1194     // * jo operations branch if the (signed) arithmetic
1195     //   operation caused an overflow to occur.
1196     
1197     Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
1198     {
1199         add32(src, dest);
1200         return Jump(m_assembler.jCC(x86Condition(cond)));
1201     }
1202
1203     Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1204     {
1205         add32(imm, dest);
1206         return Jump(m_assembler.jCC(x86Condition(cond)));
1207     }
1208     
1209     Jump branchAdd32(ResultCondition cond, TrustedImm32 src, Address dest)
1210     {
1211         add32(src, dest);
1212         return Jump(m_assembler.jCC(x86Condition(cond)));
1213     }
1214
1215     Jump branchAdd32(ResultCondition cond, RegisterID src, Address dest)
1216     {
1217         add32(src, dest);
1218         return Jump(m_assembler.jCC(x86Condition(cond)));
1219     }
1220
1221     Jump branchAdd32(ResultCondition cond, Address src, RegisterID dest)
1222     {
1223         add32(src, dest);
1224         return Jump(m_assembler.jCC(x86Condition(cond)));
1225     }
1226
1227     Jump branchAdd32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
1228     {
1229         if (src1 == dest)
1230             return branchAdd32(cond, src2, dest);
1231         move(src2, dest);
1232         return branchAdd32(cond, src1, dest);
1233     }
1234
1235     Jump branchAdd32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
1236     {
1237         move(src, dest);
1238         return branchAdd32(cond, imm, dest);
1239     }
1240
1241     Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
1242     {
1243         mul32(src, dest);
1244         if (cond != Overflow)
1245             m_assembler.testl_rr(dest, dest);
1246         return Jump(m_assembler.jCC(x86Condition(cond)));
1247     }
1248
1249     Jump branchMul32(ResultCondition cond, Address src, RegisterID dest)
1250     {
1251         mul32(src, dest);
1252         if (cond != Overflow)
1253             m_assembler.testl_rr(dest, dest);
1254         return Jump(m_assembler.jCC(x86Condition(cond)));
1255     }
1256     
1257     Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
1258     {
1259         mul32(imm, src, dest);
1260         if (cond != Overflow)
1261             m_assembler.testl_rr(dest, dest);
1262         return Jump(m_assembler.jCC(x86Condition(cond)));
1263     }
1264     
1265     Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
1266     {
1267         if (src1 == dest)
1268             return branchMul32(cond, src2, dest);
1269         move(src2, dest);
1270         return branchMul32(cond, src1, dest);
1271     }
1272
1273     Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
1274     {
1275         sub32(src, dest);
1276         return Jump(m_assembler.jCC(x86Condition(cond)));
1277     }
1278     
1279     Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1280     {
1281         sub32(imm, dest);
1282         return Jump(m_assembler.jCC(x86Condition(cond)));
1283     }
1284
1285     Jump branchSub32(ResultCondition cond, TrustedImm32 imm, Address dest)
1286     {
1287         sub32(imm, dest);
1288         return Jump(m_assembler.jCC(x86Condition(cond)));
1289     }
1290
1291     Jump branchSub32(ResultCondition cond, RegisterID src, Address dest)
1292     {
1293         sub32(src, dest);
1294         return Jump(m_assembler.jCC(x86Condition(cond)));
1295     }
1296
1297     Jump branchSub32(ResultCondition cond, Address src, RegisterID dest)
1298     {
1299         sub32(src, dest);
1300         return Jump(m_assembler.jCC(x86Condition(cond)));
1301     }
1302
1303     Jump branchSub32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
1304     {
1305         // B := A - B is invalid.
1306         ASSERT(src1 == dest || src2 != dest);
1307
1308         move(src1, dest);
1309         return branchSub32(cond, src2, dest);
1310     }
1311
1312     Jump branchSub32(ResultCondition cond, RegisterID src1, TrustedImm32 src2, RegisterID dest)
1313     {
1314         move(src1, dest);
1315         return branchSub32(cond, src2, dest);
1316     }
1317
1318     Jump branchNeg32(ResultCondition cond, RegisterID srcDest)
1319     {
1320         neg32(srcDest);
1321         return Jump(m_assembler.jCC(x86Condition(cond)));
1322     }
1323
1324     Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
1325     {
1326         or32(src, dest);
1327         return Jump(m_assembler.jCC(x86Condition(cond)));
1328     }
1329
1330
1331     // Miscellaneous operations:
1332
1333     void breakpoint()
1334     {
1335         m_assembler.int3();
1336     }
1337
1338     Call nearCall()
1339     {
1340         return Call(m_assembler.call(), Call::LinkableNear);
1341     }
1342
1343     Call call(RegisterID target)
1344     {
1345         return Call(m_assembler.call(target), Call::None);
1346     }
1347
1348     void call(Address address)
1349     {
1350         m_assembler.call_m(address.offset, address.base);
1351     }
1352
1353     void ret()
1354     {
1355         m_assembler.ret();
1356     }
1357
1358     void compare8(RelationalCondition cond, Address left, TrustedImm32 right, RegisterID dest)
1359     {
1360         m_assembler.cmpb_im(right.m_value, left.offset, left.base);
1361         set32(x86Condition(cond), dest);
1362     }
1363     
1364     void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
1365     {
1366         m_assembler.cmpl_rr(right, left);
1367         set32(x86Condition(cond), dest);
1368     }
1369
1370     void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
1371     {
1372         if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
1373             m_assembler.testl_rr(left, left);
1374         else
1375             m_assembler.cmpl_ir(right.m_value, left);
1376         set32(x86Condition(cond), dest);
1377     }
1378
1379     // FIXME:
1380     // The mask should be optional... perhaps the argument order should be
1381     // dest-src, operations always have a dest? ... possibly not true, considering
1382     // asm ops like test, or pseudo ops like pop().
1383
1384     void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1385     {
1386         if (mask.m_value == -1)
1387             m_assembler.cmpb_im(0, address.offset, address.base);
1388         else
1389             m_assembler.testb_im(mask.m_value, address.offset, address.base);
1390         set32(x86Condition(cond), dest);
1391     }
1392
1393     void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1394     {
1395         if (mask.m_value == -1)
1396             m_assembler.cmpl_im(0, address.offset, address.base);
1397         else
1398             m_assembler.testl_i32m(mask.m_value, address.offset, address.base);
1399         set32(x86Condition(cond), dest);
1400     }
1401
1402     // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc.
1403     static RelationalCondition invert(RelationalCondition cond)
1404     {
1405         return static_cast<RelationalCondition>(cond ^ 1);
1406     }
1407
1408     void nop()
1409     {
1410         m_assembler.nop();
1411     }
1412
1413     static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
1414     {
1415         X86Assembler::replaceWithJump(instructionStart.executableAddress(), destination.executableAddress());
1416     }
1417     
1418     static ptrdiff_t maxJumpReplacementSize()
1419     {
1420         return X86Assembler::maxJumpReplacementSize();
1421     }
1422
1423 protected:
1424     X86Assembler::Condition x86Condition(RelationalCondition cond)
1425     {
1426         return static_cast<X86Assembler::Condition>(cond);
1427     }
1428
1429     X86Assembler::Condition x86Condition(ResultCondition cond)
1430     {
1431         return static_cast<X86Assembler::Condition>(cond);
1432     }
1433
1434     void set32(X86Assembler::Condition cond, RegisterID dest)
1435     {
1436 #if CPU(X86)
1437         // On 32-bit x86 we can only set the first 4 registers;
1438         // esp..edi are mapped to the 'h' registers!
1439         if (dest >= 4) {
1440             m_assembler.xchgl_rr(dest, X86Registers::eax);
1441             m_assembler.setCC_r(cond, X86Registers::eax);
1442             m_assembler.movzbl_rr(X86Registers::eax, X86Registers::eax);
1443             m_assembler.xchgl_rr(dest, X86Registers::eax);
1444             return;
1445         }
1446 #endif
1447         m_assembler.setCC_r(cond, dest);
1448         m_assembler.movzbl_rr(dest, dest);
1449     }
1450
1451 private:
1452     // Only MacroAssemblerX86 should be using the following method; SSE2 is always available on
1453     // x86_64, and clients & subclasses of MacroAssembler should be using 'supportsFloatingPoint()'.
1454     friend class MacroAssemblerX86;
1455
1456 #if CPU(X86)
1457 #if OS(MAC_OS_X)
1458
1459     // All X86 Macs are guaranteed to support at least SSE2,
1460     static bool isSSE2Present()
1461     {
1462         return true;
1463     }
1464
1465 #else // OS(MAC_OS_X)
1466
1467     enum SSE2CheckState {
1468         NotCheckedSSE2,
1469         HasSSE2,
1470         NoSSE2
1471     };
1472
1473     static bool isSSE2Present()
1474     {
1475         if (s_sse2CheckState == NotCheckedSSE2) {
1476             // Default the flags value to zero; if the compiler is
1477             // not MSVC or GCC we will read this as SSE2 not present.
1478             int flags = 0;
1479 #if COMPILER(MSVC)
1480             _asm {
1481                 mov eax, 1 // cpuid function 1 gives us the standard feature set
1482                 cpuid;
1483                 mov flags, edx;
1484             }
1485 #elif COMPILER(GCC)
1486             asm (
1487                  "movl $0x1, %%eax;"
1488                  "pushl %%ebx;"
1489                  "cpuid;"
1490                  "popl %%ebx;"
1491                  "movl %%edx, %0;"
1492                  : "=g" (flags)
1493                  :
1494                  : "%eax", "%ecx", "%edx"
1495                  );
1496 #endif
1497             static const int SSE2FeatureBit = 1 << 26;
1498             s_sse2CheckState = (flags & SSE2FeatureBit) ? HasSSE2 : NoSSE2;
1499         }
1500         // Only check once.
1501         ASSERT(s_sse2CheckState != NotCheckedSSE2);
1502
1503         return s_sse2CheckState == HasSSE2;
1504     }
1505     
1506     static SSE2CheckState s_sse2CheckState;
1507
1508 #endif // OS(MAC_OS_X)
1509 #elif !defined(NDEBUG) // CPU(X86)
1510
1511     // On x86-64 we should never be checking for SSE2 in a non-debug build,
1512     // but non debug add this method to keep the asserts above happy.
1513     static bool isSSE2Present()
1514     {
1515         return true;
1516     }
1517
1518 #endif
1519 };
1520
1521 } // namespace JSC
1522
1523 #endif // ENABLE(ASSEMBLER)
1524
1525 #endif // MacroAssemblerX86Common_h