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 sequences.private sbufs sbufs.private
8 vectors vectors.private layouts system strings.private
13 compiler.generator.fixup
14 compiler.generator.registers ;
15 IN: cpu.x86.intrinsics
19 "in" operand tag-mask get AND
20 "in" operand %tag-fixnum
22 { +input+ { { f "in" } } }
27 : %slot-literal-known-tag ( -- op )
30 "obj" get operand-tag - [+] ;
32 : %slot-literal-any-tag ( -- op )
34 "obj" operand "n" get cells [+] ;
38 "n" operand fixnum>slot@
39 "obj" operand "n" operand [+] ;
42 ! Slot number is literal and the tag is known
44 [ "val" operand %slot-literal-known-tag MOV ] H{
45 { +input+ { { f "obj" known-tag } { [ small-slot? ] "n" } } }
46 { +scratch+ { { f "val" } } }
47 { +output+ { "val" } }
50 ! Slot number is literal
52 [ "obj" operand %slot-literal-any-tag MOV ] H{
53 { +input+ { { f "obj" } { [ small-slot? ] "n" } } }
54 { +output+ { "obj" } }
57 ! Slot number in a register
59 [ "obj" operand %slot-any MOV ] H{
60 { +input+ { { f "obj" } { f "n" } } }
61 { +output+ { "obj" } }
67 : generate-write-barrier ( -- )
68 #! Mark the card pointed to by vreg.
69 "val" get operand-immediate? "obj" get fresh-object? or [
71 "obj" operand card-bits SHR
72 "cards_offset" f temp-reg v>operand %alien-global
73 temp-reg v>operand "obj" operand [+] card-mark <byte> MOV
76 "obj" operand deck-bits card-bits - SHR
77 "decks_offset" f temp-reg v>operand %alien-global
78 temp-reg v>operand "obj" operand [+] card-mark <byte> MOV
82 ! Slot number is literal and the tag is known
84 [ %slot-literal-known-tag "val" operand MOV generate-write-barrier ] H{
85 { +input+ { { f "val" } { f "obj" known-tag } { [ small-slot? ] "n" } } }
86 { +clobber+ { "obj" } }
89 ! Slot number is literal
91 [ %slot-literal-any-tag "val" operand MOV generate-write-barrier ] H{
92 { +input+ { { f "val" } { f "obj" } { [ small-slot? ] "n" } } }
93 { +clobber+ { "obj" } }
96 ! Slot number in a register
98 [ %slot-any "val" operand MOV generate-write-barrier ] H{
99 { +input+ { { f "val" } { f "obj" } { f "n" } } }
100 { +clobber+ { "obj" "n" } }
105 ! Sometimes, we need to do stuff with operands which are
106 ! less than the word size. Instead of teaching the register
107 ! allocator about the different sized registers, with all
108 ! the complexity this entails, we just push/pop a register
109 ! which is guaranteed to be unused (the tempreg)
110 : small-reg cell 8 = RBX EBX ? ; inline
111 : small-reg-8 BL ; inline
112 : small-reg-16 BX ; inline
113 : small-reg-32 EBX ; inline
116 : fixnum-op ( op hash -- pair )
117 >r [ "x" operand "y" operand ] swap suffix r> 2array ;
119 : fixnum-value-op ( op -- pair )
121 { +input+ { { f "x" } { [ small-tagged? ] "y" } } }
125 : fixnum-register-op ( op -- pair )
127 { +input+ { { f "x" } { f "y" } } }
131 : define-fixnum-op ( word op -- )
132 [ fixnum-value-op ] keep fixnum-register-op
133 2array define-intrinsics ;
138 { fixnum-bitand AND }
140 { fixnum-bitxor XOR }
142 first2 define-fixnum-op
147 "x" operand tag-mask get XOR
149 { +input+ { { f "x" } } }
156 "x" operand "y" get IMUL2
158 { +input+ { { f "x" } { [ small-tagged? ] "y" } } }
163 "out" operand "x" operand MOV
164 "out" operand %untag-fixnum
165 "y" operand "out" operand IMUL2
167 { +input+ { { f "x" } { f "y" } } }
168 { +scratch+ { { f "out" } } }
169 { +output+ { "out" } }
174 : %untag-fixnums ( seq -- )
175 [ %untag-fixnum ] unique-operands ;
177 \ fixnum-shift-fast [
179 dup 0 < [ neg SAR ] [ SHL ] if
183 { +input+ { { f "x" } { [ ] "y" } } }
187 : overflow-check ( word -- )
189 "z" operand "x" operand MOV
190 "z" operand "y" operand pick execute
191 ! If the previous arithmetic operation overflowed, then we
192 ! turn the result into a bignum and leave it in EAX.
194 ! There was an overflow. Recompute the original operand.
195 { "y" "x" } %untag-fixnums
196 "x" operand "y" operand rot execute
197 "z" get "x" get %allot-bignum-signed-1
198 "end" resolve-label ; inline
200 : overflow-template ( word insn -- )
201 [ overflow-check ] curry H{
202 { +input+ { { f "x" } { f "y" } } }
203 { +scratch+ { { f "z" } } }
205 { +clobber+ { "x" "y" } }
208 \ fixnum+ \ ADD overflow-template
209 \ fixnum- \ SUB overflow-template
211 : fixnum-jump ( op inputs -- pair )
212 >r [ "x" operand "y" operand CMP ] swap suffix r> 2array ;
214 : fixnum-value-jump ( op -- pair )
215 { { f "x" } { [ small-tagged? ] "y" } } fixnum-jump ;
217 : fixnum-register-jump ( op -- pair )
218 { { f "x" } { f "y" } } fixnum-jump ;
220 : define-fixnum-jump ( word op -- )
221 [ fixnum-value-jump ] keep fixnum-register-jump
222 2array define-if-intrinsics ;
231 first2 define-fixnum-jump
235 "x" operand %untag-fixnum
236 "x" get dup %allot-bignum-signed-1
238 { +input+ { { f "x" } } }
243 "nonzero" define-label
244 "positive" define-label
247 "y" operand "x" operand cell [+] MOV
248 ! if the length is 1, its just the sign and nothing else,
250 "y" operand 1 v>operand CMP
254 "nonzero" resolve-label
256 "y" operand "x" operand 3 cells [+] MOV
258 "x" operand "x" operand 2 cells [+] MOV
259 ! is the sign negative?
263 "positive" resolve-label
267 { +input+ { { f "x" } } }
268 { +scratch+ { { f "y" } } }
269 { +clobber+ { "x" } }
276 "userenv" f rc-absolute-cell rel-dlsym
277 "n" operand fixnum>slot@
278 "n" operand "x" operand ADD ;
281 %userenv "n" operand dup [] MOV
283 { +input+ { { f "n" } } }
284 { +scratch+ { { f "x" } } }
289 %userenv "n" operand [] "val" operand MOV
291 { +input+ { { f "val" } { f "n" } } }
292 { +scratch+ { { f "x" } } }
293 { +clobber+ { "n" } }
297 tuple "layout" get size>> 2 + cells [
299 "layout" get "scratch" get load-literal
300 1 object@ "scratch" operand MOV
301 ! Store tagged ptr in reg
302 "tuple" get tuple %store-tagged
305 { +input+ { { [ ] "layout" } } }
306 { +scratch+ { { f "tuple" } { f "scratch" } } }
307 { +output+ { "tuple" } }
311 array "n" get 2 + cells [
313 1 object@ "n" operand MOV
314 ! Store tagged ptr in reg
315 "array" get object %store-tagged
318 { +input+ { { [ ] "n" } } }
319 { +scratch+ { { f "array" } } }
320 { +output+ { "array" } }
324 byte-array "n" get 2 cells + [
326 1 object@ "n" operand MOV
327 ! Store tagged ptr in reg
328 "array" get object %store-tagged
331 { +input+ { { [ ] "n" } } }
332 { +scratch+ { { f "array" } } }
333 { +output+ { "array" } }
338 1 object@ "numerator" operand MOV
339 2 object@ "denominator" operand MOV
340 ! Store tagged ptr in reg
341 "ratio" get ratio %store-tagged
344 { +input+ { { f "numerator" } { f "denominator" } } }
345 { +scratch+ { { f "ratio" } } }
346 { +output+ { "ratio" } }
351 1 object@ "real" operand MOV
352 2 object@ "imaginary" operand MOV
353 ! Store tagged ptr in reg
354 "complex" get complex %store-tagged
357 { +input+ { { f "real" } { f "imaginary" } } }
358 { +scratch+ { { f "complex" } } }
359 { +output+ { "complex" } }
364 1 object@ "obj" operand MOV
365 ! Store tagged ptr in reg
366 "wrapper" get object %store-tagged
369 { +input+ { { f "obj" } } }
370 { +scratch+ { { f "wrapper" } } }
371 { +output+ { "wrapper" } }
375 : %alien-accessor ( quot -- )
376 "offset" operand %untag-fixnum
377 "offset" operand "alien" operand ADD
378 "offset" operand [] swap call ; inline
380 : %alien-integer-get ( quot reg -- )
383 "value" operand small-reg MOV
384 "value" operand %tag-fixnum
385 small-reg POP ; inline
387 : alien-integer-get-template
390 { unboxed-c-ptr "alien" c-ptr }
391 { f "offset" fixnum }
393 { +scratch+ { { f "value" } } }
394 { +output+ { "value" } }
395 { +clobber+ { "offset" } }
398 : define-getter ( word quot reg -- )
399 [ %alien-integer-get ] 2curry
400 alien-integer-get-template
403 : define-unsigned-getter ( word reg -- )
404 [ small-reg dup XOR MOV ] swap define-getter ;
406 : define-signed-getter ( word reg -- )
407 [ [ >r MOV small-reg r> MOVSX ] curry ] keep define-getter ;
409 : %alien-integer-set ( quot reg -- )
411 small-reg "value" operand MOV
412 small-reg %untag-fixnum
414 small-reg POP ; inline
416 : alien-integer-set-template
420 { unboxed-c-ptr "alien" c-ptr }
421 { f "offset" fixnum }
423 { +clobber+ { "value" "offset" } }
426 : define-setter ( word reg -- )
428 [ %alien-integer-set ] 2curry
429 alien-integer-set-template
432 \ alien-unsigned-1 small-reg-8 define-unsigned-getter
433 \ set-alien-unsigned-1 small-reg-8 define-setter
435 \ alien-signed-1 small-reg-8 define-signed-getter
436 \ set-alien-signed-1 small-reg-8 define-setter
438 \ alien-unsigned-2 small-reg-16 define-unsigned-getter
439 \ set-alien-unsigned-2 small-reg-16 define-setter
441 \ alien-signed-2 small-reg-16 define-signed-getter
442 \ set-alien-signed-2 small-reg-16 define-setter
445 "value" operand [ MOV ] %alien-accessor
448 { unboxed-c-ptr "alien" c-ptr }
449 { f "offset" fixnum }
451 { +scratch+ { { unboxed-alien "value" } } }
452 { +output+ { "value" } }
453 { +clobber+ { "offset" } }
457 "value" operand [ swap MOV ] %alien-accessor
460 { unboxed-c-ptr "value" pinned-c-ptr }
461 { unboxed-c-ptr "alien" c-ptr }
462 { f "offset" fixnum }
464 { +clobber+ { "offset" } }