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 1526632 : 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 25760 : static inline bool CanUse8Bit(RegisterID reg) {
103 : return !!((1 << reg) & ~((1 << X86Registers::esp) |
104 : (1 << X86Registers::edi) |
105 : (1 << X86Registers::esi) |
106 25760 : (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 328883 : void add32(RegisterID src, RegisterID dest)
117 : {
118 328883 : m_assembler.addl_rr(src, dest);
119 328883 : }
120 :
121 : void add32(TrustedImm32 imm, Address address)
122 : {
123 : m_assembler.addl_im(imm.m_value, address.offset, address.base);
124 : }
125 :
126 5647032 : void add32(TrustedImm32 imm, RegisterID dest)
127 : {
128 5647032 : m_assembler.addl_ir(imm.m_value, dest);
129 5647032 : }
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 154752 : void and32(Imm32 imm, RegisterID dest)
147 : {
148 154752 : m_assembler.andl_ir(imm.m_value, dest);
149 154752 : }
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 2593 : void lshift32(Imm32 imm, RegisterID dest)
167 : {
168 2593 : m_assembler.shll_i8r(imm.m_value, dest);
169 2593 : }
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 1881 : void mul32(Imm32 imm, RegisterID src, RegisterID dest)
204 : {
205 1881 : m_assembler.imull_i32r(src, imm.m_value, dest);
206 1881 : }
207 :
208 : void idiv(RegisterID reg)
209 : {
210 : m_assembler.cdq();
211 : m_assembler.idivl_r(reg);
212 : }
213 :
214 21265 : void neg32(RegisterID srcDest)
215 : {
216 21265 : m_assembler.negl_r(srcDest);
217 21265 : }
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 55295 : void or32(TrustedImm32 imm, RegisterID dest)
240 : {
241 55295 : m_assembler.orl_ir(imm.m_value, dest);
242 55295 : }
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 3188 : void rshift32(Imm32 imm, RegisterID dest)
282 : {
283 3188 : m_assembler.sarl_i8r(imm.m_value, dest);
284 3188 : }
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 7373 : void urshift32(Imm32 imm, RegisterID dest)
309 : {
310 7373 : m_assembler.shrl_i8r(imm.m_value, dest);
311 7373 : }
312 :
313 4930 : void sub32(RegisterID src, RegisterID dest)
314 : {
315 4930 : m_assembler.subl_rr(src, dest);
316 4930 : }
317 :
318 262959 : void sub32(TrustedImm32 imm, RegisterID dest)
319 : {
320 262959 : m_assembler.subl_ir(imm.m_value, dest);
321 262959 : }
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 2805 : void xor32(RegisterID src, RegisterID dest)
340 : {
341 2805 : m_assembler.xorl_rr(src, dest);
342 2805 : }
343 :
344 : void xor32(TrustedImm32 imm, Address dest)
345 : {
346 : m_assembler.xorl_im(imm.m_value, dest.offset, dest.base);
347 : }
348 :
349 33178 : void xor32(TrustedImm32 imm, RegisterID dest)
350 : {
351 33178 : m_assembler.xorl_ir(imm.m_value, dest);
352 33178 : }
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 188 : void sqrtDouble(FPRegisterID src, FPRegisterID dst)
365 : {
366 188 : m_assembler.sqrtsd_rr(src, dst);
367 188 : }
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 22263999 : void load32(ImplicitAddress address, RegisterID dest)
377 : {
378 22263999 : m_assembler.movl_mr(address.offset, address.base, dest);
379 22263999 : }
380 :
381 56465 : void load32(BaseIndex address, RegisterID dest)
382 : {
383 56465 : m_assembler.movl_mr(address.offset, address.base, address.index, address.scale, dest);
384 56465 : }
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 62978 : void load16(BaseIndex address, RegisterID dest)
448 : {
449 62978 : m_assembler.movzwl_mr(address.offset, address.base, address.index, address.scale, dest);
450 62978 : }
451 :
452 148055 : void load16(Address address, RegisterID dest)
453 : {
454 148055 : m_assembler.movzwl_mr(address.offset, address.base, dest);
455 148055 : }
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 23398600 : void store32(RegisterID src, ImplicitAddress address)
464 : {
465 23398600 : m_assembler.movl_rm(src, address.offset, address.base);
466 23398600 : }
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 8153 : void store32(TrustedImm32 imm, BaseIndex address)
474 : {
475 8153 : m_assembler.movl_i32m(imm.m_value, address.offset, address.base, address.index, address.scale);
476 8153 : }
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 12485476 : void store32(TrustedImm32 imm, ImplicitAddress address)
489 : {
490 12485476 : m_assembler.movl_i32m(imm.m_value, address.offset, address.base);
491 12485476 : }
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 5200 : void moveDouble(FPRegisterID src, FPRegisterID dest)
509 : {
510 5200 : ASSERT(isSSE2Present());
511 5200 : m_assembler.movsd_rr(src, dest);
512 5200 : }
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 52134 : void loadDouble(ImplicitAddress address, FPRegisterID dest)
535 : {
536 52134 : ASSERT(isSSE2Present());
537 52134 : m_assembler.movsd_mr(address.offset, address.base, dest);
538 52134 : }
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 630156 : void storeDouble(FPRegisterID src, ImplicitAddress address)
567 : {
568 630156 : ASSERT(isSSE2Present());
569 630156 : m_assembler.movsd_rm(src, address.offset, address.base);
570 630156 : }
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 529223 : void addDouble(FPRegisterID src, FPRegisterID dest)
591 : {
592 529223 : ASSERT(isSSE2Present());
593 529223 : m_assembler.addsd_rr(src, dest);
594 529223 : }
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 7983 : void divDouble(FPRegisterID src, FPRegisterID dest)
603 : {
604 7983 : ASSERT(isSSE2Present());
605 7983 : m_assembler.divsd_rr(src, dest);
606 7983 : }
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 34525 : void subDouble(FPRegisterID src, FPRegisterID dest)
615 : {
616 34525 : ASSERT(isSSE2Present());
617 34525 : m_assembler.subsd_rr(src, dest);
618 34525 : }
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 4933 : void mulDouble(FPRegisterID src, FPRegisterID dest)
627 : {
628 4933 : ASSERT(isSSE2Present());
629 4933 : m_assembler.mulsd_rr(src, dest);
630 4933 : }
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 3250 : void xorDouble(FPRegisterID src, FPRegisterID dest)
639 : {
640 3250 : ASSERT(isSSE2Present());
641 3250 : m_assembler.xorpd_rr(src, dest);
642 3250 : }
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 717462 : void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
660 : {
661 717462 : ASSERT(isSSE2Present());
662 717462 : m_assembler.cvtsi2sd_rr(src, dest);
663 717462 : }
664 :
665 24669 : void convertInt32ToDouble(Address src, FPRegisterID dest)
666 : {
667 24669 : ASSERT(isSSE2Present());
668 24669 : m_assembler.cvtsi2sd_mr(src.offset, src.base, dest);
669 24669 : }
670 :
671 56199 : Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
672 : {
673 56199 : ASSERT(isSSE2Present());
674 :
675 56199 : if (cond & DoubleConditionBitInvert)
676 43297 : m_assembler.ucomisd_rr(left, right);
677 : else
678 12902 : m_assembler.ucomisd_rr(right, left);
679 :
680 56199 : 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 55674 : } 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 55674 : ASSERT(!(cond & DoubleConditionBitSpecial));
695 55674 : 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 6320 : Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest)
703 : {
704 6320 : ASSERT(isSSE2Present());
705 6320 : m_assembler.cvttsd2si_rr(src, dest);
706 6320 : 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 7137 : void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp)
714 : {
715 7137 : ASSERT(isSSE2Present());
716 7137 : ASSERT(src != fpTemp);
717 7137 : 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 7137 : 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 7137 : convertInt32ToDouble(dest, fpTemp);
724 7137 : m_assembler.ucomisd_rr(fpTemp, src);
725 7137 : failureCases.append(m_assembler.jp());
726 7137 : failureCases.append(m_assembler.jne());
727 7137 : }
728 :
729 949 : void zeroDouble(FPRegisterID srcDest)
730 : {
731 949 : ASSERT(isSSE2Present());
732 949 : m_assembler.xorpd_rr(srcDest, srcDest);
733 949 : }
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 449850 : void pop(RegisterID dest)
745 : {
746 449850 : m_assembler.pop_r(dest);
747 449850 : }
748 :
749 233906 : void push(RegisterID src)
750 : {
751 233906 : m_assembler.push_r(src);
752 233906 : }
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 1042429 : 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 1042429 : if (!imm.m_value)
774 357756 : m_assembler.xorl_rr(dest, dest);
775 : else
776 684673 : m_assembler.movl_i32r(imm.m_value, dest);
777 1042429 : }
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 11177949 : void move(RegisterID src, RegisterID dest)
814 : {
815 11177949 : if (src != dest)
816 11177925 : m_assembler.movl_rr(src, dest);
817 11177949 : }
818 :
819 1463284 : void move(TrustedImmPtr imm, RegisterID dest)
820 : {
821 1463284 : m_assembler.movl_i32r(imm.asIntptr(), dest);
822 1463284 : }
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 259138 : Jump branch32(Condition cond, RegisterID left, RegisterID right)
868 : {
869 259138 : m_assembler.cmpl_rr(right, left);
870 259138 : return Jump(m_assembler.jCC(x86Condition(cond)));
871 : }
872 :
873 4501372 : Jump branch32(Condition cond, RegisterID left, TrustedImm32 right)
874 : {
875 4501372 : if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
876 26960 : m_assembler.testl_rr(left, left);
877 : else
878 4474412 : m_assembler.cmpl_ir(right.m_value, left);
879 4501372 : 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 86999 : Jump branch32(Condition cond, RegisterID left, Address right)
908 : {
909 86999 : m_assembler.cmpl_mr(right.offset, right.base, left);
910 86999 : return Jump(m_assembler.jCC(x86Condition(cond)));
911 : }
912 :
913 62448 : Jump branch32(Condition cond, Address left, RegisterID right)
914 : {
915 62448 : m_assembler.cmpl_rm(right, left.offset, left.base);
916 62448 : return Jump(m_assembler.jCC(x86Condition(cond)));
917 : }
918 :
919 739976 : Jump branch32(Condition cond, Address left, TrustedImm32 right)
920 : {
921 739976 : m_assembler.cmpl_im(right.m_value, left.offset, left.base);
922 739976 : return Jump(m_assembler.jCC(x86Condition(cond)));
923 : }
924 :
925 74169 : Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
926 : {
927 74169 : m_assembler.cmpl_im(right.m_value, left.offset, left.base, left.index, left.scale);
928 74169 : return Jump(m_assembler.jCC(x86Condition(cond)));
929 : }
930 :
931 69522 : Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
932 : {
933 69522 : 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 57430 : Jump branch16(Condition cond, BaseIndex left, Imm32 right)
943 : {
944 57430 : ASSERT(!(right.m_value & 0xFFFF0000));
945 :
946 57430 : m_assembler.cmpw_im(right.m_value, left.offset, left.base, left.index, left.scale);
947 57430 : return Jump(m_assembler.jCC(x86Condition(cond)));
948 : }
949 :
950 606310 : Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask)
951 : {
952 606310 : ASSERT((cond == Zero) || (cond == NonZero));
953 606310 : m_assembler.testl_rr(reg, mask);
954 606310 : return Jump(m_assembler.jCC(x86Condition(cond)));
955 : }
956 :
957 248716 : Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1))
958 : {
959 248716 : ASSERT((cond == Zero) || (cond == NonZero));
960 : // if we are only interested in the low seven bits, this can be tested with a testb
961 248716 : if (mask.m_value == -1)
962 222956 : m_assembler.testl_rr(reg, reg);
963 25760 : else if (CanUse8Bit(reg) && (mask.m_value & ~0x7f) == 0)
964 14215 : m_assembler.testb_i8r(mask.m_value, reg);
965 : else
966 11545 : m_assembler.testl_i32r(mask.m_value, reg);
967 248716 : return Jump(m_assembler.jCC(x86Condition(cond)));
968 : }
969 :
970 297748 : Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1))
971 : {
972 297748 : ASSERT((cond == Zero) || (cond == NonZero));
973 297748 : if (mask.m_value == -1)
974 0 : m_assembler.cmpl_im(0, address.offset, address.base);
975 : else
976 297748 : m_assembler.testl_i32m(mask.m_value, address.offset, address.base);
977 297748 : 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 3435 : Jump branchTest8(Condition cond, Address address, Imm32 mask = Imm32(-1))
991 : {
992 3435 : ASSERT((cond == Zero) || (cond == NonZero));
993 3435 : if (mask.m_value == -1)
994 3435 : 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 3435 : 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 8690929 : Jump jump()
1011 : {
1012 8690929 : return Jump(m_assembler.jmp());
1013 : }
1014 :
1015 579341 : void jump(RegisterID target)
1016 : {
1017 579341 : m_assembler.jmp_r(target);
1018 579341 : }
1019 :
1020 : // Address is a memory location containing the address to jump to
1021 2921 : void jump(Address address)
1022 : {
1023 2921 : m_assembler.jmp_m(address.offset, address.base);
1024 2921 : }
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 319053 : Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest)
1042 : {
1043 319053 : ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1044 319053 : add32(src, dest);
1045 319053 : return Jump(m_assembler.jCC(x86Condition(cond)));
1046 : }
1047 :
1048 221891 : Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest)
1049 : {
1050 221891 : ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1051 221891 : add32(imm, dest);
1052 221891 : 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 1881 : Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest)
1091 : {
1092 1881 : ASSERT(cond == Overflow);
1093 1881 : mul32(imm, src, dest);
1094 1881 : return Jump(m_assembler.jCC(x86Condition(cond)));
1095 : }
1096 :
1097 3979 : Jump branchSub32(Condition cond, RegisterID src, RegisterID dest)
1098 : {
1099 3979 : ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1100 3979 : sub32(src, dest);
1101 3979 : return Jump(m_assembler.jCC(x86Condition(cond)));
1102 : }
1103 :
1104 42117 : Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest)
1105 : {
1106 42117 : ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1107 42117 : sub32(imm, dest);
1108 42117 : 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 112212 : void ret()
1170 : {
1171 112212 : m_assembler.ret();
1172 112212 : }
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 1104 : void set32(Condition cond, RegisterID left, Address right, RegisterID dest)
1203 : {
1204 1104 : m_assembler.cmpl_mr(right.offset, right.base, left);
1205 1104 : m_assembler.setCC_r(x86Condition(cond), dest);
1206 1104 : m_assembler.movzbl_rr(dest, dest);
1207 1104 : }
1208 :
1209 7583 : void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
1210 : {
1211 7583 : m_assembler.cmpl_rr(right, left);
1212 7583 : m_assembler.setCC_r(x86Condition(cond), dest);
1213 7583 : m_assembler.movzbl_rr(dest, dest);
1214 7583 : }
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 34997 : void set32(Condition cond, RegisterID left, Imm32 right, RegisterID dest)
1224 : {
1225 34997 : if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
1226 20726 : m_assembler.testl_rr(left, left);
1227 : else
1228 14271 : m_assembler.cmpl_ir(right.m_value, left);
1229 34997 : m_assembler.setCC_r(x86Condition(cond), dest);
1230 34997 : m_assembler.movzbl_rr(dest, dest);
1231 34997 : }
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 1322273 : static SSECheckState getSSEState()
1272 : {
1273 1322273 : if (s_sseCheckState == NotCheckedSSE) {
1274 0 : MacroAssemblerX86Common::setSSECheckState();
1275 : }
1276 : // Only check once.
1277 1322273 : ASSERT(s_sseCheckState != NotCheckedSSE);
1278 :
1279 1322273 : return s_sseCheckState;
1280 : }
1281 :
1282 : protected:
1283 8988801 : X86Assembler::Condition x86Condition(Condition cond)
1284 : {
1285 8988801 : return static_cast<X86Assembler::Condition>(cond);
1286 : }
1287 :
1288 : private:
1289 : friend class MacroAssemblerX86;
1290 :
1291 : static SSECheckState s_sseCheckState;
1292 :
1293 16462 : 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 16462 : volatile int flags_edx = 0;
1298 16462 : 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 16462 : );
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 16462 : if (flags_ecx & SSE42FeatureBit)
1374 16445 : s_sseCheckState = HasSSE4_2;
1375 17 : else if (flags_ecx & SSE41FeatureBit)
1376 0 : s_sseCheckState = HasSSE4_1;
1377 17 : else if (flags_ecx & SSSE3FeatureBit)
1378 17 : 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 16462 : }
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 3126088 : static bool isSSE2Present()
1417 : {
1418 3126088 : if (s_sseCheckState == NotCheckedSSE) {
1419 16462 : setSSECheckState();
1420 : }
1421 : // Only check once.
1422 3126088 : ASSERT(s_sseCheckState != NotCheckedSSE);
1423 :
1424 3126088 : 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
|