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