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
34namespace JSC {
35
36class MacroAssemblerX86Common : public AbstractMacroAssembler<X86Assembler> {
37    static const int DoubleConditionBitInvert = 0x10;
38    static const int DoubleConditionBitSpecial = 0x20;
39    static const int DoubleConditionBits = DoubleConditionBitInvert | DoubleConditionBitSpecial;
40
41public:
42    typedef X86Assembler::FPRegisterID FPRegisterID;
43
44    enum Condition {
45        Equal = X86Assembler::ConditionE,
46        NotEqual = X86Assembler::ConditionNE,
47        Above = X86Assembler::ConditionA,
48        AboveOrEqual = X86Assembler::ConditionAE,
49        Below = X86Assembler::ConditionB,
50        BelowOrEqual = X86Assembler::ConditionBE,
51        GreaterThan = X86Assembler::ConditionG,
52        GreaterThanOrEqual = X86Assembler::ConditionGE,
53        LessThan = X86Assembler::ConditionL,
54        LessThanOrEqual = X86Assembler::ConditionLE,
55        Overflow = X86Assembler::ConditionO,
56        Signed = X86Assembler::ConditionS,
57        Zero = X86Assembler::ConditionE,
58        NonZero = X86Assembler::ConditionNE
59    };
60
61    enum DoubleCondition {
62        // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
63        DoubleEqual = X86Assembler::ConditionE | DoubleConditionBitSpecial,
64        DoubleNotEqual = X86Assembler::ConditionNE,
65        DoubleGreaterThan = X86Assembler::ConditionA,
66        DoubleGreaterThanOrEqual = X86Assembler::ConditionAE,
67        DoubleLessThan = X86Assembler::ConditionA | DoubleConditionBitInvert,
68        DoubleLessThanOrEqual = X86Assembler::ConditionAE | DoubleConditionBitInvert,
69        // If either operand is NaN, these conditions always evaluate to true.
70        DoubleEqualOrUnordered = X86Assembler::ConditionE,
71        DoubleNotEqualOrUnordered = X86Assembler::ConditionNE | DoubleConditionBitSpecial,
72        DoubleGreaterThanOrUnordered = X86Assembler::ConditionB | DoubleConditionBitInvert,
73        DoubleGreaterThanOrEqualOrUnordered = X86Assembler::ConditionBE | DoubleConditionBitInvert,
74        DoubleLessThanOrUnordered = X86Assembler::ConditionB,
75        DoubleLessThanOrEqualOrUnordered = X86Assembler::ConditionBE,
76    };
77    COMPILE_ASSERT(
78        !((X86Assembler::ConditionE | X86Assembler::ConditionNE | X86Assembler::ConditionA | X86Assembler::ConditionAE | X86Assembler::ConditionB | X86Assembler::ConditionBE) & DoubleConditionBits),
79        DoubleConditionBits_should_not_interfere_with_X86Assembler_Condition_codes);
80
81    static const RegisterID stackPointerRegister = X86Registers::esp;
82
83    // Integer arithmetic operations:
84    //
85    // Operations are typically two operand - operation(source, srcDst)
86    // For many operations the source may be an TrustedImm32, the srcDst operand
87    // may often be a memory location (explictly described using an Address
88    // object).
89
90    void add32(RegisterID src, RegisterID dest)
91    {
92        m_assembler.addl_rr(src, dest);
93    }
94
95    void add32(TrustedImm32 imm, Address address)
96    {
97        m_assembler.addl_im(imm.m_value, address.offset, address.base);
98    }
99
100    void add32(TrustedImm32 imm, RegisterID dest)
101    {
102        m_assembler.addl_ir(imm.m_value, dest);
103    }
104
105    void add32(Address src, RegisterID dest)
106    {
107        m_assembler.addl_mr(src.offset, src.base, dest);
108    }
109
110    void add32(RegisterID src, Address dest)
111    {
112        m_assembler.addl_rm(src, dest.offset, dest.base);
113    }
114
115    void and32(RegisterID src, RegisterID dest)
116    {
117        m_assembler.andl_rr(src, dest);
118    }
119
120    void and32(TrustedImm32 imm, RegisterID dest)
121    {
122        m_assembler.andl_ir(imm.m_value, dest);
123    }
124
125    void and32(RegisterID src, Address dest)
126    {
127        m_assembler.andl_rm(src, dest.offset, dest.base);
128    }
129
130    void and32(Address src, RegisterID dest)
131    {
132        m_assembler.andl_mr(src.offset, src.base, dest);
133    }
134
135    void and32(TrustedImm32 imm, Address address)
136    {
137        m_assembler.andl_im(imm.m_value, address.offset, address.base);
138    }
139
140    void and32(RegisterID op1, RegisterID op2, RegisterID dest)
141    {
142        if (op1 == op2)
143            zeroExtend32ToPtr(op1, dest);
144        else if (op1 == dest)
145            and32(op2, dest);
146        else {
147            move(op2, dest);
148            and32(op1, dest);
149        }
150    }
151
152    void and32(TrustedImm32 imm, RegisterID src, RegisterID dest)
153    {
154        move(src, dest);
155        and32(imm, dest);
156    }
157
158    void lshift32(RegisterID shift_amount, RegisterID dest)
159    {
160        ASSERT(shift_amount != dest);
161
162        if (shift_amount == X86Registers::ecx)
163            m_assembler.shll_CLr(dest);
164        else {
165            // On x86 we can only shift by ecx; if asked to shift by another register we'll
166            // need rejig the shift amount into ecx first, and restore the registers afterwards.
167            // If we dest is ecx, then shift the swapped register!
168            swap(shift_amount, X86Registers::ecx);
169            m_assembler.shll_CLr(dest == X86Registers::ecx ? shift_amount : dest);
170            swap(shift_amount, X86Registers::ecx);
171        }
172    }
173
174    void lshift32(RegisterID src, RegisterID shift_amount, RegisterID dest)
175    {
176        ASSERT(shift_amount != dest);
177
178        if (src != dest)
179            move(src, dest);
180        lshift32(shift_amount, dest);
181    }
182
183    void lshift32(TrustedImm32 imm, RegisterID dest)
184    {
185        m_assembler.shll_i8r(imm.m_value, dest);
186    }
187
188    void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
189    {
190        if (src != dest)
191            move(src, dest);
192        lshift32(imm, dest);
193    }
194
195    void mul32(RegisterID src, RegisterID dest)
196    {
197        m_assembler.imull_rr(src, dest);
198    }
199
200    void mul32(Address src, RegisterID dest)
201    {
202        m_assembler.imull_mr(src.offset, src.base, dest);
203    }
204
205    void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
206    {
207        m_assembler.imull_i32r(src, imm.m_value, dest);
208    }
209
210    void neg32(RegisterID srcDest)
211    {
212        m_assembler.negl_r(srcDest);
213    }
214
215    void neg32(Address srcDest)
216    {
217        m_assembler.negl_m(srcDest.offset, srcDest.base);
218    }
219
220    void not32(RegisterID srcDest)
221    {
222        m_assembler.notl_r(srcDest);
223    }
224
225    void not32(Address srcDest)
226    {
227        m_assembler.notl_m(srcDest.offset, srcDest.base);
228    }
229
230    void or32(RegisterID src, RegisterID dest)
231    {
232        m_assembler.orl_rr(src, dest);
233    }
234
235    void or32(TrustedImm32 imm, RegisterID dest)
236    {
237        m_assembler.orl_ir(imm.m_value, dest);
238    }
239
240    void or32(RegisterID src, Address dest)
241    {
242        m_assembler.orl_rm(src, dest.offset, dest.base);
243    }
244
245    void or32(Address src, RegisterID dest)
246    {
247        m_assembler.orl_mr(src.offset, src.base, dest);
248    }
249
250    void or32(TrustedImm32 imm, Address address)
251    {
252        m_assembler.orl_im(imm.m_value, address.offset, address.base);
253    }
254
255    void or32(RegisterID op1, RegisterID op2, RegisterID dest)
256    {
257        if (op1 == op2)
258            zeroExtend32ToPtr(op1, dest);
259        else if (op1 == dest)
260            or32(op2, dest);
261        else {
262            move(op2, dest);
263            or32(op1, dest);
264        }
265    }
266
267    void or32(TrustedImm32 imm, RegisterID src, RegisterID dest)
268    {
269        move(src, dest);
270        or32(imm, dest);
271    }
272
273    void rshift32(RegisterID shift_amount, RegisterID dest)
274    {
275        ASSERT(shift_amount != dest);
276
277        if (shift_amount == X86Registers::ecx)
278            m_assembler.sarl_CLr(dest);
279        else {
280            // On x86 we can only shift by ecx; if asked to shift by another register we'll
281            // need rejig the shift amount into ecx first, and restore the registers afterwards.
282            // If we dest is ecx, then shift the swapped register!
283            swap(shift_amount, X86Registers::ecx);
284            m_assembler.sarl_CLr(dest == X86Registers::ecx ? shift_amount : dest);
285            swap(shift_amount, X86Registers::ecx);
286        }
287    }
288
289    void rshift32(RegisterID src, RegisterID shift_amount, RegisterID dest)
290    {
291        ASSERT(shift_amount != dest);
292
293        if (src != dest)
294            move(src, dest);
295        rshift32(shift_amount, dest);
296    }
297
298    void rshift32(TrustedImm32 imm, RegisterID dest)
299    {
300        m_assembler.sarl_i8r(imm.m_value, dest);
301    }
302
303    void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
304    {
305        if (src != dest)
306            move(src, dest);
307        rshift32(imm, dest);
308    }
309
310    void urshift32(RegisterID shift_amount, RegisterID dest)
311    {
312        ASSERT(shift_amount != dest);
313
314        if (shift_amount == X86Registers::ecx)
315            m_assembler.shrl_CLr(dest);
316        else {
317            // On x86 we can only shift by ecx; if asked to shift by another register we'll
318            // need rejig the shift amount into ecx first, and restore the registers afterwards.
319            // If we dest is ecx, then shift the swapped register!
320            swap(shift_amount, X86Registers::ecx);
321            m_assembler.shrl_CLr(dest == X86Registers::ecx ? shift_amount : dest);
322            swap(shift_amount, X86Registers::ecx);
323        }
324    }
325
326    void urshift32(RegisterID src, RegisterID shift_amount, RegisterID dest)
327    {
328        ASSERT(shift_amount != dest);
329
330        if (src != dest)
331            move(src, dest);
332        urshift32(shift_amount, dest);
333    }
334
335    void urshift32(TrustedImm32 imm, RegisterID dest)
336    {
337        m_assembler.shrl_i8r(imm.m_value, dest);
338    }
339
340    void urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
341    {
342        if (src != dest)
343            move(src, dest);
344        urshift32(imm, dest);
345    }
346
347    void sub32(RegisterID src, RegisterID dest)
348    {
349        m_assembler.subl_rr(src, dest);
350    }
351
352    void sub32(TrustedImm32 imm, RegisterID dest)
353    {
354        m_assembler.subl_ir(imm.m_value, dest);
355    }
356
357    void sub32(TrustedImm32 imm, Address address)
358    {
359        m_assembler.subl_im(imm.m_value, address.offset, address.base);
360    }
361
362    void sub32(Address src, RegisterID dest)
363    {
364        m_assembler.subl_mr(src.offset, src.base, dest);
365    }
366
367    void sub32(RegisterID src, Address dest)
368    {
369        m_assembler.subl_rm(src, dest.offset, dest.base);
370    }
371
372
373    void xor32(RegisterID src, RegisterID dest)
374    {
375        m_assembler.xorl_rr(src, dest);
376    }
377
378    void xor32(TrustedImm32 imm, Address dest)
379    {
380        m_assembler.xorl_im(imm.m_value, dest.offset, dest.base);
381    }
382
383    void xor32(TrustedImm32 imm, RegisterID dest)
384    {
385        m_assembler.xorl_ir(imm.m_value, dest);
386    }
387
388    void xor32(RegisterID src, Address dest)
389    {
390        m_assembler.xorl_rm(src, dest.offset, dest.base);
391    }
392
393    void xor32(Address src, RegisterID dest)
394    {
395        m_assembler.xorl_mr(src.offset, src.base, dest);
396    }
397
398    void xor32(RegisterID op1, RegisterID op2, RegisterID dest)
399    {
400        if (op1 == op2)
401            move(TrustedImm32(0), dest);
402        else if (op1 == dest)
403            xor32(op2, dest);
404        else {
405            move(op2, dest);
406            xor32(op1, dest);
407        }
408    }
409
410    void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest)
411    {
412        move(src, dest);
413        xor32(imm, dest);
414    }
415
416    void sqrtDouble(FPRegisterID src, FPRegisterID dst)
417    {
418        m_assembler.sqrtsd_rr(src, dst);
419    }
420
421    // Memory access operations:
422    //
423    // Loads are of the form load(address, destination) and stores of the form
424    // store(source, address).  The source for a store may be an TrustedImm32.  Address
425    // operand objects to loads and store will be implicitly constructed if a
426    // register is passed.
427
428    void load32(ImplicitAddress address, RegisterID dest)
429    {
430        m_assembler.movl_mr(address.offset, address.base, dest);
431    }
432
433    void load32(BaseIndex address, RegisterID dest)
434    {
435        m_assembler.movl_mr(address.offset, address.base, address.index, address.scale, dest);
436    }
437
438    void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
439    {
440        load32(address, dest);
441    }
442
443    DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
444    {
445        m_assembler.movl_mr_disp32(address.offset, address.base, dest);
446        return DataLabel32(this);
447    }
448
449    void load16(BaseIndex address, RegisterID dest)
450    {
451        m_assembler.movzwl_mr(address.offset, address.base, address.index, address.scale, dest);
452    }
453
454    void load16(Address address, RegisterID dest)
455    {
456        m_assembler.movzwl_mr(address.offset, address.base, dest);
457    }
458
459    DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
460    {
461        m_assembler.movl_rm_disp32(src, address.offset, address.base);
462        return DataLabel32(this);
463    }
464
465    void store32(RegisterID src, ImplicitAddress address)
466    {
467        m_assembler.movl_rm(src, address.offset, address.base);
468    }
469
470    void store32(RegisterID src, BaseIndex address)
471    {
472        m_assembler.movl_rm(src, address.offset, address.base, address.index, address.scale);
473    }
474
475    void store32(TrustedImm32 imm, ImplicitAddress address)
476    {
477        m_assembler.movl_i32m(imm.m_value, address.offset, address.base);
478    }
479
480
481    // Floating-point operation:
482    //
483    // Presently only supports SSE, not x87 floating point.
484
485    void moveDouble(FPRegisterID src, FPRegisterID dest)
486    {
487        ASSERT(isSSE2Present());
488        if (src != dest)
489            m_assembler.movsd_rr(src, dest);
490    }
491
492    void loadDouble(ImplicitAddress address, FPRegisterID dest)
493    {
494        ASSERT(isSSE2Present());
495        m_assembler.movsd_mr(address.offset, address.base, dest);
496    }
497
498    void storeDouble(FPRegisterID src, ImplicitAddress address)
499    {
500        ASSERT(isSSE2Present());
501        m_assembler.movsd_rm(src, address.offset, address.base);
502    }
503
504    void addDouble(FPRegisterID src, FPRegisterID dest)
505    {
506        ASSERT(isSSE2Present());
507        m_assembler.addsd_rr(src, dest);
508    }
509
510    void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
511    {
512        ASSERT(isSSE2Present());
513        if (op1 == dest)
514            addDouble(op2, dest);
515        else {
516            moveDouble(op2, dest);
517            addDouble(op1, dest);
518        }
519    }
520
521    void addDouble(Address src, FPRegisterID dest)
522    {
523        ASSERT(isSSE2Present());
524        m_assembler.addsd_mr(src.offset, src.base, dest);
525    }
526
527    void divDouble(FPRegisterID src, FPRegisterID dest)
528    {
529        ASSERT(isSSE2Present());
530        m_assembler.divsd_rr(src, dest);
531    }
532
533    void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
534    {
535        // B := A / B is invalid.
536        ASSERT(op1 == dest || op2 != dest);
537
538        moveDouble(op1, dest);
539        divDouble(op2, dest);
540    }
541
542    void divDouble(Address src, FPRegisterID dest)
543    {
544        ASSERT(isSSE2Present());
545        m_assembler.divsd_mr(src.offset, src.base, dest);
546    }
547
548    void subDouble(FPRegisterID src, FPRegisterID dest)
549    {
550        ASSERT(isSSE2Present());
551        m_assembler.subsd_rr(src, dest);
552    }
553
554    void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
555    {
556        // B := A - B is invalid.
557        ASSERT(op1 == dest || op2 != dest);
558
559        moveDouble(op1, dest);
560        subDouble(op2, dest);
561    }
562
563    void subDouble(Address src, FPRegisterID dest)
564    {
565        ASSERT(isSSE2Present());
566        m_assembler.subsd_mr(src.offset, src.base, dest);
567    }
568
569    void mulDouble(FPRegisterID src, FPRegisterID dest)
570    {
571        ASSERT(isSSE2Present());
572        m_assembler.mulsd_rr(src, dest);
573    }
574
575    void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
576    {
577        ASSERT(isSSE2Present());
578        if (op1 == dest)
579            mulDouble(op2, dest);
580        else {
581            moveDouble(op2, dest);
582            mulDouble(op1, dest);
583        }
584    }
585
586    void mulDouble(Address src, FPRegisterID dest)
587    {
588        ASSERT(isSSE2Present());
589        m_assembler.mulsd_mr(src.offset, src.base, dest);
590    }
591
592    void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
593    {
594        ASSERT(isSSE2Present());
595        m_assembler.cvtsi2sd_rr(src, dest);
596    }
597
598    void convertInt32ToDouble(Address src, FPRegisterID dest)
599    {
600        ASSERT(isSSE2Present());
601        m_assembler.cvtsi2sd_mr(src.offset, src.base, dest);
602    }
603
604    Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
605    {
606        ASSERT(isSSE2Present());
607
608        if (cond & DoubleConditionBitInvert)
609            m_assembler.ucomisd_rr(left, right);
610        else
611            m_assembler.ucomisd_rr(right, left);
612
613        if (cond == DoubleEqual) {
614            Jump isUnordered(m_assembler.jp());
615            Jump result = Jump(m_assembler.je());
616            isUnordered.link(this);
617            return result;
618        } else if (cond == DoubleNotEqualOrUnordered) {
619            Jump isUnordered(m_assembler.jp());
620            Jump isEqual(m_assembler.je());
621            isUnordered.link(this);
622            Jump result = jump();
623            isEqual.link(this);
624            return result;
625        }
626
627        ASSERT(!(cond & DoubleConditionBitSpecial));
628        return Jump(m_assembler.jCC(static_cast<X86Assembler::Condition>(cond & ~DoubleConditionBits)));
629    }
630
631    // Truncates 'src' to an integer, and places the resulting 'dest'.
632    // If the result is not representable as a 32 bit value, branch.
633    // May also branch for some values that are representable in 32 bits
634    // (specifically, in this case, INT_MIN).
635    enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful };
636    Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
637    {
638        ASSERT(isSSE2Present());
639        m_assembler.cvttsd2si_rr(src, dest);
640        return branch32(branchType ? NotEqual : Equal, dest, TrustedImm32(0x80000000));
641    }
642
643    // Convert 'src' to an integer, and places the resulting 'dest'.
644    // If the result is not representable as a 32 bit value, branch.
645    // May also branch for some values that are representable in 32 bits
646    // (specifically, in this case, 0).
647    void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp)
648    {
649        ASSERT(isSSE2Present());
650        m_assembler.cvttsd2si_rr(src, dest);
651
652        // If the result is zero, it might have been -0.0, and the double comparison won't catch this!
653        failureCases.append(branchTest32(Zero, dest));
654
655        // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
656        convertInt32ToDouble(dest, fpTemp);
657        m_assembler.ucomisd_rr(fpTemp, src);
658        failureCases.append(m_assembler.jp());
659        failureCases.append(m_assembler.jne());
660    }
661
662    Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch)
663    {
664        ASSERT(isSSE2Present());
665        m_assembler.xorpd_rr(scratch, scratch);
666        return branchDouble(DoubleNotEqual, reg, scratch);
667    }
668
669    Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID scratch)
670    {
671        ASSERT(isSSE2Present());
672        m_assembler.xorpd_rr(scratch, scratch);
673        return branchDouble(DoubleEqualOrUnordered, reg, scratch);
674    }
675
676    // Stack manipulation operations:
677    //
678    // The ABI is assumed to provide a stack abstraction to memory,
679    // containing machine word sized units of data.  Push and pop
680    // operations add and remove a single register sized unit of data
681    // to or from the stack.  Peek and poke operations read or write
682    // values on the stack, without moving the current stack position.
683
684    void pop(RegisterID dest)
685    {
686        m_assembler.pop_r(dest);
687    }
688
689    void push(RegisterID src)
690    {
691        m_assembler.push_r(src);
692    }
693
694    void push(Address address)
695    {
696        m_assembler.push_m(address.offset, address.base);
697    }
698
699    void push(TrustedImm32 imm)
700    {
701        m_assembler.push_i32(imm.m_value);
702    }
703
704
705    // Register move operations:
706    //
707    // Move values in registers.
708
709    void move(TrustedImm32 imm, RegisterID dest)
710    {
711        // Note: on 64-bit the TrustedImm32 value is zero extended into the register, it
712        // may be useful to have a separate version that sign extends the value?
713        if (!imm.m_value)
714            m_assembler.xorl_rr(dest, dest);
715        else
716            m_assembler.movl_i32r(imm.m_value, dest);
717    }
718
719#if CPU(X86_64)
720    void move(RegisterID src, RegisterID dest)
721    {
722        // Note: on 64-bit this is is a full register move; perhaps it would be
723        // useful to have separate move32 & movePtr, with move32 zero extending?
724        if (src != dest)
725            m_assembler.movq_rr(src, dest);
726    }
727
728    void move(TrustedImmPtr imm, RegisterID dest)
729    {
730        m_assembler.movq_i64r(imm.asIntptr(), dest);
731    }
732
733    void swap(RegisterID reg1, RegisterID reg2)
734    {
735        if (reg1 != reg2)
736            m_assembler.xchgq_rr(reg1, reg2);
737    }
738
739    void signExtend32ToPtr(RegisterID src, RegisterID dest)
740    {
741        m_assembler.movsxd_rr(src, dest);
742    }
743
744    void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
745    {
746        m_assembler.movl_rr(src, dest);
747    }
748#else
749    void move(RegisterID src, RegisterID dest)
750    {
751        if (src != dest)
752            m_assembler.movl_rr(src, dest);
753    }
754
755    void move(TrustedImmPtr imm, RegisterID dest)
756    {
757        m_assembler.movl_i32r(imm.asIntptr(), dest);
758    }
759
760    void swap(RegisterID reg1, RegisterID reg2)
761    {
762        if (reg1 != reg2)
763            m_assembler.xchgl_rr(reg1, reg2);
764    }
765
766    void signExtend32ToPtr(RegisterID src, RegisterID dest)
767    {
768        move(src, dest);
769    }
770
771    void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
772    {
773        move(src, dest);
774    }
775#endif
776
777
778    // Forwards / external control flow operations:
779    //
780    // This set of jump and conditional branch operations return a Jump
781    // object which may linked at a later point, allow forwards jump,
782    // or jumps that will require external linkage (after the code has been
783    // relocated).
784    //
785    // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
786    // respecitvely, for unsigned comparisons the names b, a, be, and ae are
787    // used (representing the names 'below' and 'above').
788    //
789    // Operands to the comparision are provided in the expected order, e.g.
790    // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
791    // treated as a signed 32bit value, is less than or equal to 5.
792    //
793    // jz and jnz test whether the first operand is equal to zero, and take
794    // an optional second operand of a mask under which to perform the test.
795
796public:
797    Jump branch8(Condition cond, Address left, TrustedImm32 right)
798    {
799        m_assembler.cmpb_im(right.m_value, left.offset, left.base);
800        return Jump(m_assembler.jCC(x86Condition(cond)));
801    }
802
803    Jump branch32(Condition cond, RegisterID left, RegisterID right)
804    {
805        m_assembler.cmpl_rr(right, left);
806        return Jump(m_assembler.jCC(x86Condition(cond)));
807    }
808
809    Jump branch32(Condition cond, RegisterID left, TrustedImm32 right)
810    {
811        if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
812            m_assembler.testl_rr(left, left);
813        else
814            m_assembler.cmpl_ir(right.m_value, left);
815        return Jump(m_assembler.jCC(x86Condition(cond)));
816    }
817
818    Jump branch32(Condition cond, RegisterID left, Address right)
819    {
820        m_assembler.cmpl_mr(right.offset, right.base, left);
821        return Jump(m_assembler.jCC(x86Condition(cond)));
822    }
823
824    Jump branch32(Condition cond, Address left, RegisterID right)
825    {
826        m_assembler.cmpl_rm(right, left.offset, left.base);
827        return Jump(m_assembler.jCC(x86Condition(cond)));
828    }
829
830    Jump branch32(Condition cond, Address left, TrustedImm32 right)
831    {
832        m_assembler.cmpl_im(right.m_value, left.offset, left.base);
833        return Jump(m_assembler.jCC(x86Condition(cond)));
834    }
835
836    Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
837    {
838        m_assembler.cmpl_im(right.m_value, left.offset, left.base, left.index, left.scale);
839        return Jump(m_assembler.jCC(x86Condition(cond)));
840    }
841
842    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
843    {
844        return branch32(cond, left, right);
845    }
846
847    Jump branch16(Condition cond, BaseIndex left, RegisterID right)
848    {
849        m_assembler.cmpw_rm(right, left.offset, left.base, left.index, left.scale);
850        return Jump(m_assembler.jCC(x86Condition(cond)));
851    }
852
853    Jump branch16(Condition cond, BaseIndex left, TrustedImm32 right)
854    {
855        ASSERT(!(right.m_value & 0xFFFF0000));
856
857        m_assembler.cmpw_im(right.m_value, left.offset, left.base, left.index, left.scale);
858        return Jump(m_assembler.jCC(x86Condition(cond)));
859    }
860
861    Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask)
862    {
863        ASSERT((cond == Zero) || (cond == NonZero) || (cond == Signed));
864        m_assembler.testl_rr(reg, mask);
865        return Jump(m_assembler.jCC(x86Condition(cond)));
866    }
867
868    Jump branchTest32(Condition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
869    {
870        ASSERT((cond == Zero) || (cond == NonZero) || (cond == Signed));
871        // if we are only interested in the low seven bits, this can be tested with a testb
872        if (mask.m_value == -1)
873            m_assembler.testl_rr(reg, reg);
874        else if ((mask.m_value & ~0x7f) == 0)
875            m_assembler.testb_i8r(mask.m_value, reg);
876        else
877            m_assembler.testl_i32r(mask.m_value, reg);
878        return Jump(m_assembler.jCC(x86Condition(cond)));
879    }
880
881    Jump branchTest32(Condition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
882    {
883        ASSERT((cond == Zero) || (cond == NonZero) || (cond == Signed));
884        if (mask.m_value == -1)
885            m_assembler.cmpl_im(0, address.offset, address.base);
886        else
887            m_assembler.testl_i32m(mask.m_value, address.offset, address.base);
888        return Jump(m_assembler.jCC(x86Condition(cond)));
889    }
890
891    Jump branchTest32(Condition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
892    {
893        ASSERT((cond == Zero) || (cond == NonZero) || (cond == Signed));
894        if (mask.m_value == -1)
895            m_assembler.cmpl_im(0, address.offset, address.base, address.index, address.scale);
896        else
897            m_assembler.testl_i32m(mask.m_value, address.offset, address.base, address.index, address.scale);
898        return Jump(m_assembler.jCC(x86Condition(cond)));
899    }
900
901    Jump branchTest8(Condition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
902    {
903        // Byte in TrustedImm32 is not well defined, so be a little permisive here, but don't accept nonsense values.
904        ASSERT(mask.m_value >= -128 && mask.m_value <= 255);
905        ASSERT((cond == Zero) || (cond == NonZero) || (cond == Signed));
906        if (mask.m_value == -1)
907            m_assembler.testb_rr(reg, reg);
908        else
909            m_assembler.testb_i8r(mask.m_value, reg);
910        return Jump(m_assembler.jCC(x86Condition(cond)));
911    }
912
913    Jump branchTest8(Condition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
914    {
915        // Byte in TrustedImm32 is not well defined, so be a little permisive here, but don't accept nonsense values.
916        ASSERT(mask.m_value >= -128 && mask.m_value <= 255);
917        ASSERT((cond == Zero) || (cond == NonZero) || (cond == Signed));
918        if (mask.m_value == -1)
919            m_assembler.cmpb_im(0, address.offset, address.base);
920        else
921            m_assembler.testb_im(mask.m_value, address.offset, address.base);
922        return Jump(m_assembler.jCC(x86Condition(cond)));
923    }
924
925    Jump branchTest8(Condition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
926    {
927        // Byte in TrustedImm32 is not well defined, so be a little permisive here, but don't accept nonsense values.
928        ASSERT(mask.m_value >= -128 && mask.m_value <= 255);
929        ASSERT((cond == Zero) || (cond == NonZero) || (cond == Signed));
930        if (mask.m_value == -1)
931            m_assembler.cmpb_im(0, address.offset, address.base, address.index, address.scale);
932        else
933            m_assembler.testb_im(mask.m_value, address.offset, address.base, address.index, address.scale);
934        return Jump(m_assembler.jCC(x86Condition(cond)));
935    }
936
937    Jump jump()
938    {
939        return Jump(m_assembler.jmp());
940    }
941
942    void jump(RegisterID target)
943    {
944        m_assembler.jmp_r(target);
945    }
946
947    // Address is a memory location containing the address to jump to
948    void jump(Address address)
949    {
950        m_assembler.jmp_m(address.offset, address.base);
951    }
952
953
954    // Arithmetic control flow operations:
955    //
956    // This set of conditional branch operations branch based
957    // on the result of an arithmetic operation.  The operation
958    // is performed as normal, storing the result.
959    //
960    // * jz operations branch if the result is zero.
961    // * jo operations branch if the (signed) arithmetic
962    //   operation caused an overflow to occur.
963
964    Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest)
965    {
966        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
967        add32(src, dest);
968        return Jump(m_assembler.jCC(x86Condition(cond)));
969    }
970
971    Jump branchAdd32(Condition cond, TrustedImm32 imm, RegisterID dest)
972    {
973        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
974        add32(imm, dest);
975        return Jump(m_assembler.jCC(x86Condition(cond)));
976    }
977
978    Jump branchAdd32(Condition cond, TrustedImm32 src, Address dest)
979    {
980        ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
981        add32(src, dest);
982        return Jump(m_assembler.jCC(x86Condition(cond)));
983    }
984
985    Jump branchAdd32(Condition cond, RegisterID src, Address dest)
986    {
987        ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
988        add32(src, dest);
989        return Jump(m_assembler.jCC(x86Condition(cond)));
990    }
991
992    Jump branchAdd32(Condition cond, Address src, RegisterID dest)
993    {
994        ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
995        add32(src, dest);
996        return Jump(m_assembler.jCC(x86Condition(cond)));
997    }
998
999    Jump branchAdd32(Condition cond, RegisterID src1, RegisterID src2, RegisterID dest)
1000    {
1001        if (src1 == dest)
1002            return branchAdd32(cond, src2, dest);
1003        move(src2, dest);
1004        return branchAdd32(cond, src1, dest);
1005    }
1006
1007    Jump branchAdd32(Condition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
1008    {
1009        move(src, dest);
1010        return branchAdd32(cond, imm, dest);
1011    }
1012
1013    Jump branchMul32(Condition cond, RegisterID src, RegisterID dest)
1014    {
1015        ASSERT(cond == Overflow);
1016        mul32(src, dest);
1017        return Jump(m_assembler.jCC(x86Condition(cond)));
1018    }
1019
1020    Jump branchMul32(Condition cond, Address src, RegisterID dest)
1021    {
1022        ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
1023        mul32(src, dest);
1024        return Jump(m_assembler.jCC(x86Condition(cond)));
1025    }
1026
1027    Jump branchMul32(Condition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
1028    {
1029        ASSERT(cond == Overflow);
1030        mul32(imm, src, dest);
1031        return Jump(m_assembler.jCC(x86Condition(cond)));
1032    }
1033
1034    Jump branchMul32(Condition cond, RegisterID src1, RegisterID src2, RegisterID dest)
1035    {
1036        if (src1 == dest)
1037            return branchMul32(cond, src2, dest);
1038        move(src2, dest);
1039        return branchMul32(cond, src1, dest);
1040    }
1041
1042    Jump branchSub32(Condition cond, RegisterID src, RegisterID dest)
1043    {
1044        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1045        sub32(src, dest);
1046        return Jump(m_assembler.jCC(x86Condition(cond)));
1047    }
1048
1049    Jump branchSub32(Condition cond, TrustedImm32 imm, RegisterID dest)
1050    {
1051        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1052        sub32(imm, dest);
1053        return Jump(m_assembler.jCC(x86Condition(cond)));
1054    }
1055
1056    Jump branchSub32(Condition cond, TrustedImm32 imm, Address dest)
1057    {
1058        ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
1059        sub32(imm, dest);
1060        return Jump(m_assembler.jCC(x86Condition(cond)));
1061    }
1062
1063    Jump branchSub32(Condition cond, RegisterID src, Address dest)
1064    {
1065        ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
1066        sub32(src, dest);
1067        return Jump(m_assembler.jCC(x86Condition(cond)));
1068    }
1069
1070    Jump branchSub32(Condition cond, Address src, RegisterID dest)
1071    {
1072        ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
1073        sub32(src, dest);
1074        return Jump(m_assembler.jCC(x86Condition(cond)));
1075    }
1076
1077    Jump branchSub32(Condition cond, RegisterID src1, RegisterID src2, RegisterID dest)
1078    {
1079        // B := A - B is invalid.
1080        ASSERT(src1 == dest || src2 != dest);
1081
1082        move(src1, dest);
1083        return branchSub32(cond, src2, dest);
1084    }
1085
1086    Jump branchSub32(Condition cond, RegisterID src1, TrustedImm32 src2, RegisterID dest)
1087    {
1088        move(src1, dest);
1089        return branchSub32(cond, src2, dest);
1090    }
1091
1092    Jump branchNeg32(Condition cond, RegisterID srcDest)
1093    {
1094        ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
1095        neg32(srcDest);
1096        return Jump(m_assembler.jCC(x86Condition(cond)));
1097    }
1098
1099    Jump branchOr32(Condition cond, RegisterID src, RegisterID dest)
1100    {
1101        ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero));
1102        or32(src, dest);
1103        return Jump(m_assembler.jCC(x86Condition(cond)));
1104    }
1105
1106
1107    // Miscellaneous operations:
1108
1109    void breakpoint()
1110    {
1111        m_assembler.int3();
1112    }
1113
1114    Call nearCall()
1115    {
1116        return Call(m_assembler.call(), Call::LinkableNear);
1117    }
1118
1119    Call call(RegisterID target)
1120    {
1121        return Call(m_assembler.call(target), Call::None);
1122    }
1123
1124    void call(Address address)
1125    {
1126        m_assembler.call_m(address.offset, address.base);
1127    }
1128
1129    void ret()
1130    {
1131        m_assembler.ret();
1132    }
1133
1134    void set8Compare32(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
1135    {
1136        m_assembler.cmpl_rr(right, left);
1137        m_assembler.setCC_r(x86Condition(cond), dest);
1138    }
1139
1140    void set8Compare32(Condition cond, Address left, RegisterID right, RegisterID dest)
1141    {
1142        m_assembler.cmpl_mr(left.offset, left.base, right);
1143        m_assembler.setCC_r(x86Condition(cond), dest);
1144    }
1145
1146    void set8Compare32(Condition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
1147    {
1148        if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
1149            m_assembler.testl_rr(left, left);
1150        else
1151            m_assembler.cmpl_ir(right.m_value, left);
1152        m_assembler.setCC_r(x86Condition(cond), dest);
1153    }
1154
1155    void set32Compare32(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
1156    {
1157        m_assembler.cmpl_rr(right, left);
1158        m_assembler.setCC_r(x86Condition(cond), dest);
1159        m_assembler.movzbl_rr(dest, dest);
1160    }
1161
1162    void set32Compare32(Condition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
1163    {
1164        if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
1165            m_assembler.testl_rr(left, left);
1166        else
1167            m_assembler.cmpl_ir(right.m_value, left);
1168        m_assembler.setCC_r(x86Condition(cond), dest);
1169        m_assembler.movzbl_rr(dest, dest);
1170    }
1171
1172    // FIXME:
1173    // The mask should be optional... paerhaps the argument order should be
1174    // dest-src, operations always have a dest? ... possibly not true, considering
1175    // asm ops like test, or pseudo ops like pop().
1176
1177    void set32Test8(Condition cond, Address address, TrustedImm32 mask, RegisterID dest)
1178    {
1179        if (mask.m_value == -1)
1180            m_assembler.cmpb_im(0, address.offset, address.base);
1181        else
1182            m_assembler.testb_im(mask.m_value, address.offset, address.base);
1183        m_assembler.setCC_r(x86Condition(cond), dest);
1184        m_assembler.movzbl_rr(dest, dest);
1185    }
1186
1187    void set32Test32(Condition cond, Address address, TrustedImm32 mask, RegisterID dest)
1188    {
1189        if (mask.m_value == -1)
1190            m_assembler.cmpl_im(0, address.offset, address.base);
1191        else
1192            m_assembler.testl_i32m(mask.m_value, address.offset, address.base);
1193        m_assembler.setCC_r(x86Condition(cond), dest);
1194        m_assembler.movzbl_rr(dest, dest);
1195    }
1196
1197protected:
1198    X86Assembler::Condition x86Condition(Condition cond)
1199    {
1200        return static_cast<X86Assembler::Condition>(cond);
1201    }
1202
1203private:
1204    // Only MacroAssemblerX86 should be using the following method; SSE2 is always available on
1205    // x86_64, and clients & subclasses of MacroAssembler should be using 'supportsFloatingPoint()'.
1206    friend class MacroAssemblerX86;
1207
1208#if CPU(X86)
1209#if OS(MAC_OS_X)
1210
1211    // All X86 Macs are guaranteed to support at least SSE2,
1212    static bool isSSE2Present()
1213    {
1214        return true;
1215    }
1216
1217#else // OS(MAC_OS_X)
1218
1219    enum SSE2CheckState {
1220        NotCheckedSSE2,
1221        HasSSE2,
1222        NoSSE2
1223    };
1224
1225    static bool isSSE2Present()
1226    {
1227        if (s_sse2CheckState == NotCheckedSSE2) {
1228            // Default the flags value to zero; if the compiler is
1229            // not MSVC or GCC we will read this as SSE2 not present.
1230            int flags = 0;
1231#if COMPILER(MSVC)
1232            _asm {
1233                mov eax, 1 // cpuid function 1 gives us the standard feature set
1234                cpuid;
1235                mov flags, edx;
1236            }
1237#elif COMPILER(GCC)
1238            asm (
1239                 "movl $0x1, %%eax;"
1240                 "pushl %%ebx;"
1241                 "cpuid;"
1242                 "popl %%ebx;"
1243                 "movl %%edx, %0;"
1244                 : "=g" (flags)
1245                 :
1246                 : "%eax", "%ecx", "%edx"
1247                 );
1248#endif
1249            static const int SSE2FeatureBit = 1 << 26;
1250            s_sse2CheckState = (flags & SSE2FeatureBit) ? HasSSE2 : NoSSE2;
1251        }
1252        // Only check once.
1253        ASSERT(s_sse2CheckState != NotCheckedSSE2);
1254
1255        return s_sse2CheckState == HasSSE2;
1256    }
1257
1258    static SSE2CheckState s_sse2CheckState;
1259
1260#endif // OS(MAC_OS_X)
1261#elif !defined(NDEBUG) // CPU(X86)
1262
1263    // On x86-64 we should never be checking for SSE2 in a non-debug build,
1264    // but non debug add this method to keep the asserts above happy.
1265    static bool isSSE2Present()
1266    {
1267        return true;
1268    }
1269
1270#endif
1271};
1272
1273} // namespace JSC
1274
1275#endif // ENABLE(ASSEMBLER)
1276
1277#endif // MacroAssemblerX86Common_h
1278