1 ! Copyright (C) 2005, 2006 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: alien arrays cpu.x86.assembler cpu.x86.allot
4 cpu.x86.architecture cpu.architecture kernel kernel.private math
5 math.functions math.private namespaces quotations sequences
6 words generic byte-arrays hashtables hashtables.private
7 generator generator.registers generator.fixup sequences.private
8 sbufs sbufs.private vectors vectors.private layouts system
9 tuples.private strings.private slots.private ;
10 IN: cpu.x86.intrinsics
14 "in" operand tag-mask get AND
15 "in" operand %tag-fixnum
17 { +input+ { { f "in" } } }
24 "x" operand "obj" operand MOV
26 "x" operand tag-mask get AND
28 "x" operand %tag-fixnum
29 ! Compare with object tag number (3).
30 "x" operand object tag-number tag-bits get shift CMP
32 ! If we have equality, load type from header
33 "x" operand "obj" operand -3 [+] MOV
36 { +input+ { { f "obj" } } }
37 { +scratch+ { { f "x" } } }
46 "x" operand "obj" operand MOV
48 "x" operand tag-mask get AND
50 "x" operand %tag-fixnum
51 ! Compare with tuple tag number (2).
52 "x" operand tuple tag-number tag-bits get shift CMP
54 ! Compare with object tag number (3).
55 "x" operand object tag-number tag-bits get shift CMP
58 "object" get resolve-label
60 "x" operand "obj" operand header-offset [+] MOV
62 "tuple" get resolve-label
64 "x" operand "obj" operand tuple-class-offset [+] MOV
65 "x" operand dup class-hash-offset [+] MOV
68 { +input+ { { f "obj" } } }
69 { +scratch+ { { f "x" } } }
76 ! Slot number is literal
81 "obj" operand dup "n" get cells [+] MOV
83 { +input+ { { f "obj" } { [ small-slot? ] "n" } } }
84 { +output+ { "obj" } }
87 ! Slot number in a register
91 ! turn tagged fixnum slot # into an offset,
93 "n" operand fixnum>slot@
95 "obj" operand dup "n" operand [+] MOV
97 { +input+ { { f "obj" } { f "n" } } }
98 { +output+ { "obj" } }
104 : generate-write-barrier ( -- )
105 #! Mark the card pointed to by vreg.
106 "val" operand-immediate? "obj" get fresh-object? or [
107 "obj" operand card-bits SHR
108 "scratch" operand HEX: ffffffff MOV
109 "cards_offset" f rc-absolute-cell rel-dlsym
110 "scratch" operand dup [] MOV
111 "scratch" operand "obj" operand [+] card-mark OR
115 ! Slot number is literal
119 ! store new slot value
120 "obj" operand "n" get cells [+] "val" operand MOV
121 generate-write-barrier
123 { +input+ { { f "val" } { f "obj" } { [ small-slot? ] "n" } } }
124 { +scratch+ { { f "scratch" } } }
125 { +clobber+ { "obj" } }
128 ! Slot number in a register
131 ! turn tagged fixnum slot # into an offset
132 "n" operand fixnum>slot@
134 ! store new slot value
135 "obj" operand "n" operand [+] "val" operand MOV
137 "n" get "scratch" set
138 generate-write-barrier
140 { +input+ { { f "val" } { f "obj" } { f "n" } } }
141 { +clobber+ { "obj" "n" } }
146 ! Sometimes, we need to do stuff with operands which are
147 ! less than the word size. Instead of teaching the register
148 ! allocator about the different sized registers, with all
149 ! the complexity this entails, we just push/pop a register
150 ! which is guaranteed to be unused (the tempreg)
151 : small-reg cell 8 = RBX EBX ? ; inline
152 : small-reg-8 BL ; inline
153 : small-reg-16 BX ; inline
154 : small-reg-32 EBX ; inline
160 "obj" operand "n" operand ADD
161 small-reg-16 "obj" operand string-offset [+] MOV
162 small-reg %tag-fixnum
163 "obj" operand small-reg MOV
166 { +input+ { { f "n" } { f "obj" } } }
167 { +output+ { "obj" } }
168 { +clobber+ { "obj" "n" } }
173 "val" operand %untag-fixnum
175 "obj" operand "slot" operand ADD
176 small-reg "val" operand MOV
177 "obj" operand string-offset [+] small-reg-16 MOV
180 { +input+ { { f "val" } { f "slot" } { f "obj" } } }
181 { +clobber+ { "val" "slot" "obj" } }
185 : fixnum-op ( op hash -- pair )
186 >r [ "x" operand "y" operand ] swap add r> 2array ;
188 : fixnum-value-op ( op -- pair )
190 { +input+ { { f "x" } { [ small-tagged? ] "y" } } }
194 : fixnum-register-op ( op -- pair )
196 { +input+ { { f "x" } { f "y" } } }
200 : define-fixnum-op ( word op -- )
201 [ fixnum-value-op ] keep fixnum-register-op
202 2array define-intrinsics ;
207 { fixnum-bitand AND }
209 { fixnum-bitxor XOR }
211 first2 define-fixnum-op
216 "x" operand tag-mask get XOR
218 { +input+ { { f "x" } } }
225 "x" operand "y" get IMUL2
227 { +input+ { { f "x" } { [ small-tagged? ] "y" } } }
232 "out" operand "x" operand MOV
233 "out" operand %untag-fixnum
234 "y" operand "out" operand IMUL2
236 { +input+ { { f "x" } { f "y" } } }
237 { +scratch+ { { f "out" } } }
238 { +output+ { "out" } }
244 "x" operand "y" get neg SAR
248 { +input+ { { f "x" } { [ -31 0 between? ] "y" } } }
252 : %untag-fixnums ( seq -- )
253 [ %untag-fixnum ] unique-operands ;
255 : overflow-check ( word -- )
257 "z" operand "x" operand MOV
258 "z" operand "y" operand pick execute
259 ! If the previous arithmetic operation overflowed, then we
260 ! turn the result into a bignum and leave it in EAX.
262 ! There was an overflow. Recompute the original operand.
263 { "y" "x" } %untag-fixnums
264 "x" operand "y" operand rot execute
265 "z" get "x" get %allot-bignum-signed-1
266 "end" resolve-label ; inline
268 : overflow-template ( word insn -- )
269 [ overflow-check ] curry H{
270 { +input+ { { f "x" } { f "y" } } }
271 { +scratch+ { { f "z" } } }
273 { +clobber+ { "x" "y" } }
276 \ fixnum+ \ ADD overflow-template
277 \ fixnum- \ SUB overflow-template
279 : fixnum-jump ( op inputs -- pair )
280 >r [ "x" operand "y" operand CMP ] swap add r> 2array ;
282 : fixnum-value-jump ( op -- pair )
283 { { f "x" } { [ small-tagged? ] "y" } } fixnum-jump ;
285 : fixnum-register-jump ( op -- pair )
286 { { f "x" } { f "y" } } fixnum-jump ;
288 : define-fixnum-jump ( word op -- )
289 [ fixnum-value-jump ] keep fixnum-register-jump
290 2array define-if-intrinsics ;
299 first2 define-fixnum-jump
303 "x" operand %untag-fixnum
304 "x" get dup %allot-bignum-signed-1
306 { +input+ { { f "x" } } }
311 "nonzero" define-label
312 "positive" define-label
315 "y" operand "x" operand cell [+] MOV
316 ! if the length is 1, its just the sign and nothing else,
318 "y" operand 1 v>operand CMP
322 "nonzero" resolve-label
324 "y" operand "x" operand 3 cells [+] MOV
326 "x" operand "x" operand 2 cells [+] MOV
327 ! is the sign negative?
331 "positive" resolve-label
335 { +input+ { { f "x" } } }
336 { +scratch+ { { f "y" } } }
337 { +clobber+ { "x" } }
344 "userenv" f rc-absolute-cell rel-dlsym
345 "n" operand fixnum>slot@
346 "n" operand "x" operand ADD ;
349 %userenv "n" operand dup [] MOV
351 { +input+ { { f "n" } } }
352 { +scratch+ { { f "x" } } }
357 %userenv "n" operand [] "val" operand MOV
359 { +input+ { { f "val" } { f "n" } } }
360 { +scratch+ { { f "x" } } }
361 { +clobber+ { "n" } }
365 tuple "n" get 2 + cells [
367 1 object@ "n" operand MOV
369 2 object@ "class" operand MOV
370 ! Zero out the rest of the tuple
371 "n" operand 1- [ 3 + object@ f v>operand MOV ] each
372 ! Store tagged ptr in reg
373 "tuple" get tuple %store-tagged
376 { +input+ { { f "class" } { [ inline-array? ] "n" } } }
377 { +scratch+ { { f "tuple" } } }
378 { +output+ { "tuple" } }
382 array "n" get 2 + cells [
384 1 object@ "n" operand MOV
385 ! Zero out the rest of the tuple
386 "n" get [ 2 + object@ "initial" operand MOV ] each
387 ! Store tagged ptr in reg
388 "array" get object %store-tagged
391 { +input+ { { [ inline-array? ] "n" } { f "initial" } } }
392 { +scratch+ { { f "array" } } }
393 { +output+ { "array" } }
397 byte-array "n" get 2 cells + [
399 1 object@ "n" operand MOV
400 ! Store initial element
401 "n" get cell align cell /i [ 2 + object@ 0 MOV ] each
402 ! Store tagged ptr in reg
403 "array" get object %store-tagged
406 { +input+ { { [ inline-array? ] "n" } } }
407 { +scratch+ { { f "array" } } }
408 { +output+ { "array" } }
413 1 object@ "numerator" operand MOV
414 2 object@ "denominator" operand MOV
415 ! Store tagged ptr in reg
416 "ratio" get ratio %store-tagged
419 { +input+ { { f "numerator" } { f "denominator" } } }
420 { +scratch+ { { f "ratio" } } }
421 { +output+ { "ratio" } }
426 1 object@ "real" operand MOV
427 2 object@ "imaginary" operand MOV
428 ! Store tagged ptr in reg
429 "complex" get complex %store-tagged
432 { +input+ { { f "real" } { f "imaginary" } } }
433 { +scratch+ { { f "complex" } } }
434 { +output+ { "complex" } }
439 1 object@ "obj" operand MOV
440 ! Store tagged ptr in reg
441 "wrapper" get object %store-tagged
444 { +input+ { { f "obj" } } }
445 { +scratch+ { { f "wrapper" } } }
446 { +output+ { "wrapper" } }
451 1 object@ f v>operand MOV
452 2 object@ f v>operand MOV
453 3 object@ f v>operand MOV
454 ! Store tagged ptr in reg
455 "hashtable" get object %store-tagged
458 { +scratch+ { { f "hashtable" } } }
459 { +output+ { "hashtable" } }
464 1 object@ "length" operand MOV
465 2 object@ "string" operand MOV
466 ! Store tagged ptr in reg
467 "sbuf" get object %store-tagged
470 { +input+ { { f "string" } { f "length" } } }
471 { +scratch+ { { f "sbuf" } } }
472 { +output+ { "sbuf" } }
477 1 object@ "length" operand MOV
478 2 object@ "array" operand MOV
479 ! Store tagged ptr in reg
480 "vector" get object %store-tagged
483 { +input+ { { f "array" } { f "length" } } }
484 { +scratch+ { { f "vector" } } }
485 { +output+ { "vector" } }
490 1 object@ "obj" operand MOV
491 2 object@ "quot" operand MOV
492 ! Store tagged ptr in reg
493 "curry" get object %store-tagged
496 { +input+ { { f "obj" } { f "quot" } } }
497 { +scratch+ { { f "curry" } } }
498 { +output+ { "curry" } }
502 : %alien-integer-get ( quot reg -- )
504 "offset" operand %untag-fixnum
505 "alien" operand-class %alien-accessor
506 "offset" operand small-reg MOV
507 "offset" operand %tag-fixnum
508 small-reg POP ; inline
510 : alien-integer-get-template
513 { f "alien" simple-c-ptr }
514 { f "offset" fixnum }
516 { +output+ { "offset" } }
517 { +clobber+ { "alien" "offset" } }
521 [ %alien-integer-get ] 2curry
522 alien-integer-get-template
525 : define-unsigned-getter
526 [ small-reg dup XOR MOV ] swap define-getter ;
528 : define-signed-getter
529 [ [ >r MOV small-reg r> MOVSX ] curry ] keep define-getter ;
531 : %alien-integer-set ( quot reg -- )
533 { "offset" "value" } %untag-fixnums
534 small-reg "value" operand MOV
535 "alien" operand-class %alien-accessor
536 small-reg POP ; inline
538 : alien-integer-set-template
542 { f "alien" simple-c-ptr }
543 { f "offset" fixnum }
545 { +clobber+ { "value" "alien" "offset" } }
550 [ %alien-integer-set ] 2curry
551 alien-integer-set-template
554 \ alien-unsigned-1 small-reg-8 define-unsigned-getter
555 \ set-alien-unsigned-1 small-reg-8 define-setter
557 \ alien-signed-1 small-reg-8 define-signed-getter
558 \ set-alien-signed-1 small-reg-8 define-setter
560 \ alien-unsigned-2 small-reg-16 define-unsigned-getter
561 \ set-alien-unsigned-2 small-reg-16 define-setter
563 \ alien-signed-2 small-reg-16 define-signed-getter
564 \ set-alien-signed-2 small-reg-16 define-setter
567 "offset" operand %untag-fixnum
571 "alien" operand-class
574 "offset" get %allot-alien
575 ] alien-integer-get-template define-intrinsic