]> gitweb.factorcode.org Git - factor.git/blob - basis/cpu/x86/x86.factor
9790f6e7dd3d750db83fd9cf0f8ba06ffe00d0b5
[factor.git] / basis / cpu / x86 / x86.factor
1 ! Copyright (C) 2005, 2010 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors assocs alien alien.c-types arrays strings
4 cpu.x86.assembler cpu.x86.assembler.private cpu.x86.assembler.operands
5 cpu.x86.features cpu.x86.features.private cpu.architecture kernel
6 kernel.private math memory namespaces make sequences words system
7 layouts combinators math.order math.vectors fry locals compiler.constants
8 byte-arrays io macros quotations classes.algebra compiler
9 compiler.units init vm
10 compiler.cfg.registers
11 compiler.cfg.instructions
12 compiler.cfg.intrinsics
13 compiler.cfg.comparisons
14 compiler.cfg.stack-frame
15 compiler.codegen.fixup ;
16 QUALIFIED-WITH: alien.c-types c
17 FROM: layouts => cell ;
18 FROM: math => float ;
19 IN: cpu.x86
20
21 ! Add some methods to the assembler to be more useful to the backend
22 M: label JMP 0 JMP rc-relative label-fixup ;
23 M: label JUMPcc [ 0 ] dip JUMPcc rc-relative label-fixup ;
24
25 M: x86 vector-regs float-regs ;
26
27 HOOK: stack-reg cpu ( -- reg )
28
29 HOOK: frame-reg cpu ( -- reg )
30
31 HOOK: reserved-stack-space cpu ( -- n )
32
33 HOOK: extra-stack-space cpu ( stack-frame -- n )
34
35 : stack@ ( n -- op ) stack-reg swap [+] ;
36
37 : special-offset ( m -- n )
38     stack-frame get extra-stack-space +
39     reserved-stack-space + ;
40
41 : special@ ( n -- op ) special-offset stack@ ;
42
43 : spill@ ( n -- op ) spill-offset special@ ;
44
45 : param@ ( n -- op ) reserved-stack-space + stack@ ;
46
47 : gc-root-offsets ( seq -- seq' )
48     [ n>> spill-offset special-offset cell + ] map f like ;
49
50 : decr-stack-reg ( n -- )
51     dup 0 = [ drop ] [ stack-reg swap SUB ] if ;
52
53 : incr-stack-reg ( n -- )
54     dup 0 = [ drop ] [ stack-reg swap ADD ] if ;
55
56 : align-stack ( n -- n' ) 16 align ;
57
58 M: x86 stack-frame-size ( stack-frame -- i )
59     [ (stack-frame-size) ]
60     [ extra-stack-space ] bi +
61     reserved-stack-space +
62     3 cells +
63     align-stack ;
64
65 ! Must be a volatile register not used for parameter passing or
66 ! integer return
67 HOOK: temp-reg cpu ( -- reg )
68
69 HOOK: pic-tail-reg cpu ( -- reg )
70
71 M: x86 complex-addressing? t ;
72
73 M: x86 fused-unboxing? t ;
74
75 M: x86 test-instruction? t ;
76
77 M: x86 immediate-store? immediate-comparand? ;
78
79 M: x86 %load-immediate dup 0 = [ drop dup XOR ] [ MOV ] if ;
80
81 M: x86 %load-reference
82     [ swap 0 MOV rc-absolute-cell rel-literal ]
83     [ \ f type-number MOV ]
84     if* ;
85
86 HOOK: ds-reg cpu ( -- reg )
87 HOOK: rs-reg cpu ( -- reg )
88
89 : reg-stack ( n reg -- op ) swap cells neg [+] ;
90
91 GENERIC: loc>operand ( loc -- operand )
92
93 M: ds-loc loc>operand n>> ds-reg reg-stack ;
94 M: rs-loc loc>operand n>> rs-reg reg-stack ;
95
96 M: x86 %peek loc>operand MOV ;
97
98 M: x86 %replace loc>operand swap MOV ;
99
100 M: x86 %replace-imm
101     loc>operand swap
102     {
103         { [ dup not ] [ drop \ f type-number MOV ] }
104         { [ dup fixnum? ] [ tag-fixnum MOV ] }
105         [ [ HEX: ffffffff MOV ] dip rc-absolute rel-literal ]
106     } cond ;
107
108 : (%inc) ( n reg -- ) swap cells dup 0 > [ ADD ] [ neg SUB ] if ; inline
109 M: x86 %inc-d ( n -- ) ds-reg (%inc) ;
110 M: x86 %inc-r ( n -- ) rs-reg (%inc) ;
111
112 M: x86 %call ( word -- ) 0 CALL rc-relative rel-word-pic ;
113
114 : xt-tail-pic-offset ( -- n )
115     #! See the comment in vm/cpu-x86.hpp
116     4 1 + ; inline
117
118 HOOK: %prepare-jump cpu ( -- )
119
120 M: x86 %jump ( word -- )
121     %prepare-jump
122     0 JMP rc-relative rel-word-pic-tail ;
123
124 M: x86 %jump-label ( label -- ) 0 JMP rc-relative label-fixup ;
125
126 M: x86 %return ( -- ) 0 RET ;
127
128 : (%slot) ( obj slot scale tag -- op ) neg <indirect> ; inline
129 : (%slot-imm) ( obj slot tag -- op ) slot-offset [+] ; inline
130
131 M: x86 %slot ( dst obj slot scale tag -- ) (%slot) MOV ;
132 M: x86 %slot-imm ( dst obj slot tag -- ) (%slot-imm) MOV ;
133 M: x86 %set-slot ( src obj slot scale tag -- ) (%slot) swap MOV ;
134 M: x86 %set-slot-imm ( src obj slot tag -- ) (%slot-imm) swap MOV ;
135
136 :: two-operand ( dst src1 src2 rep -- dst src )
137     dst src2 eq? dst src1 eq? not and [ "Cannot handle this case" throw ] when
138     dst src1 rep %copy
139     dst src2 ; inline
140
141 :: one-operand ( dst src rep -- dst )
142     dst src rep %copy
143     dst ; inline
144
145 M: x86 %add     2over eq? [ nip ADD ] [ [+] LEA ] if ;
146 M: x86 %add-imm 2over eq? [ nip ADD ] [ [+] LEA ] if ;
147 M: x86 %sub     int-rep two-operand SUB ;
148 M: x86 %sub-imm 2over eq? [ nip SUB ] [ neg [+] LEA ] if ;
149 M: x86 %mul     int-rep two-operand IMUL2 ;
150 M: x86 %mul-imm IMUL3 ;
151 M: x86 %and     int-rep two-operand AND ;
152 M: x86 %and-imm int-rep two-operand AND ;
153 M: x86 %or      int-rep two-operand OR ;
154 M: x86 %or-imm  int-rep two-operand OR ;
155 M: x86 %xor     int-rep two-operand XOR ;
156 M: x86 %xor-imm int-rep two-operand XOR ;
157 M: x86 %shl-imm int-rep two-operand SHL ;
158 M: x86 %shr-imm int-rep two-operand SHR ;
159 M: x86 %sar-imm int-rep two-operand SAR ;
160
161 M: x86 %min     int-rep two-operand [ CMP ] [ CMOVG ] 2bi ;
162 M: x86 %max     int-rep two-operand [ CMP ] [ CMOVL ] 2bi ;
163
164 M: x86 %not     int-rep one-operand NOT ;
165 M: x86 %neg     int-rep one-operand NEG ;
166 M: x86 %log2    BSR ;
167 M: x86 %bit-count POPCNT ;
168
169 ! A bit of logic to avoid using MOVSS/MOVSD for reg-reg moves
170 ! since this induces partial register stalls
171 GENERIC: copy-register* ( dst src rep -- )
172 GENERIC: copy-memory* ( dst src rep -- )
173
174 M: int-rep copy-register* drop MOV ;
175 M: tagged-rep copy-register* drop MOV ;
176 M: float-rep copy-register* drop MOVAPS ;
177 M: double-rep copy-register* drop MOVAPS ;
178 M: float-4-rep copy-register* drop MOVAPS ;
179 M: double-2-rep copy-register* drop MOVAPS ;
180 M: vector-rep copy-register* drop MOVDQA ;
181
182 M: object copy-memory* copy-register* ;
183 M: float-rep copy-memory* drop MOVSS ;
184 M: double-rep copy-memory* drop MOVSD ;
185
186 : ?spill-slot ( obj -- obj ) dup spill-slot? [ n>> spill@ ] when ;
187
188 M: x86 %copy ( dst src rep -- )
189     2over eq? [ 3drop ] [
190         [ [ ?spill-slot ] bi@ ] dip
191         2over [ register? ] both? [ copy-register* ] [ copy-memory* ] if
192     ] if ;
193
194 : fixnum-overflow ( label dst src1 src2 cc quot -- )
195     swap [ [ int-rep two-operand ] dip call ] dip
196     {
197         { cc-o [ JO ] }
198         { cc/o [ JNO ] }
199     } case ; inline
200
201 M: x86 %fixnum-add ( label dst src1 src2 cc -- )
202     [ ADD ] fixnum-overflow ;
203
204 M: x86 %fixnum-sub ( label dst src1 src2 cc -- )
205     [ SUB ] fixnum-overflow ;
206
207 M: x86 %fixnum-mul ( label dst src1 src2 cc -- )
208     [ IMUL2 ] fixnum-overflow ;
209
210 M: x86 %unbox-alien ( dst src -- )
211     alien-offset [+] MOV ;
212
213 M:: x86 %unbox-any-c-ptr ( dst src -- )
214     [
215         "end" define-label
216         dst dst XOR
217         ! Is the object f?
218         src \ f type-number CMP
219         "end" get JE
220         ! Compute tag in dst register
221         dst src MOV
222         dst tag-mask get AND
223         ! Is the object an alien?
224         dst alien type-number CMP
225         ! Add an offset to start of byte array's data
226         dst src byte-array-offset [+] LEA
227         "end" get JNE
228         ! If so, load the offset and add it to the address
229         dst src alien-offset [+] MOV
230         "end" resolve-label
231     ] with-scope ;
232
233 : alien@ ( reg n -- op ) cells alien type-number - [+] ;
234
235 M:: x86 %box-alien ( dst src temp -- )
236     [
237         "end" define-label
238         dst \ f type-number MOV
239         src src TEST
240         "end" get JE
241         dst 5 cells alien temp %allot
242         dst 1 alien@ \ f type-number MOV ! base
243         dst 2 alien@ \ f type-number MOV ! expired
244         dst 3 alien@ src MOV ! displacement
245         dst 4 alien@ src MOV ! address
246         "end" resolve-label
247     ] with-scope ;
248
249 :: %box-displaced-alien/f ( dst displacement -- )
250     dst 1 alien@ \ f type-number MOV
251     dst 3 alien@ displacement MOV
252     dst 4 alien@ displacement MOV ;
253
254 :: %box-displaced-alien/alien ( dst displacement base temp -- )
255     ! Set new alien's base to base.base
256     temp base 1 alien@ MOV
257     dst 1 alien@ temp MOV
258
259     ! Compute displacement
260     temp base 3 alien@ MOV
261     temp displacement ADD
262     dst 3 alien@ temp MOV
263
264     ! Compute address
265     temp base 4 alien@ MOV
266     temp displacement ADD
267     dst 4 alien@ temp MOV ;
268
269 :: %box-displaced-alien/byte-array ( dst displacement base temp -- )
270     dst 1 alien@ base MOV
271     dst 3 alien@ displacement MOV
272     temp base displacement byte-array-offset [++] LEA
273     dst 4 alien@ temp MOV ;
274
275 :: %box-displaced-alien/dynamic ( dst displacement base temp -- )
276     "not-f" define-label
277     "not-alien" define-label
278
279     ! Check base type
280     temp base MOV
281     temp tag-mask get AND
282
283     ! Is base f?
284     temp \ f type-number CMP
285     "not-f" get JNE
286
287     ! Yes, it is f. Fill in new object
288     dst displacement %box-displaced-alien/f
289
290     "end" get JMP
291
292     "not-f" resolve-label
293
294     ! Is base an alien?
295     temp alien type-number CMP
296     "not-alien" get JNE
297
298     dst displacement base temp %box-displaced-alien/alien
299
300     ! We are done
301     "end" get JMP
302
303     ! Is base a byte array? It has to be, by now...
304     "not-alien" resolve-label
305
306     dst displacement base temp %box-displaced-alien/byte-array ;
307
308 M:: x86 %box-displaced-alien ( dst displacement base temp base-class -- )
309     [
310         "end" define-label
311
312         ! If displacement is zero, return the base
313         dst base MOV
314         displacement displacement TEST
315         "end" get JE
316
317         ! Displacement is non-zero, we're going to be allocating a new
318         ! object
319         dst 5 cells alien temp %allot
320
321         ! Set expired to f
322         dst 2 alien@ \ f type-number MOV
323
324         dst displacement base temp
325         {
326             { [ base-class \ f class<= ] [ 2drop %box-displaced-alien/f ] }
327             { [ base-class \ alien class<= ] [ %box-displaced-alien/alien ] }
328             { [ base-class \ byte-array class<= ] [ %box-displaced-alien/byte-array ] }
329             [ %box-displaced-alien/dynamic ]
330         } cond
331
332         "end" resolve-label
333     ] with-scope ;
334
335 ! The 'small-reg' mess is pretty crappy, but its only used on x86-32.
336 ! On x86-64, all registers have 8-bit versions. However, a similar
337 ! problem arises for shifts, where the shift count must be in CL, and
338 ! so one day I will fix this properly by adding precoloring to the
339 ! register allocator.
340
341 HOOK: has-small-reg? cpu ( reg size -- ? )
342
343 CONSTANT: have-byte-regs { EAX ECX EDX EBX }
344
345 M: x86.32 has-small-reg?
346     {
347         { 8 [ have-byte-regs member-eq? ] }
348         { 16 [ drop t ] }
349         { 32 [ drop t ] }
350     } case ;
351
352 M: x86.64 has-small-reg? 2drop t ;
353
354 : small-reg-that-isn't ( exclude -- reg' )
355     [ have-byte-regs ] dip
356     [ native-version-of ] map
357     '[ _ member-eq? not ] find nip ;
358
359 : with-save/restore ( reg quot -- )
360     [ drop PUSH ] [ call ] [ drop POP ] 2tri ; inline
361
362 :: with-small-register ( dst exclude size quot: ( new-dst -- ) -- )
363     ! If the destination register overlaps a small register with
364     ! 'size' bits, we call the quot with that. Otherwise, we find a
365     ! small register that is not in exclude, and call quot, saving and
366     ! restoring the small register.
367     dst size has-small-reg? [ dst quot call ] [
368         exclude small-reg-that-isn't
369         [ quot call ] with-save/restore
370     ] if ; inline
371
372 :: %alien-integer-getter ( dst exclude address bits quot -- )
373     dst exclude bits [| new-dst |
374         new-dst dup bits n-bit-version-of dup address MOV
375         quot call
376         dst new-dst int-rep %copy
377     ] with-small-register ; inline
378
379 : %alien-unsigned-getter ( dst exclude address bits -- )
380     [ MOVZX ] %alien-integer-getter ; inline
381
382 : %alien-signed-getter ( dst exclude address bits -- )
383     [ MOVSX ] %alien-integer-getter ; inline
384
385 :: %alien-integer-setter ( value exclude address bits -- )
386     value exclude bits [| new-value |
387         new-value value int-rep %copy
388         address new-value bits n-bit-version-of MOV
389     ] with-small-register ; inline
390
391 : (%memory) ( base displacement scale offset rep c-type -- exclude address rep c-type )
392     [ [ [ 2array ] 2keep ] 2dip <indirect> ] 2dip ;
393
394 : (%memory-imm) ( base offset rep c-type -- exclude address rep c-type )
395     [ [ drop 1array ] [ [+] ] 2bi ] 2dip ;
396
397 : (%load-memory) ( dst exclude address rep c-type -- )
398     [
399         {
400             { c:char   [ 8 %alien-signed-getter ] }
401             { c:uchar  [ 8 %alien-unsigned-getter ] }
402             { c:short  [ 16 %alien-signed-getter ] }
403             { c:ushort [ 16 %alien-unsigned-getter ] }
404             { c:int    [ 32 %alien-signed-getter ] }
405             { c:uint   [ 32 [ 2drop ] %alien-integer-getter ] }
406         } case
407     ] [ [ drop ] 2dip %copy ] ?if ;
408
409 M: x86 %load-memory ( dst base displacement scale offset rep c-type -- )
410     (%memory) (%load-memory) ;
411
412 M: x86 %load-memory-imm ( dst base offset rep c-type -- )
413     (%memory-imm) (%load-memory) ;
414
415 : (%store-memory) ( src exclude address rep c-type -- )
416     [
417         {
418             { c:char   [ 8 %alien-integer-setter ] }
419             { c:uchar  [ 8 %alien-integer-setter ] }
420             { c:short  [ 16 %alien-integer-setter ] }
421             { c:ushort [ 16 %alien-integer-setter ] }
422             { c:int    [ 32 %alien-integer-setter ] }
423             { c:uint   [ 32 %alien-integer-setter ] }
424         } case
425     ] [ [ nip swap ] dip %copy ] ?if ;
426
427 M: x86 %store-memory ( src base displacement scale offset rep c-type -- )
428     (%memory) (%store-memory) ;
429
430 M: x86 %store-memory-imm ( src base offset rep c-type -- )
431     (%memory-imm) (%store-memory) ;
432
433 : shift-count? ( reg -- ? ) { ECX RCX } member-eq? ;
434
435 :: emit-shift ( dst src quot -- )
436     src shift-count? [
437         dst CL quot call
438     ] [
439         dst shift-count? [
440             dst src XCHG
441             src CL quot call
442             dst src XCHG
443         ] [
444             ECX native-version-of [
445                 CL src MOV
446                 drop dst CL quot call
447             ] with-save/restore
448         ] if
449     ] if ; inline
450
451 M: x86 %shl int-rep two-operand [ SHL ] emit-shift ;
452 M: x86 %shr int-rep two-operand [ SHR ] emit-shift ;
453 M: x86 %sar int-rep two-operand [ SAR ] emit-shift ;
454
455 HOOK: %mov-vm-ptr cpu ( reg -- )
456
457 HOOK: %vm-field-ptr cpu ( reg offset -- )
458
459 : load-zone-offset ( nursery-ptr -- )
460     "nursery" vm-field-offset %vm-field-ptr ;
461
462 : load-allot-ptr ( nursery-ptr allot-ptr -- )
463     [ drop load-zone-offset ] [ swap [] MOV ] 2bi ;
464
465 : inc-allot-ptr ( nursery-ptr n -- )
466     [ [] ] dip data-alignment get align ADD ;
467
468 : store-header ( temp class -- )
469     [ [] ] [ type-number tag-header ] bi* MOV ;
470
471 : store-tagged ( dst tag -- )
472     type-number OR ;
473
474 M:: x86 %allot ( dst size class nursery-ptr -- )
475     nursery-ptr dst load-allot-ptr
476     dst class store-header
477     dst class store-tagged
478     nursery-ptr size inc-allot-ptr ;
479
480 HOOK: %mark-card cpu ( card temp -- )
481 HOOK: %mark-deck cpu ( card temp -- )
482
483 :: (%write-barrier) ( temp1 temp2 -- )
484     temp1 card-bits SHR
485     temp1 temp2 %mark-card
486     temp1 deck-bits card-bits - SHR
487     temp1 temp2 %mark-deck ;
488
489 M:: x86 %write-barrier ( src slot scale tag temp1 temp2 -- )
490     temp1 src slot scale tag (%slot) LEA
491     temp1 temp2 (%write-barrier) ;
492
493 M:: x86 %write-barrier-imm ( src slot tag temp1 temp2 -- )
494     temp1 src slot tag (%slot-imm) LEA
495     temp1 temp2 (%write-barrier) ;
496
497 M:: x86 %check-nursery-branch ( label size cc temp1 temp2 -- )
498     temp1 load-zone-offset
499     temp2 temp1 [] MOV
500     temp2 size ADD
501     temp2 temp1 2 cells [+] CMP
502     cc {
503         { cc<= [ label JLE ] }
504         { cc/<= [ label JG ] }
505     } case ;
506
507 M: x86 %alien-global ( dst symbol library -- )
508     [ 0 MOV ] 2dip rc-absolute-cell rel-dlsym ;    
509
510 M: x86 %epilogue ( n -- ) cell - incr-stack-reg ;
511
512 :: (%boolean) ( dst temp insn -- )
513     dst \ f type-number MOV
514     temp 0 MOV \ t rc-absolute-cell rel-literal
515     dst temp insn execute ; inline
516
517 : %boolean ( dst cc temp -- )
518     swap order-cc {
519         { cc<  [ \ CMOVL (%boolean) ] }
520         { cc<= [ \ CMOVLE (%boolean) ] }
521         { cc>  [ \ CMOVG (%boolean) ] }
522         { cc>= [ \ CMOVGE (%boolean) ] }
523         { cc=  [ \ CMOVE (%boolean) ] }
524         { cc/= [ \ CMOVNE (%boolean) ] }
525     } case ;
526
527 M:: x86 %compare ( dst src1 src2 cc temp -- )
528     src1 src2 CMP
529     dst cc temp %boolean ;
530
531 M:: x86 %test ( dst src1 src2 cc temp -- )
532     src1 src2 TEST
533     dst cc temp %boolean ;
534
535 : (%compare-tagged) ( src1 src2 -- )
536     [ HEX: ffffffff CMP ] dip rc-absolute rel-literal ;
537
538 M:: x86 %compare-integer-imm ( dst src1 src2 cc temp -- )
539     src1 src2 CMP
540     dst cc temp %boolean ;
541
542 M:: x86 %test-imm ( dst src1 src2 cc temp -- )
543     src1 src2 TEST
544     dst cc temp %boolean ;
545
546 : (%compare-imm) ( src1 src2 -- )
547     {
548         { [ dup fixnum? ] [ tag-fixnum CMP ] }
549         { [ dup not ] [ drop \ f type-number CMP ] }
550         [ (%compare-tagged) ]
551     } cond ;
552
553 M:: x86 %compare-imm ( dst src1 src2 cc temp -- )
554     src1 src2 (%compare-imm)
555     dst cc temp %boolean ;
556
557 : %branch ( label cc -- )
558     order-cc {
559         { cc<  [ JL ] }
560         { cc<= [ JLE ] }
561         { cc>  [ JG ] }
562         { cc>= [ JGE ] }
563         { cc=  [ JE ] }
564         { cc/= [ JNE ] }
565     } case ;
566
567 M:: x86 %compare-branch ( label src1 src2 cc -- )
568     src1 src2 CMP
569     label cc %branch ;
570
571 M:: x86 %compare-integer-imm-branch ( label src1 src2 cc -- )
572     src1 src2 CMP
573     label cc %branch ;
574
575 M:: x86 %test-branch ( label src1 src2 cc -- )
576     src1 src2 TEST
577     label cc %branch ;
578
579 M:: x86 %test-imm-branch ( label src1 src2 cc -- )
580     src1 src2 TEST
581     label cc %branch ;
582
583 M:: x86 %compare-imm-branch ( label src1 src2 cc -- )
584     src1 src2 (%compare-imm)
585     label cc %branch ;
586
587 M: x86 %add-float double-rep two-operand ADDSD ;
588 M: x86 %sub-float double-rep two-operand SUBSD ;
589 M: x86 %mul-float double-rep two-operand MULSD ;
590 M: x86 %div-float double-rep two-operand DIVSD ;
591 M: x86 %min-float double-rep two-operand MINSD ;
592 M: x86 %max-float double-rep two-operand MAXSD ;
593 M: x86 %sqrt SQRTSD ;
594
595 : %clear-unless-in-place ( dst src -- )
596     over = [ drop ] [ dup XORPS ] if ;
597
598 M: x86 %single>double-float [ %clear-unless-in-place ] [ CVTSS2SD ] 2bi ;
599 M: x86 %double>single-float [ %clear-unless-in-place ] [ CVTSD2SS ] 2bi ;
600
601 M: x86 %integer>float [ drop dup XORPS ] [ CVTSI2SD ] 2bi ;
602 M: x86 %float>integer CVTTSD2SI ;
603
604 : %cmov-float= ( dst src -- )
605     [
606         "no-move" define-label
607
608         "no-move" get [ JNE ] [ JP ] bi
609         MOV
610         "no-move" resolve-label
611     ] with-scope ;
612
613 : %cmov-float/= ( dst src -- )
614     [
615         "no-move" define-label
616         "move" define-label
617
618         "move" get JP
619         "no-move" get JE
620         "move" resolve-label
621         MOV
622         "no-move" resolve-label
623     ] with-scope ;
624
625 :: (%compare-float) ( dst src1 src2 cc temp compare -- )
626     cc {
627         { cc<    [ src2 src1 \ compare execute( a b -- ) dst temp \ CMOVA  (%boolean) ] }
628         { cc<=   [ src2 src1 \ compare execute( a b -- ) dst temp \ CMOVAE (%boolean) ] }
629         { cc>    [ src1 src2 \ compare execute( a b -- ) dst temp \ CMOVA  (%boolean) ] }
630         { cc>=   [ src1 src2 \ compare execute( a b -- ) dst temp \ CMOVAE (%boolean) ] }
631         { cc=    [ src1 src2 \ compare execute( a b -- ) dst temp \ %cmov-float= (%boolean) ] }
632         { cc<>   [ src1 src2 \ compare execute( a b -- ) dst temp \ CMOVNE (%boolean) ] }
633         { cc<>=  [ src1 src2 \ compare execute( a b -- ) dst temp \ CMOVNP (%boolean) ] }
634         { cc/<   [ src2 src1 \ compare execute( a b -- ) dst temp \ CMOVBE (%boolean) ] }
635         { cc/<=  [ src2 src1 \ compare execute( a b -- ) dst temp \ CMOVB  (%boolean) ] }
636         { cc/>   [ src1 src2 \ compare execute( a b -- ) dst temp \ CMOVBE (%boolean) ] }
637         { cc/>=  [ src1 src2 \ compare execute( a b -- ) dst temp \ CMOVB  (%boolean) ] }
638         { cc/=   [ src1 src2 \ compare execute( a b -- ) dst temp \ %cmov-float/= (%boolean) ] }
639         { cc/<>  [ src1 src2 \ compare execute( a b -- ) dst temp \ CMOVE  (%boolean) ] }
640         { cc/<>= [ src1 src2 \ compare execute( a b -- ) dst temp \ CMOVP  (%boolean) ] }
641     } case ; inline
642
643 M: x86 %compare-float-ordered ( dst src1 src2 cc temp -- )
644     \ COMISD (%compare-float) ;
645
646 M: x86 %compare-float-unordered ( dst src1 src2 cc temp -- )
647     \ UCOMISD (%compare-float) ;
648
649 : %jump-float= ( label -- )
650     [
651         "no-jump" define-label
652         "no-jump" get JP
653         JE
654         "no-jump" resolve-label
655     ] with-scope ;
656
657 : %jump-float/= ( label -- )
658     [ JNE ] [ JP ] bi ;
659
660 :: (%compare-float-branch) ( label src1 src2 cc compare -- )
661     cc {
662         { cc<    [ src2 src1 \ compare execute( a b -- ) label JA  ] }
663         { cc<=   [ src2 src1 \ compare execute( a b -- ) label JAE ] }
664         { cc>    [ src1 src2 \ compare execute( a b -- ) label JA  ] }
665         { cc>=   [ src1 src2 \ compare execute( a b -- ) label JAE ] }
666         { cc=    [ src1 src2 \ compare execute( a b -- ) label %jump-float= ] }
667         { cc<>   [ src1 src2 \ compare execute( a b -- ) label JNE ] }
668         { cc<>=  [ src1 src2 \ compare execute( a b -- ) label JNP ] }
669         { cc/<   [ src2 src1 \ compare execute( a b -- ) label JBE ] }
670         { cc/<=  [ src2 src1 \ compare execute( a b -- ) label JB  ] }
671         { cc/>   [ src1 src2 \ compare execute( a b -- ) label JBE ] }
672         { cc/>=  [ src1 src2 \ compare execute( a b -- ) label JB  ] }
673         { cc/=   [ src1 src2 \ compare execute( a b -- ) label %jump-float/= ] }
674         { cc/<>  [ src1 src2 \ compare execute( a b -- ) label JE  ] }
675         { cc/<>= [ src1 src2 \ compare execute( a b -- ) label JP  ] }
676     } case ;
677
678 M: x86 %compare-float-ordered-branch ( label src1 src2 cc -- )
679     \ COMISD (%compare-float-branch) ;
680
681 M: x86 %compare-float-unordered-branch ( label src1 src2 cc -- )
682     \ UCOMISD (%compare-float-branch) ;
683
684 MACRO: available-reps ( alist -- )
685     ! Each SSE version adds new representations and supports
686     ! all old ones
687     unzip { } [ append ] accumulate rest swap suffix
688     [ [ 1quotation ] map ] bi@ zip
689     reverse [ { } ] suffix
690     '[ _ cond ] ;
691
692 M: x86 %alien-vector-reps
693     {
694         { sse? { float-4-rep } }
695         { sse2? { double-2-rep char-16-rep uchar-16-rep short-8-rep ushort-8-rep int-4-rep uint-4-rep longlong-2-rep ulonglong-2-rep } }
696     } available-reps ;
697
698 M: x86 %zero-vector
699     {
700         { double-2-rep [ dup XORPS ] }
701         { float-4-rep [ dup XORPS ] }
702         [ drop dup PXOR ]
703     } case ;
704
705 M: x86 %zero-vector-reps
706     {
707         { sse? { float-4-rep } }
708         { sse2? { double-2-rep char-16-rep uchar-16-rep short-8-rep ushort-8-rep int-4-rep uint-4-rep longlong-2-rep ulonglong-2-rep } }
709     } available-reps ;
710
711 M: x86 %fill-vector
712     {
713         { double-2-rep [ dup [ XORPS ] [ CMPEQPS ] 2bi ] }
714         { float-4-rep  [ dup [ XORPS ] [ CMPEQPS ] 2bi ] }
715         [ drop dup PCMPEQB ]
716     } case ;
717
718 M: x86 %fill-vector-reps
719     {
720         { sse? { float-4-rep } }
721         { sse2? { double-2-rep char-16-rep uchar-16-rep short-8-rep ushort-8-rep int-4-rep uint-4-rep longlong-2-rep ulonglong-2-rep } }
722     } available-reps ;
723
724 M:: x86 %gather-vector-4 ( dst src1 src2 src3 src4 rep -- )
725     rep signed-rep {
726         { float-4-rep [
727             dst src1 float-4-rep %copy
728             dst src2 UNPCKLPS
729             src3 src4 UNPCKLPS
730             dst src3 MOVLHPS
731         ] }
732         { int-4-rep [
733             dst src1 int-4-rep %copy
734             dst src2 PUNPCKLDQ
735             src3 src4 PUNPCKLDQ
736             dst src3 PUNPCKLQDQ
737         ] }
738     } case ;
739
740 M: x86 %gather-vector-4-reps
741     {
742         ! Can't do this with sse1 since it will want to unbox
743         ! double-precision floats and convert to single precision
744         { sse2? { float-4-rep int-4-rep uint-4-rep } }
745     } available-reps ;
746
747 M:: x86 %gather-int-vector-4 ( dst src1 src2 src3 src4 rep -- )
748     dst rep %zero-vector
749     dst src1 32-bit-version-of 0 PINSRD
750     dst src2 32-bit-version-of 1 PINSRD
751     dst src3 32-bit-version-of 2 PINSRD
752     dst src4 32-bit-version-of 3 PINSRD ;
753
754 M: x86 %gather-int-vector-4-reps
755     {
756         { sse4.1? { int-4-rep uint-4-rep } }
757     } available-reps ;
758
759 M:: x86 %gather-vector-2 ( dst src1 src2 rep -- )
760     rep signed-rep {
761         { double-2-rep [
762             dst src1 double-2-rep %copy
763             dst src2 MOVLHPS
764         ] }
765         { longlong-2-rep [
766             dst src1 longlong-2-rep %copy
767             dst src2 PUNPCKLQDQ
768         ] }
769     } case ;
770
771 M: x86 %gather-vector-2-reps
772     {
773         { sse2? { double-2-rep longlong-2-rep ulonglong-2-rep } }
774     } available-reps ;
775
776 M:: x86.64 %gather-int-vector-2 ( dst src1 src2 rep -- )
777     dst rep %zero-vector
778     dst src1 0 PINSRQ
779     dst src2 1 PINSRQ ;
780
781 M: x86.64 %gather-int-vector-2-reps
782     {
783         { sse4.1? { longlong-2-rep ulonglong-2-rep } }
784     } available-reps ;
785
786 : sse1-float-4-shuffle ( dst shuffle -- )
787     {
788         { { 0 1 2 3 } [ drop ] }
789         { { 0 1 0 1 } [ dup MOVLHPS ] }
790         { { 2 3 2 3 } [ dup MOVHLPS ] }
791         { { 0 0 1 1 } [ dup UNPCKLPS ] }
792         { { 2 2 3 3 } [ dup UNPCKHPS ] }
793         [ dupd SHUFPS ]
794     } case ;
795
796 : float-4-shuffle ( dst shuffle -- )
797     sse3? [
798         {
799             { { 0 0 2 2 } [ dup MOVSLDUP ] }
800             { { 1 1 3 3 } [ dup MOVSHDUP ] }
801             [ sse1-float-4-shuffle ]
802         } case
803     ] [ sse1-float-4-shuffle ] if ;
804
805 : int-4-shuffle ( dst shuffle -- )
806     {
807         { { 0 1 2 3 } [ drop ] }
808         { { 0 0 1 1 } [ dup PUNPCKLDQ ] }
809         { { 2 2 3 3 } [ dup PUNPCKHDQ ] }
810         { { 0 1 0 1 } [ dup PUNPCKLQDQ ] }
811         { { 2 3 2 3 } [ dup PUNPCKHQDQ ] }
812         [ dupd PSHUFD ]
813     } case ;
814
815 : longlong-2-shuffle ( dst shuffle -- )
816     first2 [ 2 * dup 1 + ] bi@ 4array int-4-shuffle ;
817
818 : >float-4-shuffle ( double-2-shuffle -- float-4-shuffle )
819     [ 2 * { 0 1 } n+v ] map concat ;
820
821 M:: x86 %shuffle-vector-imm ( dst src shuffle rep -- )
822     dst src rep %copy
823     dst shuffle rep signed-rep {
824         { double-2-rep [ >float-4-shuffle float-4-shuffle ] }
825         { float-4-rep [ float-4-shuffle ] }
826         { int-4-rep [ int-4-shuffle ] }
827         { longlong-2-rep [ longlong-2-shuffle ] }
828     } case ;
829
830 M: x86 %shuffle-vector-imm-reps
831     {
832         { sse? { float-4-rep } }
833         { sse2? { double-2-rep int-4-rep uint-4-rep longlong-2-rep ulonglong-2-rep } }
834     } available-reps ;
835
836 M:: x86 %shuffle-vector-halves-imm ( dst src1 src2 shuffle rep -- )
837     dst src1 src2 rep two-operand
838     shuffle rep {
839         { double-2-rep [ >float-4-shuffle SHUFPS ] }
840         { float-4-rep [ SHUFPS ] }
841     } case ;
842
843 M: x86 %shuffle-vector-halves-imm-reps
844     {
845         { sse? { float-4-rep } }
846         { sse2? { double-2-rep } }
847     } available-reps ;
848
849 M: x86 %shuffle-vector ( dst src shuffle rep -- )
850     two-operand PSHUFB ;
851
852 M: x86 %shuffle-vector-reps
853     {
854         { ssse3? { float-4-rep double-2-rep longlong-2-rep ulonglong-2-rep int-4-rep uint-4-rep short-8-rep ushort-8-rep char-16-rep uchar-16-rep } }
855     } available-reps ;
856
857 M: x86 %merge-vector-head
858     [ two-operand ] keep
859     signed-rep {
860         { double-2-rep   [ MOVLHPS ] }
861         { float-4-rep    [ UNPCKLPS ] }
862         { longlong-2-rep [ PUNPCKLQDQ ] }
863         { int-4-rep      [ PUNPCKLDQ ] }
864         { short-8-rep    [ PUNPCKLWD ] }
865         { char-16-rep    [ PUNPCKLBW ] }
866     } case ;
867
868 M: x86 %merge-vector-tail
869     [ two-operand ] keep
870     signed-rep {
871         { double-2-rep   [ UNPCKHPD ] }
872         { float-4-rep    [ UNPCKHPS ] }
873         { longlong-2-rep [ PUNPCKHQDQ ] }
874         { int-4-rep      [ PUNPCKHDQ ] }
875         { short-8-rep    [ PUNPCKHWD ] }
876         { char-16-rep    [ PUNPCKHBW ] }
877     } case ;
878
879 M: x86 %merge-vector-reps
880     {
881         { sse? { float-4-rep } }
882         { sse2? { double-2-rep char-16-rep uchar-16-rep short-8-rep ushort-8-rep int-4-rep uint-4-rep longlong-2-rep ulonglong-2-rep } }
883     } available-reps ;
884
885 M: x86 %signed-pack-vector
886     [ two-operand ] keep
887     {
888         { int-4-rep    [ PACKSSDW ] }
889         { short-8-rep  [ PACKSSWB ] }
890     } case ;
891
892 M: x86 %signed-pack-vector-reps
893     {
894         { sse2? { short-8-rep int-4-rep } }
895     } available-reps ;
896
897 M: x86 %unsigned-pack-vector
898     [ two-operand ] keep
899     signed-rep {
900         { int-4-rep   [ PACKUSDW ] }
901         { short-8-rep [ PACKUSWB ] }
902     } case ;
903
904 M: x86 %unsigned-pack-vector-reps
905     {
906         { sse2? { short-8-rep } }
907         { sse4.1? { int-4-rep } }
908     } available-reps ;
909
910 M: x86 %tail>head-vector ( dst src rep -- )
911     dup {
912         { float-4-rep [ drop UNPCKHPD ] }
913         { double-2-rep [ drop UNPCKHPD ] }
914         [ drop [ %copy ] [ drop PUNPCKHQDQ ] 3bi ]
915     } case ;
916
917 M: x86 %unpack-vector-head ( dst src rep -- )
918     {
919         { char-16-rep  [ PMOVSXBW ] }
920         { uchar-16-rep [ PMOVZXBW ] }
921         { short-8-rep  [ PMOVSXWD ] }
922         { ushort-8-rep [ PMOVZXWD ] }
923         { int-4-rep    [ PMOVSXDQ ] }
924         { uint-4-rep   [ PMOVZXDQ ] }
925         { float-4-rep  [ CVTPS2PD ] }
926     } case ;
927
928 M: x86 %unpack-vector-head-reps ( -- reps )
929     {
930         { sse2? { float-4-rep } }
931         { sse4.1? { char-16-rep uchar-16-rep short-8-rep ushort-8-rep int-4-rep uint-4-rep } }
932     } available-reps ;
933
934 M: x86 %integer>float-vector ( dst src rep -- )
935     {
936         { int-4-rep [ CVTDQ2PS ] }
937     } case ;
938
939 M: x86 %integer>float-vector-reps
940     {
941         { sse2? { int-4-rep } }
942     } available-reps ;
943
944 M: x86 %float>integer-vector ( dst src rep -- )
945     {
946         { float-4-rep [ CVTTPS2DQ ] }
947     } case ;
948
949 M: x86 %float>integer-vector-reps
950     {
951         { sse2? { float-4-rep } }
952     } available-reps ;
953
954 : (%compare-float-vector) ( dst src rep double single -- )
955     [ double-2-rep eq? ] 2dip if ; inline
956
957 : %compare-float-vector ( dst src rep cc -- )
958     {
959         { cc<    [ [ CMPLTPD    ] [ CMPLTPS    ] (%compare-float-vector) ] }
960         { cc<=   [ [ CMPLEPD    ] [ CMPLEPS    ] (%compare-float-vector) ] }
961         { cc=    [ [ CMPEQPD    ] [ CMPEQPS    ] (%compare-float-vector) ] }
962         { cc<>=  [ [ CMPORDPD   ] [ CMPORDPS   ] (%compare-float-vector) ] }
963         { cc/<   [ [ CMPNLTPD   ] [ CMPNLTPS   ] (%compare-float-vector) ] }
964         { cc/<=  [ [ CMPNLEPD   ] [ CMPNLEPS   ] (%compare-float-vector) ] }
965         { cc/=   [ [ CMPNEQPD   ] [ CMPNEQPS   ] (%compare-float-vector) ] }
966         { cc/<>= [ [ CMPUNORDPD ] [ CMPUNORDPS ] (%compare-float-vector) ] }
967     } case ;
968
969 :: (%compare-int-vector) ( dst src rep int64 int32 int16 int8 -- )
970     rep signed-rep :> rep'
971     dst src rep' {
972         { longlong-2-rep [ int64 call ] }
973         { int-4-rep      [ int32 call ] }
974         { short-8-rep    [ int16 call ] }
975         { char-16-rep    [ int8  call ] }
976     } case ; inline
977
978 : %compare-int-vector ( dst src rep cc -- )
979     {
980         { cc= [ [ PCMPEQQ ] [ PCMPEQD ] [ PCMPEQW ] [ PCMPEQB ] (%compare-int-vector) ] }
981         { cc> [ [ PCMPGTQ ] [ PCMPGTD ] [ PCMPGTW ] [ PCMPGTB ] (%compare-int-vector) ] }
982     } case ;
983
984 M: x86 %compare-vector ( dst src1 src2 rep cc -- )
985     [ [ two-operand ] keep ] dip
986     over float-vector-rep?
987     [ %compare-float-vector ]
988     [ %compare-int-vector ] if ;
989
990 : %compare-vector-eq-reps ( -- reps )
991     {
992         { sse? { float-4-rep } }
993         { sse2? { double-2-rep char-16-rep uchar-16-rep short-8-rep ushort-8-rep int-4-rep uint-4-rep } }
994         { sse4.1? { longlong-2-rep ulonglong-2-rep } }
995     } available-reps ;
996
997 : %compare-vector-ord-reps ( -- reps )
998     {
999         { sse? { float-4-rep } }
1000         { sse2? { double-2-rep char-16-rep short-8-rep int-4-rep } }
1001         { sse4.2? { longlong-2-rep } }
1002     } available-reps ;
1003
1004 M: x86 %compare-vector-reps
1005     {
1006         { [ dup { cc= cc/= cc/<>= cc<>= } member-eq? ] [ drop %compare-vector-eq-reps ] }
1007         [ drop %compare-vector-ord-reps ]
1008     } cond ;
1009
1010 : %compare-float-vector-ccs ( cc -- ccs not? )
1011     {
1012         { cc<    [ { { cc<  f   }              } f ] }
1013         { cc<=   [ { { cc<= f   }              } f ] }
1014         { cc>    [ { { cc<  t   }              } f ] }
1015         { cc>=   [ { { cc<= t   }              } f ] }
1016         { cc=    [ { { cc=  f   }              } f ] }
1017         { cc<>   [ { { cc<  f   } { cc<    t } } f ] }
1018         { cc<>=  [ { { cc<>= f  }              } f ] }
1019         { cc/<   [ { { cc/<  f  }              } f ] }
1020         { cc/<=  [ { { cc/<= f  }              } f ] }
1021         { cc/>   [ { { cc/<  t  }              } f ] }
1022         { cc/>=  [ { { cc/<= t  }              } f ] }
1023         { cc/=   [ { { cc/=  f  }              } f ] }
1024         { cc/<>  [ { { cc/=  f  } { cc/<>= f } } f ] }
1025         { cc/<>= [ { { cc/<>= f }              } f ] }
1026     } case ;
1027
1028 : %compare-int-vector-ccs ( cc -- ccs not? )
1029     order-cc {
1030         { cc<    [ { { cc> t } } f ] }
1031         { cc<=   [ { { cc> f } } t ] }
1032         { cc>    [ { { cc> f } } f ] }
1033         { cc>=   [ { { cc> t } } t ] }
1034         { cc=    [ { { cc= f } } f ] }
1035         { cc/=   [ { { cc= f } } t ] }
1036         { t      [ {           } t ] }
1037         { f      [ {           } f ] }
1038     } case ;
1039
1040 M: x86 %compare-vector-ccs
1041     swap float-vector-rep?
1042     [ %compare-float-vector-ccs ]
1043     [ %compare-int-vector-ccs ] if ;
1044
1045 :: %test-vector-mask ( dst temp mask vcc -- )
1046     vcc {
1047         { vcc-any    [ dst dst TEST dst temp \ CMOVNE (%boolean) ] }
1048         { vcc-none   [ dst dst TEST dst temp \ CMOVE  (%boolean) ] }
1049         { vcc-all    [ dst mask CMP dst temp \ CMOVE  (%boolean) ] }
1050         { vcc-notall [ dst mask CMP dst temp \ CMOVNE (%boolean) ] }
1051     } case ;
1052
1053 : %move-vector-mask ( dst src rep -- mask )
1054     {
1055         { double-2-rep [ MOVMSKPS HEX: f ] }
1056         { float-4-rep  [ MOVMSKPS HEX: f ] }
1057         [ drop PMOVMSKB HEX: ffff ]
1058     } case ;
1059
1060 M:: x86 %test-vector ( dst src temp rep vcc -- )
1061     dst src rep %move-vector-mask :> mask
1062     dst temp mask vcc %test-vector-mask ;
1063
1064 :: %test-vector-mask-branch ( label temp mask vcc -- )
1065     vcc {
1066         { vcc-any    [ temp temp TEST label JNE ] }
1067         { vcc-none   [ temp temp TEST label JE ] }
1068         { vcc-all    [ temp mask CMP label JE ] }
1069         { vcc-notall [ temp mask CMP label JNE ] }
1070     } case ;
1071
1072 M:: x86 %test-vector-branch ( label src temp rep vcc -- )
1073     temp src rep %move-vector-mask :> mask
1074     label temp mask vcc %test-vector-mask-branch ;
1075
1076 M: x86 %test-vector-reps
1077     {
1078         { sse? { float-4-rep } }
1079         { sse2? { double-2-rep char-16-rep uchar-16-rep short-8-rep ushort-8-rep int-4-rep uint-4-rep longlong-2-rep ulonglong-2-rep } }
1080     } available-reps ;
1081
1082 M: x86 %add-vector ( dst src1 src2 rep -- )
1083     [ two-operand ] keep
1084     {
1085         { float-4-rep [ ADDPS ] }
1086         { double-2-rep [ ADDPD ] }
1087         { char-16-rep [ PADDB ] }
1088         { uchar-16-rep [ PADDB ] }
1089         { short-8-rep [ PADDW ] }
1090         { ushort-8-rep [ PADDW ] }
1091         { int-4-rep [ PADDD ] }
1092         { uint-4-rep [ PADDD ] }
1093         { longlong-2-rep [ PADDQ ] }
1094         { ulonglong-2-rep [ PADDQ ] }
1095     } case ;
1096
1097 M: x86 %add-vector-reps
1098     {
1099         { sse? { float-4-rep } }
1100         { sse2? { double-2-rep char-16-rep uchar-16-rep short-8-rep ushort-8-rep int-4-rep uint-4-rep longlong-2-rep ulonglong-2-rep } }
1101     } available-reps ;
1102
1103 M: x86 %saturated-add-vector ( dst src1 src2 rep -- )
1104     [ two-operand ] keep
1105     {
1106         { char-16-rep [ PADDSB ] }
1107         { uchar-16-rep [ PADDUSB ] }
1108         { short-8-rep [ PADDSW ] }
1109         { ushort-8-rep [ PADDUSW ] }
1110     } case ;
1111
1112 M: x86 %saturated-add-vector-reps
1113     {
1114         { sse2? { char-16-rep uchar-16-rep short-8-rep ushort-8-rep } }
1115     } available-reps ;
1116
1117 M: x86 %add-sub-vector ( dst src1 src2 rep -- )
1118     [ two-operand ] keep
1119     {
1120         { float-4-rep [ ADDSUBPS ] }
1121         { double-2-rep [ ADDSUBPD ] }
1122     } case ;
1123
1124 M: x86 %add-sub-vector-reps
1125     {
1126         { sse3? { float-4-rep double-2-rep } }
1127     } available-reps ;
1128
1129 M: x86 %sub-vector ( dst src1 src2 rep -- )
1130     [ two-operand ] keep
1131     {
1132         { float-4-rep [ SUBPS ] }
1133         { double-2-rep [ SUBPD ] }
1134         { char-16-rep [ PSUBB ] }
1135         { uchar-16-rep [ PSUBB ] }
1136         { short-8-rep [ PSUBW ] }
1137         { ushort-8-rep [ PSUBW ] }
1138         { int-4-rep [ PSUBD ] }
1139         { uint-4-rep [ PSUBD ] }
1140         { longlong-2-rep [ PSUBQ ] }
1141         { ulonglong-2-rep [ PSUBQ ] }
1142     } case ;
1143
1144 M: x86 %sub-vector-reps
1145     {
1146         { sse? { float-4-rep } }
1147         { sse2? { double-2-rep char-16-rep uchar-16-rep short-8-rep ushort-8-rep int-4-rep uint-4-rep longlong-2-rep ulonglong-2-rep } }
1148     } available-reps ;
1149
1150 M: x86 %saturated-sub-vector ( dst src1 src2 rep -- )
1151     [ two-operand ] keep
1152     {
1153         { char-16-rep [ PSUBSB ] }
1154         { uchar-16-rep [ PSUBUSB ] }
1155         { short-8-rep [ PSUBSW ] }
1156         { ushort-8-rep [ PSUBUSW ] }
1157     } case ;
1158
1159 M: x86 %saturated-sub-vector-reps
1160     {
1161         { sse2? { char-16-rep uchar-16-rep short-8-rep ushort-8-rep } }
1162     } available-reps ;
1163
1164 M: x86 %mul-vector ( dst src1 src2 rep -- )
1165     [ two-operand ] keep
1166     {
1167         { float-4-rep [ MULPS ] }
1168         { double-2-rep [ MULPD ] }
1169         { short-8-rep [ PMULLW ] }
1170         { ushort-8-rep [ PMULLW ] }
1171         { int-4-rep [ PMULLD ] }
1172         { uint-4-rep [ PMULLD ] }
1173     } case ;
1174
1175 M: x86 %mul-vector-reps
1176     {
1177         { sse? { float-4-rep } }
1178         { sse2? { double-2-rep short-8-rep ushort-8-rep } }
1179         { sse4.1? { int-4-rep uint-4-rep } }
1180     } available-reps ;
1181
1182 M: x86 %mul-high-vector ( dst src1 src2 rep -- )
1183     [ two-operand ] keep
1184     {
1185         { short-8-rep  [ PMULHW ] }
1186         { ushort-8-rep [ PMULHUW ] }
1187     } case ;
1188
1189 M: x86 %mul-high-vector-reps
1190     {
1191         { sse2? { short-8-rep ushort-8-rep } }
1192     } available-reps ;
1193
1194 M: x86 %mul-horizontal-add-vector ( dst src1 src2 rep -- )
1195     [ two-operand ] keep
1196     {
1197         { char-16-rep  [ PMADDUBSW ] }
1198         { uchar-16-rep [ PMADDUBSW ] }
1199         { short-8-rep  [ PMADDWD ] }
1200     } case ;
1201
1202 M: x86 %mul-horizontal-add-vector-reps
1203     {
1204         { sse2?  { short-8-rep } }
1205         { ssse3? { char-16-rep uchar-16-rep } }
1206     } available-reps ;
1207
1208 M: x86 %div-vector ( dst src1 src2 rep -- )
1209     [ two-operand ] keep
1210     {
1211         { float-4-rep [ DIVPS ] }
1212         { double-2-rep [ DIVPD ] }
1213     } case ;
1214
1215 M: x86 %div-vector-reps
1216     {
1217         { sse? { float-4-rep } }
1218         { sse2? { double-2-rep } }
1219     } available-reps ;
1220
1221 M: x86 %min-vector ( dst src1 src2 rep -- )
1222     [ two-operand ] keep
1223     {
1224         { char-16-rep [ PMINSB ] }
1225         { uchar-16-rep [ PMINUB ] }
1226         { short-8-rep [ PMINSW ] }
1227         { ushort-8-rep [ PMINUW ] }
1228         { int-4-rep [ PMINSD ] }
1229         { uint-4-rep [ PMINUD ] }
1230         { float-4-rep [ MINPS ] }
1231         { double-2-rep [ MINPD ] }
1232     } case ;
1233
1234 M: x86 %min-vector-reps
1235     {
1236         { sse? { float-4-rep } }
1237         { sse2? { uchar-16-rep short-8-rep double-2-rep } }
1238         { sse4.1? { char-16-rep ushort-8-rep int-4-rep uint-4-rep } }
1239     } available-reps ;
1240
1241 M: x86 %max-vector ( dst src1 src2 rep -- )
1242     [ two-operand ] keep
1243     {
1244         { char-16-rep [ PMAXSB ] }
1245         { uchar-16-rep [ PMAXUB ] }
1246         { short-8-rep [ PMAXSW ] }
1247         { ushort-8-rep [ PMAXUW ] }
1248         { int-4-rep [ PMAXSD ] }
1249         { uint-4-rep [ PMAXUD ] }
1250         { float-4-rep [ MAXPS ] }
1251         { double-2-rep [ MAXPD ] }
1252     } case ;
1253
1254 M: x86 %max-vector-reps
1255     {
1256         { sse? { float-4-rep } }
1257         { sse2? { uchar-16-rep short-8-rep double-2-rep } }
1258         { sse4.1? { char-16-rep ushort-8-rep int-4-rep uint-4-rep } }
1259     } available-reps ;
1260
1261 M: x86 %avg-vector ( dst src1 src2 rep -- )
1262     [ two-operand ] keep
1263     {
1264         { uchar-16-rep [ PAVGB ] }
1265         { ushort-8-rep [ PAVGW ] }
1266     } case ;
1267
1268 M: x86 %avg-vector-reps
1269     {
1270         { sse2? { uchar-16-rep ushort-8-rep } }
1271     } available-reps ;
1272
1273 M: x86 %dot-vector
1274     [ two-operand ] keep
1275     {
1276         { float-4-rep [ HEX: ff DPPS ] }
1277         { double-2-rep [ HEX: ff DPPD ] }
1278     } case ;
1279
1280 M: x86 %dot-vector-reps
1281     {
1282         { sse4.1? { float-4-rep double-2-rep } }
1283     } available-reps ;
1284
1285 M: x86 %sad-vector
1286     [ two-operand ] keep
1287     {
1288         { uchar-16-rep [ PSADBW ] }
1289     } case ;
1290
1291 M: x86 %sad-vector-reps
1292     {
1293         { sse2? { uchar-16-rep } }
1294     } available-reps ;
1295
1296 M: x86 %horizontal-add-vector ( dst src1 src2 rep -- )
1297     [ two-operand ] keep
1298     signed-rep {
1299         { float-4-rep  [ HADDPS ] }
1300         { double-2-rep [ HADDPD ] }
1301         { int-4-rep    [ PHADDD ] }
1302         { short-8-rep  [ PHADDW ] }
1303     } case ;
1304
1305 M: x86 %horizontal-add-vector-reps
1306     {
1307         { sse3? { float-4-rep double-2-rep } }
1308         { ssse3? { int-4-rep uint-4-rep short-8-rep ushort-8-rep } }
1309     } available-reps ;
1310
1311 M: x86 %horizontal-shl-vector-imm ( dst src1 src2 rep -- )
1312     two-operand PSLLDQ ;
1313
1314 M: x86 %horizontal-shl-vector-imm-reps
1315     {
1316         { sse2? { char-16-rep uchar-16-rep short-8-rep ushort-8-rep int-4-rep uint-4-rep longlong-2-rep ulonglong-2-rep float-4-rep double-2-rep } }
1317     } available-reps ;
1318
1319 M: x86 %horizontal-shr-vector-imm ( dst src1 src2 rep -- )
1320     two-operand PSRLDQ ;
1321
1322 M: x86 %horizontal-shr-vector-imm-reps
1323     {
1324         { sse2? { char-16-rep uchar-16-rep short-8-rep ushort-8-rep int-4-rep uint-4-rep longlong-2-rep ulonglong-2-rep float-4-rep double-2-rep } }
1325     } available-reps ;
1326
1327 M: x86 %abs-vector ( dst src rep -- )
1328     {
1329         { char-16-rep [ PABSB ] }
1330         { short-8-rep [ PABSW ] }
1331         { int-4-rep [ PABSD ] }
1332     } case ;
1333
1334 M: x86 %abs-vector-reps
1335     {
1336         { ssse3? { char-16-rep short-8-rep int-4-rep } }
1337     } available-reps ;
1338
1339 M: x86 %sqrt-vector ( dst src rep -- )
1340     {
1341         { float-4-rep [ SQRTPS ] }
1342         { double-2-rep [ SQRTPD ] }
1343     } case ;
1344
1345 M: x86 %sqrt-vector-reps
1346     {
1347         { sse? { float-4-rep } }
1348         { sse2? { double-2-rep } }
1349     } available-reps ;
1350
1351 M: x86 %and-vector ( dst src1 src2 rep -- )
1352     [ two-operand ] keep
1353     {
1354         { float-4-rep [ ANDPS ] }
1355         { double-2-rep [ ANDPS ] }
1356         [ drop PAND ]
1357     } case ;
1358
1359 M: x86 %and-vector-reps
1360     {
1361         { sse? { float-4-rep } }
1362         { sse2? { double-2-rep char-16-rep uchar-16-rep short-8-rep ushort-8-rep int-4-rep uint-4-rep longlong-2-rep ulonglong-2-rep } }
1363     } available-reps ;
1364
1365 M: x86 %andn-vector ( dst src1 src2 rep -- )
1366     [ two-operand ] keep
1367     {
1368         { float-4-rep [ ANDNPS ] }
1369         { double-2-rep [ ANDNPS ] }
1370         [ drop PANDN ]
1371     } case ;
1372
1373 M: x86 %andn-vector-reps
1374     {
1375         { sse? { float-4-rep } }
1376         { sse2? { double-2-rep char-16-rep uchar-16-rep short-8-rep ushort-8-rep int-4-rep uint-4-rep longlong-2-rep ulonglong-2-rep } }
1377     } available-reps ;
1378
1379 M: x86 %or-vector ( dst src1 src2 rep -- )
1380     [ two-operand ] keep
1381     {
1382         { float-4-rep [ ORPS ] }
1383         { double-2-rep [ ORPS ] }
1384         [ drop POR ]
1385     } case ;
1386
1387 M: x86 %or-vector-reps
1388     {
1389         { sse? { float-4-rep } }
1390         { sse2? { double-2-rep char-16-rep uchar-16-rep short-8-rep ushort-8-rep int-4-rep uint-4-rep longlong-2-rep ulonglong-2-rep } }
1391     } available-reps ;
1392
1393 M: x86 %xor-vector ( dst src1 src2 rep -- )
1394     [ two-operand ] keep
1395     {
1396         { float-4-rep [ XORPS ] }
1397         { double-2-rep [ XORPS ] }
1398         [ drop PXOR ]
1399     } case ;
1400
1401 M: x86 %xor-vector-reps
1402     {
1403         { sse? { float-4-rep } }
1404         { sse2? { double-2-rep char-16-rep uchar-16-rep short-8-rep ushort-8-rep int-4-rep uint-4-rep longlong-2-rep ulonglong-2-rep } }
1405     } available-reps ;
1406
1407 M: x86 %shl-vector ( dst src1 src2 rep -- )
1408     [ two-operand ] keep
1409     {
1410         { short-8-rep [ PSLLW ] }
1411         { ushort-8-rep [ PSLLW ] }
1412         { int-4-rep [ PSLLD ] }
1413         { uint-4-rep [ PSLLD ] }
1414         { longlong-2-rep [ PSLLQ ] }
1415         { ulonglong-2-rep [ PSLLQ ] }
1416     } case ;
1417
1418 M: x86 %shl-vector-reps
1419     {
1420         { sse2? { short-8-rep ushort-8-rep int-4-rep uint-4-rep longlong-2-rep ulonglong-2-rep } }
1421     } available-reps ;
1422
1423 M: x86 %shr-vector ( dst src1 src2 rep -- )
1424     [ two-operand ] keep
1425     {
1426         { short-8-rep [ PSRAW ] }
1427         { ushort-8-rep [ PSRLW ] }
1428         { int-4-rep [ PSRAD ] }
1429         { uint-4-rep [ PSRLD ] }
1430         { ulonglong-2-rep [ PSRLQ ] }
1431     } case ;
1432
1433 M: x86 %shr-vector-reps
1434     {
1435         { sse2? { short-8-rep ushort-8-rep int-4-rep uint-4-rep ulonglong-2-rep } }
1436     } available-reps ;
1437
1438 M: x86 %shl-vector-imm %shl-vector ;
1439 M: x86 %shl-vector-imm-reps %shl-vector-reps ;
1440 M: x86 %shr-vector-imm %shr-vector ;
1441 M: x86 %shr-vector-imm-reps %shr-vector-reps ;
1442
1443 : scalar-sized-reg ( reg rep -- reg' )
1444     rep-size 8 * n-bit-version-of ;
1445
1446 M: x86 %integer>scalar drop MOVD ;
1447
1448 :: %scalar>integer-32 ( dst src rep -- )
1449     rep {
1450         { int-scalar-rep [
1451             dst 32-bit-version-of src MOVD
1452             dst dst 32-bit-version-of
1453             2dup eq? [ 2drop ] [ MOVSX ] if
1454         ] }
1455         { uint-scalar-rep [
1456             dst 32-bit-version-of src MOVD
1457         ] }
1458         { short-scalar-rep [
1459             dst 32-bit-version-of src MOVD
1460             dst dst 16-bit-version-of MOVSX
1461         ] }
1462         { ushort-scalar-rep [
1463             dst 32-bit-version-of src MOVD
1464             dst dst 16-bit-version-of MOVZX
1465         ] }
1466         { char-scalar-rep [
1467             dst 32-bit-version-of src MOVD
1468             dst { } 8 [| tmp-dst |
1469                 tmp-dst dst int-rep %copy
1470                 tmp-dst tmp-dst 8-bit-version-of MOVSX
1471                 dst tmp-dst int-rep %copy
1472             ] with-small-register
1473         ] }
1474         { uchar-scalar-rep [
1475             dst 32-bit-version-of src MOVD
1476             dst { } 8 [| tmp-dst |
1477                 tmp-dst dst int-rep %copy
1478                 tmp-dst tmp-dst 8-bit-version-of MOVZX
1479                 dst tmp-dst int-rep %copy
1480             ] with-small-register
1481         ] }
1482     } case ;
1483
1484 M: x86.32 %scalar>integer ( dst src rep -- ) %scalar>integer-32 ;
1485
1486 M: x86.64 %scalar>integer ( dst src rep -- )
1487     {
1488         { longlong-scalar-rep  [ MOVD ] }
1489         { ulonglong-scalar-rep [ MOVD ] }
1490         [ %scalar>integer-32 ]
1491     } case ;
1492
1493 M: x86 %vector>scalar %copy ;
1494
1495 M: x86 %scalar>vector %copy ;
1496
1497 M:: x86 %spill ( src rep dst -- )
1498     dst src rep %copy ;
1499
1500 M:: x86 %reload ( dst rep src -- )
1501     dst src rep %copy ;
1502
1503 M:: x86 %store-reg-param ( src reg rep -- )
1504     reg src rep %copy ;
1505
1506 M:: x86 %store-stack-param ( src n rep -- )
1507     n param@ src rep %copy ;
1508
1509 HOOK: struct-return@ cpu ( n -- operand )
1510
1511 M: x86 %prepare-struct-area ( dst -- )
1512     f struct-return@ LEA ;
1513
1514 M: x86 %alien-indirect ( src -- )
1515     ?spill-slot CALL ;
1516
1517 M: x86 %loop-entry 16 alignment [ NOP ] times ;
1518
1519 M:: x86 %restore-context ( temp1 temp2 -- )
1520     #! Load Factor stack pointers on entry from C to Factor.
1521     temp1 %context
1522     ds-reg temp1 "datastack" context-field-offset [+] MOV
1523     rs-reg temp1 "retainstack" context-field-offset [+] MOV ;
1524
1525 M:: x86 %save-context ( temp1 temp2 -- )
1526     #! Save Factor stack pointers in case the C code calls a
1527     #! callback which does a GC, which must reliably trace
1528     #! all roots.
1529     temp1 %context
1530     temp2 stack-reg cell neg [+] LEA
1531     temp1 "callstack-top" context-field-offset [+] temp2 MOV
1532     temp1 "datastack" context-field-offset [+] ds-reg MOV
1533     temp1 "retainstack" context-field-offset [+] rs-reg MOV ;
1534
1535 M: x86 value-struct? drop t ;
1536
1537 M: x86 immediate-arithmetic? ( n -- ? )
1538     HEX: -80000000 HEX: 7fffffff between? ;
1539
1540 M: x86 immediate-bitwise? ( n -- ? )
1541     HEX: -80000000 HEX: 7fffffff between? ;
1542
1543 : next-stack@ ( n -- operand )
1544     #! nth parameter from the next stack frame. Used to box
1545     #! input values to callbacks; the callback has its own
1546     #! stack frame set up, and we want to read the frame
1547     #! set up by the caller.
1548     frame-reg swap 2 cells + [+] ;
1549
1550 enable-min/max
1551 enable-log2
1552
1553 enable-float-intrinsics
1554 enable-float-functions
1555 enable-float-min/max
1556 enable-fsqrt
1557
1558 : check-sse ( -- )
1559     [ { (sse-version) popcnt? } compile ] with-optimizer
1560     sse-version 20 < [
1561         "Factor requires SSE2, which your CPU does not support." print
1562         flush
1563         1 exit
1564     ] when ;