1 ! Copyright (C) 2005, 2008 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors alien alien.accessors arrays cpu.x86.assembler
4 cpu.x86.allot cpu.x86.architecture cpu.architecture kernel
5 kernel.private math 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 classes.tuple.private strings.private slots.private
11 IN: cpu.x86.intrinsics
15 "in" operand tag-mask get AND
16 "in" operand %tag-fixnum
18 { +input+ { { f "in" } } }
23 : %slot-literal-known-tag ( -- op )
26 "obj" get operand-tag - [+] ;
28 : %slot-literal-any-tag ( -- op )
30 "obj" operand "n" get cells [+] ;
34 "n" operand fixnum>slot@
35 "obj" operand "n" operand [+] ;
38 ! Slot number is literal and the tag is known
40 [ "val" operand %slot-literal-known-tag MOV ] H{
41 { +input+ { { f "obj" known-tag } { [ small-slot? ] "n" } } }
42 { +scratch+ { { f "val" } } }
43 { +output+ { "val" } }
46 ! Slot number is literal
48 [ "obj" operand %slot-literal-any-tag MOV ] H{
49 { +input+ { { f "obj" } { [ small-slot? ] "n" } } }
50 { +output+ { "obj" } }
53 ! Slot number in a register
55 [ "obj" operand %slot-any MOV ] H{
56 { +input+ { { f "obj" } { f "n" } } }
57 { +output+ { "obj" } }
63 : generate-write-barrier ( -- )
64 #! Mark the card pointed to by vreg.
65 "val" get operand-immediate? "obj" get fresh-object? or [
67 "obj" operand card-bits SHR
68 "cards_offset" f temp-reg v>operand %alien-global
69 temp-reg v>operand "obj" operand [+] card-mark <byte> MOV
72 "obj" operand deck-bits card-bits - SHR
73 "decks_offset" f temp-reg v>operand %alien-global
74 temp-reg v>operand "obj" operand [+] card-mark <byte> MOV
78 ! Slot number is literal and the tag is known
80 [ %slot-literal-known-tag "val" operand MOV generate-write-barrier ] H{
81 { +input+ { { f "val" } { f "obj" known-tag } { [ small-slot? ] "n" } } }
82 { +clobber+ { "obj" } }
85 ! Slot number is literal
87 [ %slot-literal-any-tag "val" operand MOV generate-write-barrier ] H{
88 { +input+ { { f "val" } { f "obj" } { [ small-slot? ] "n" } } }
89 { +clobber+ { "obj" } }
92 ! Slot number in a register
94 [ %slot-any "val" operand MOV generate-write-barrier ] H{
95 { +input+ { { f "val" } { f "obj" } { f "n" } } }
96 { +clobber+ { "obj" "n" } }
101 ! Sometimes, we need to do stuff with operands which are
102 ! less than the word size. Instead of teaching the register
103 ! allocator about the different sized registers, with all
104 ! the complexity this entails, we just push/pop a register
105 ! which is guaranteed to be unused (the tempreg)
106 : small-reg cell 8 = RBX EBX ? ; inline
107 : small-reg-8 BL ; inline
108 : small-reg-16 BX ; inline
109 : small-reg-32 EBX ; inline
112 : fixnum-op ( op hash -- pair )
113 >r [ "x" operand "y" operand ] swap suffix r> 2array ;
115 : fixnum-value-op ( op -- pair )
117 { +input+ { { f "x" } { [ small-tagged? ] "y" } } }
121 : fixnum-register-op ( op -- pair )
123 { +input+ { { f "x" } { f "y" } } }
127 : define-fixnum-op ( word op -- )
128 [ fixnum-value-op ] keep fixnum-register-op
129 2array define-intrinsics ;
134 { fixnum-bitand AND }
136 { fixnum-bitxor XOR }
138 first2 define-fixnum-op
143 "x" operand tag-mask get XOR
145 { +input+ { { f "x" } } }
152 "x" operand "y" get IMUL2
154 { +input+ { { f "x" } { [ small-tagged? ] "y" } } }
159 "out" operand "x" operand MOV
160 "out" operand %untag-fixnum
161 "y" operand "out" operand IMUL2
163 { +input+ { { f "x" } { f "y" } } }
164 { +scratch+ { { f "out" } } }
165 { +output+ { "out" } }
170 : %untag-fixnums ( seq -- )
171 [ %untag-fixnum ] unique-operands ;
173 \ fixnum-shift-fast [
175 dup 0 < [ neg SAR ] [ SHL ] if
179 { +input+ { { f "x" } { [ ] "y" } } }
183 : overflow-check ( word -- )
185 "z" operand "x" operand MOV
186 "z" operand "y" operand pick execute
187 ! If the previous arithmetic operation overflowed, then we
188 ! turn the result into a bignum and leave it in EAX.
190 ! There was an overflow. Recompute the original operand.
191 { "y" "x" } %untag-fixnums
192 "x" operand "y" operand rot execute
193 "z" get "x" get %allot-bignum-signed-1
194 "end" resolve-label ; inline
196 : overflow-template ( word insn -- )
197 [ overflow-check ] curry H{
198 { +input+ { { f "x" } { f "y" } } }
199 { +scratch+ { { f "z" } } }
201 { +clobber+ { "x" "y" } }
204 \ fixnum+ \ ADD overflow-template
205 \ fixnum- \ SUB overflow-template
207 : fixnum-jump ( op inputs -- pair )
208 >r [ "x" operand "y" operand CMP ] swap suffix r> 2array ;
210 : fixnum-value-jump ( op -- pair )
211 { { f "x" } { [ small-tagged? ] "y" } } fixnum-jump ;
213 : fixnum-register-jump ( op -- pair )
214 { { f "x" } { f "y" } } fixnum-jump ;
216 : define-fixnum-jump ( word op -- )
217 [ fixnum-value-jump ] keep fixnum-register-jump
218 2array define-if-intrinsics ;
227 first2 define-fixnum-jump
231 "x" operand %untag-fixnum
232 "x" get dup %allot-bignum-signed-1
234 { +input+ { { f "x" } } }
239 "nonzero" define-label
240 "positive" define-label
243 "y" operand "x" operand cell [+] MOV
244 ! if the length is 1, its just the sign and nothing else,
246 "y" operand 1 v>operand CMP
250 "nonzero" resolve-label
252 "y" operand "x" operand 3 cells [+] MOV
254 "x" operand "x" operand 2 cells [+] MOV
255 ! is the sign negative?
259 "positive" resolve-label
263 { +input+ { { f "x" } } }
264 { +scratch+ { { f "y" } } }
265 { +clobber+ { "x" } }
272 "userenv" f rc-absolute-cell rel-dlsym
273 "n" operand fixnum>slot@
274 "n" operand "x" operand ADD ;
277 %userenv "n" operand dup [] MOV
279 { +input+ { { f "n" } } }
280 { +scratch+ { { f "x" } } }
285 %userenv "n" operand [] "val" operand MOV
287 { +input+ { { f "val" } { f "n" } } }
288 { +scratch+ { { f "x" } } }
289 { +clobber+ { "n" } }
293 tuple "layout" get size>> 2 + cells [
295 "layout" get "scratch" get load-literal
296 1 object@ "scratch" operand MOV
297 ! Zero out the rest of the tuple
298 "layout" get size>> [
299 2 + object@ f v>operand MOV
301 ! Store tagged ptr in reg
302 "tuple" get tuple %store-tagged
305 { +input+ { { [ tuple-layout? ] "layout" } } }
306 { +scratch+ { { f "tuple" } { f "scratch" } } }
307 { +output+ { "tuple" } }
311 array "n" get 2 + cells [
313 1 object@ "n" operand MOV
314 ! Zero out the rest of the tuple
315 "n" get [ 2 + object@ "initial" operand MOV ] each
316 ! Store tagged ptr in reg
317 "array" get object %store-tagged
320 { +input+ { { [ inline-array? ] "n" } { f "initial" } } }
321 { +scratch+ { { f "array" } } }
322 { +output+ { "array" } }
326 byte-array "n" get 2 cells + [
328 1 object@ "n" operand MOV
329 ! Store initial element
330 "n" get cell align cell /i [ 2 + object@ 0 MOV ] each
331 ! Store tagged ptr in reg
332 "array" get object %store-tagged
335 { +input+ { { [ inline-array? ] "n" } } }
336 { +scratch+ { { f "array" } } }
337 { +output+ { "array" } }
342 1 object@ "numerator" operand MOV
343 2 object@ "denominator" operand MOV
344 ! Store tagged ptr in reg
345 "ratio" get ratio %store-tagged
348 { +input+ { { f "numerator" } { f "denominator" } } }
349 { +scratch+ { { f "ratio" } } }
350 { +output+ { "ratio" } }
355 1 object@ "real" operand MOV
356 2 object@ "imaginary" operand MOV
357 ! Store tagged ptr in reg
358 "complex" get complex %store-tagged
361 { +input+ { { f "real" } { f "imaginary" } } }
362 { +scratch+ { { f "complex" } } }
363 { +output+ { "complex" } }
368 1 object@ "obj" operand MOV
369 ! Store tagged ptr in reg
370 "wrapper" get object %store-tagged
373 { +input+ { { f "obj" } } }
374 { +scratch+ { { f "wrapper" } } }
375 { +output+ { "wrapper" } }
379 : %alien-accessor ( quot -- )
380 "offset" operand %untag-fixnum
381 "offset" operand "alien" operand ADD
382 "offset" operand [] swap call ; inline
384 : %alien-integer-get ( quot reg -- )
387 "value" operand small-reg MOV
388 "value" operand %tag-fixnum
389 small-reg POP ; inline
391 : alien-integer-get-template
394 { unboxed-c-ptr "alien" c-ptr }
395 { f "offset" fixnum }
397 { +scratch+ { { f "value" } } }
398 { +output+ { "value" } }
399 { +clobber+ { "offset" } }
402 : define-getter ( word quot reg -- )
403 [ %alien-integer-get ] 2curry
404 alien-integer-get-template
407 : define-unsigned-getter ( word reg -- )
408 [ small-reg dup XOR MOV ] swap define-getter ;
410 : define-signed-getter ( word reg -- )
411 [ [ >r MOV small-reg r> MOVSX ] curry ] keep define-getter ;
413 : %alien-integer-set ( quot reg -- )
415 "offset" get "value" get = [
416 "value" operand %untag-fixnum
418 small-reg "value" operand MOV
420 small-reg POP ; inline
422 : alien-integer-set-template
426 { unboxed-c-ptr "alien" c-ptr }
427 { f "offset" fixnum }
429 { +clobber+ { "value" "offset" } }
432 : define-setter ( word reg -- )
434 [ %alien-integer-set ] 2curry
435 alien-integer-set-template
438 \ alien-unsigned-1 small-reg-8 define-unsigned-getter
439 \ set-alien-unsigned-1 small-reg-8 define-setter
441 \ alien-signed-1 small-reg-8 define-signed-getter
442 \ set-alien-signed-1 small-reg-8 define-setter
444 \ alien-unsigned-2 small-reg-16 define-unsigned-getter
445 \ set-alien-unsigned-2 small-reg-16 define-setter
447 \ alien-signed-2 small-reg-16 define-signed-getter
448 \ set-alien-signed-2 small-reg-16 define-setter
451 "value" operand [ MOV ] %alien-accessor
454 { unboxed-c-ptr "alien" c-ptr }
455 { f "offset" fixnum }
457 { +scratch+ { { unboxed-alien "value" } } }
458 { +output+ { "value" } }
459 { +clobber+ { "offset" } }
463 "value" operand [ swap MOV ] %alien-accessor
466 { unboxed-c-ptr "value" pinned-c-ptr }
467 { unboxed-c-ptr "alien" c-ptr }
468 { f "offset" fixnum }
470 { +clobber+ { "offset" } }