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 strings.private slots.private compiler.constants optimizer.allot ;
10 IN: cpu.x86.intrinsics
14 "in" operand tag-mask get AND
15 "in" operand %tag-fixnum
17 { +input+ { { f "in" } } }
22 : %slot-literal-known-tag ( -- op )
25 "obj" get operand-tag - [+] ;
27 : %slot-literal-any-tag ( -- op )
29 "obj" operand "n" get cells [+] ;
33 "n" operand fixnum>slot@
34 "obj" operand "n" operand [+] ;
37 ! Slot number is literal and the tag is known
39 [ "val" operand %slot-literal-known-tag MOV ] H{
40 { +input+ { { f "obj" known-tag } { [ small-slot? ] "n" } } }
41 { +scratch+ { { f "val" } } }
42 { +output+ { "val" } }
45 ! Slot number is literal
47 [ "obj" operand %slot-literal-any-tag MOV ] H{
48 { +input+ { { f "obj" } { [ small-slot? ] "n" } } }
49 { +output+ { "obj" } }
52 ! Slot number in a register
54 [ "obj" operand %slot-any MOV ] H{
55 { +input+ { { f "obj" } { f "n" } } }
56 { +output+ { "obj" } }
62 : generate-write-barrier ( -- )
63 #! Mark the card pointed to by vreg.
64 "val" get operand-immediate? "obj" get fresh-object? or [
66 "obj" operand card-bits SHR
67 "cards_offset" f temp-reg v>operand %alien-global
68 temp-reg v>operand "obj" operand [+] card-mark <byte> MOV
71 "obj" operand deck-bits card-bits - SHR
72 "decks_offset" f temp-reg v>operand %alien-global
73 temp-reg v>operand "obj" operand [+] card-mark <byte> MOV
77 ! Slot number is literal and the tag is known
79 [ %slot-literal-known-tag "val" operand MOV generate-write-barrier ] H{
80 { +input+ { { f "val" } { f "obj" known-tag } { [ small-slot? ] "n" } } }
81 { +clobber+ { "obj" } }
84 ! Slot number is literal
86 [ %slot-literal-any-tag "val" operand MOV generate-write-barrier ] H{
87 { +input+ { { f "val" } { f "obj" } { [ small-slot? ] "n" } } }
88 { +clobber+ { "obj" } }
91 ! Slot number in a register
93 [ %slot-any "val" operand MOV generate-write-barrier ] H{
94 { +input+ { { f "val" } { f "obj" } { f "n" } } }
95 { +clobber+ { "obj" "n" } }
100 ! Sometimes, we need to do stuff with operands which are
101 ! less than the word size. Instead of teaching the register
102 ! allocator about the different sized registers, with all
103 ! the complexity this entails, we just push/pop a register
104 ! which is guaranteed to be unused (the tempreg)
105 : small-reg cell 8 = RBX EBX ? ; inline
106 : small-reg-8 BL ; inline
107 : small-reg-16 BX ; inline
108 : small-reg-32 EBX ; inline
111 : fixnum-op ( op hash -- pair )
112 >r [ "x" operand "y" operand ] swap suffix r> 2array ;
114 : fixnum-value-op ( op -- pair )
116 { +input+ { { f "x" } { [ small-tagged? ] "y" } } }
120 : fixnum-register-op ( op -- pair )
122 { +input+ { { f "x" } { f "y" } } }
126 : define-fixnum-op ( word op -- )
127 [ fixnum-value-op ] keep fixnum-register-op
128 2array define-intrinsics ;
133 { fixnum-bitand AND }
135 { fixnum-bitxor XOR }
137 first2 define-fixnum-op
142 "x" operand tag-mask get XOR
144 { +input+ { { f "x" } } }
151 "x" operand "y" get IMUL2
153 { +input+ { { f "x" } { [ small-tagged? ] "y" } } }
158 "out" operand "x" operand MOV
159 "out" operand %untag-fixnum
160 "y" operand "out" operand IMUL2
162 { +input+ { { f "x" } { f "y" } } }
163 { +scratch+ { { f "out" } } }
164 { +output+ { "out" } }
169 : %untag-fixnums ( seq -- )
170 [ %untag-fixnum ] unique-operands ;
172 \ fixnum-shift-fast [
174 dup 0 < [ neg SAR ] [ SHL ] if
178 { +input+ { { f "x" } { [ ] "y" } } }
182 : overflow-check ( word -- )
184 "z" operand "x" operand MOV
185 "z" operand "y" operand pick execute
186 ! If the previous arithmetic operation overflowed, then we
187 ! turn the result into a bignum and leave it in EAX.
189 ! There was an overflow. Recompute the original operand.
190 { "y" "x" } %untag-fixnums
191 "x" operand "y" operand rot execute
192 "z" get "x" get %allot-bignum-signed-1
193 "end" resolve-label ; inline
195 : overflow-template ( word insn -- )
196 [ overflow-check ] curry H{
197 { +input+ { { f "x" } { f "y" } } }
198 { +scratch+ { { f "z" } } }
200 { +clobber+ { "x" "y" } }
203 \ fixnum+ \ ADD overflow-template
204 \ fixnum- \ SUB overflow-template
206 : fixnum-jump ( op inputs -- pair )
207 >r [ "x" operand "y" operand CMP ] swap suffix r> 2array ;
209 : fixnum-value-jump ( op -- pair )
210 { { f "x" } { [ small-tagged? ] "y" } } fixnum-jump ;
212 : fixnum-register-jump ( op -- pair )
213 { { f "x" } { f "y" } } fixnum-jump ;
215 : define-fixnum-jump ( word op -- )
216 [ fixnum-value-jump ] keep fixnum-register-jump
217 2array define-if-intrinsics ;
226 first2 define-fixnum-jump
230 "x" operand %untag-fixnum
231 "x" get dup %allot-bignum-signed-1
233 { +input+ { { f "x" } } }
238 "nonzero" define-label
239 "positive" define-label
242 "y" operand "x" operand cell [+] MOV
243 ! if the length is 1, its just the sign and nothing else,
245 "y" operand 1 v>operand CMP
249 "nonzero" resolve-label
251 "y" operand "x" operand 3 cells [+] MOV
253 "x" operand "x" operand 2 cells [+] MOV
254 ! is the sign negative?
258 "positive" resolve-label
262 { +input+ { { f "x" } } }
263 { +scratch+ { { f "y" } } }
264 { +clobber+ { "x" } }
271 "userenv" f rc-absolute-cell rel-dlsym
272 "n" operand fixnum>slot@
273 "n" operand "x" operand ADD ;
276 %userenv "n" operand dup [] MOV
278 { +input+ { { f "n" } } }
279 { +scratch+ { { f "x" } } }
284 %userenv "n" operand [] "val" operand MOV
286 { +input+ { { f "val" } { f "n" } } }
287 { +scratch+ { { f "x" } } }
288 { +clobber+ { "n" } }
292 tuple "layout" get size>> 2 + cells [
294 "layout" get "scratch" get load-literal
295 1 object@ "scratch" operand MOV
296 ! Store tagged ptr in reg
297 "tuple" get tuple %store-tagged
300 { +input+ { { [ ] "layout" } } }
301 { +scratch+ { { f "tuple" } { f "scratch" } } }
302 { +output+ { "tuple" } }
306 array "n" get 2 + cells [
308 1 object@ "n" operand MOV
309 ! Store tagged ptr in reg
310 "array" get object %store-tagged
313 { +input+ { { [ ] "n" } } }
314 { +scratch+ { { f "array" } } }
315 { +output+ { "array" } }
319 byte-array "n" get 2 cells + [
321 1 object@ "n" operand MOV
322 ! Store tagged ptr in reg
323 "array" get object %store-tagged
326 { +input+ { { [ ] "n" } } }
327 { +scratch+ { { f "array" } } }
328 { +output+ { "array" } }
333 1 object@ "numerator" operand MOV
334 2 object@ "denominator" operand MOV
335 ! Store tagged ptr in reg
336 "ratio" get ratio %store-tagged
339 { +input+ { { f "numerator" } { f "denominator" } } }
340 { +scratch+ { { f "ratio" } } }
341 { +output+ { "ratio" } }
346 1 object@ "real" operand MOV
347 2 object@ "imaginary" operand MOV
348 ! Store tagged ptr in reg
349 "complex" get complex %store-tagged
352 { +input+ { { f "real" } { f "imaginary" } } }
353 { +scratch+ { { f "complex" } } }
354 { +output+ { "complex" } }
359 1 object@ "obj" operand MOV
360 ! Store tagged ptr in reg
361 "wrapper" get object %store-tagged
364 { +input+ { { f "obj" } } }
365 { +scratch+ { { f "wrapper" } } }
366 { +output+ { "wrapper" } }
370 : %alien-accessor ( quot -- )
371 "offset" operand %untag-fixnum
372 "offset" operand "alien" operand ADD
373 "offset" operand [] swap call ; inline
375 : %alien-integer-get ( quot reg -- )
378 "value" operand small-reg MOV
379 "value" operand %tag-fixnum
380 small-reg POP ; inline
382 : alien-integer-get-template
385 { unboxed-c-ptr "alien" c-ptr }
386 { f "offset" fixnum }
388 { +scratch+ { { f "value" } } }
389 { +output+ { "value" } }
390 { +clobber+ { "offset" } }
393 : define-getter ( word quot reg -- )
394 [ %alien-integer-get ] 2curry
395 alien-integer-get-template
398 : define-unsigned-getter ( word reg -- )
399 [ small-reg dup XOR MOV ] swap define-getter ;
401 : define-signed-getter ( word reg -- )
402 [ [ >r MOV small-reg r> MOVSX ] curry ] keep define-getter ;
404 : %alien-integer-set ( quot reg -- )
406 "offset" get "value" get = [
407 "value" operand %untag-fixnum
409 small-reg "value" operand MOV
411 small-reg POP ; inline
413 : alien-integer-set-template
417 { unboxed-c-ptr "alien" c-ptr }
418 { f "offset" fixnum }
420 { +clobber+ { "value" "offset" } }
423 : define-setter ( word reg -- )
425 [ %alien-integer-set ] 2curry
426 alien-integer-set-template
429 \ alien-unsigned-1 small-reg-8 define-unsigned-getter
430 \ set-alien-unsigned-1 small-reg-8 define-setter
432 \ alien-signed-1 small-reg-8 define-signed-getter
433 \ set-alien-signed-1 small-reg-8 define-setter
435 \ alien-unsigned-2 small-reg-16 define-unsigned-getter
436 \ set-alien-unsigned-2 small-reg-16 define-setter
438 \ alien-signed-2 small-reg-16 define-signed-getter
439 \ set-alien-signed-2 small-reg-16 define-setter
442 "value" operand [ MOV ] %alien-accessor
445 { unboxed-c-ptr "alien" c-ptr }
446 { f "offset" fixnum }
448 { +scratch+ { { unboxed-alien "value" } } }
449 { +output+ { "value" } }
450 { +clobber+ { "offset" } }
454 "value" operand [ swap MOV ] %alien-accessor
457 { unboxed-c-ptr "value" pinned-c-ptr }
458 { unboxed-c-ptr "alien" c-ptr }
459 { f "offset" fixnum }
461 { +clobber+ { "offset" } }