1 ! Copyright (C) 2007 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: alien arrays cpu.architecture cpu.arm.assembler
4 cpu.arm.architecture cpu.arm.allot kernel kernel.private math
5 math.private namespaces sequences words
6 quotations byte-arrays hashtables.private hashtables generator
7 generator.registers generator.fixup sequences.private sbufs
8 sbufs.private vectors vectors.private system
9 classes.tuple.private layouts strings.private slots.private ;
10 IN: cpu.arm.intrinsics
12 : %slot-literal-known-tag
16 "obj" get operand-tag - <+/-> ;
18 : %slot-literal-any-tag
19 "scratch" operand "obj" operand %untag
20 "val" operand "scratch" operand "n" get cells <+> ;
23 "scratch" operand "obj" operand %untag
24 "n" operand dup 1 <LSR> MOV
25 "val" operand "scratch" operand "n" operand <+> ;
28 ! Slot number is literal and the tag is known
30 [ %slot-literal-known-tag LDR ] H{
31 { +input+ { { f "obj" known-tag } { [ small-slot? ] "n" } } }
32 { +scratch+ { { f "val" } } }
33 { +output+ { "val" } }
36 ! Slot number is literal
38 [ %slot-literal-any-tag LDR ] H{
39 { +input+ { { f "obj" } { [ small-slot? ] "n" } } }
40 { +scratch+ { { f "scratch" } { f "val" } } }
41 { +output+ { "val" } }
44 ! Slot number in a register
47 { +input+ { { f "obj" } { f "n" } } }
48 { +scratch+ { { f "val" } { f "scratch" } } }
49 { +output+ { "val" } }
55 : %write-barrier ( -- )
56 "val" get operand-immediate? "obj" get fresh-object? or [
57 "cards_offset" f R12 %alien-global
58 "scratch" operand R12 "obj" operand card-bits <LSR> ADD
59 "val" operand "scratch" operand 0 <+> LDRB
60 "val" operand dup card-mark ORR
61 "val" operand "scratch" operand 0 <+> STRB
65 ! Slot number is literal and tag is known
67 [ %slot-literal-known-tag STR %write-barrier ] H{
68 { +input+ { { f "val" } { f "obj" known-tag } { [ small-slot? ] "n" } } }
69 { +scratch+ { { f "scratch" } } }
70 { +clobber+ { "val" } }
73 ! Slot number is literal
75 [ %slot-literal-any-tag STR %write-barrier ] H{
76 { +input+ { { f "val" } { f "obj" } { [ small-slot? ] "n" } } }
77 { +scratch+ { { f "scratch" } } }
78 { +clobber+ { "val" } }
81 ! Slot number is in a register
83 [ %slot-any STR %write-barrier ] H{
84 { +input+ { { f "val" } { f "obj" } { f "n" } } }
85 { +scratch+ { { f "scratch" } } }
86 { +clobber+ { "val" "n" } }
91 : fixnum-op ( op -- quot )
92 [ "out" operand "x" operand "y" operand ] swap add ;
94 : fixnum-register-op ( op -- pair )
96 { +input+ { { f "x" } { f "y" } } }
97 { +scratch+ { { f "out" } } }
98 { +output+ { "out" } }
101 : fixnum-value-op ( op -- pair )
103 { +input+ { { f "x" } { [ small-tagged? ] "y" } } }
104 { +scratch+ { { f "out" } } }
105 { +output+ { "out" } }
108 : define-fixnum-op ( word op -- )
109 [ fixnum-value-op ] keep fixnum-register-op 2array
115 { fixnum-bitand AND }
117 { fixnum-bitxor EOR }
119 first2 define-fixnum-op
124 "x" operand dup %untag
126 { +input+ { { f "x" } } }
131 "out" operand "y" operand %untag-fixnum
132 "out" operand "x" operand "out" operand MUL
134 { +input+ { { f "x" } { f "y" } } }
135 { +scratch+ { { f "out" } } }
136 { +output+ { "out" } }
140 "out" operand "x" operand "y" get neg <ASR> MOV
142 "out" operand dup %untag
144 { +input+ { { f "x" } { [ -31 0 between? ] "y" } } }
145 { +scratch+ { { f "out" } } }
146 { +output+ { "out" } }
149 : %untag-fixnums ( seq -- )
150 [ dup %untag-fixnum ] unique-operands ;
152 : overflow-check ( insn -- )
155 [ "out" operand "x" operand "y" operand roll S execute ] keep
157 { "x" "y" } %untag-fixnums
158 "x" operand "x" operand "y" operand roll execute
159 "out" get "x" get %allot-bignum-signed-1
161 ] with-scope ; inline
163 : overflow-template ( word insn -- )
164 [ overflow-check ] curry H{
165 { +input+ { { f "x" } { f "y" } } }
166 { +scratch+ { { f "out" } } }
167 { +output+ { "out" } }
168 { +clobber+ { "x" "y" } }
171 \ fixnum+ \ ADD overflow-template
172 \ fixnum- \ SUB overflow-template
175 "x" operand dup %untag-fixnum
176 "out" get "x" get %allot-bignum-signed-1
178 { +input+ { { f "x" } } }
179 { +scratch+ { { f "out" } } }
180 { +clobber+ { "x" } }
181 { +output+ { "out" } }
186 "x" operand dup %untag
187 "y" operand "x" operand cell <+> LDR
188 ! if the length is 1, its just the sign and nothing else,
190 "y" operand 1 v>operand CMP
194 "y" operand "x" operand 3 cells <+> LDR
196 "x" operand "x" operand 2 cells <+> LDR
197 ! is the sign negative?
200 "y" operand "y" operand 0 NE RSB
201 "y" operand dup %tag-fixnum
204 { +input+ { { f "x" } } }
205 { +scratch+ { { f "y" } } }
206 { +clobber+ { "x" } }
210 : fixnum-jump ( op -- quo )
211 [ "x" operand "y" operand CMP ] swap
212 1quotation [ B ] 3append ;
214 : fixnum-register-jump ( op -- pair )
215 fixnum-jump { { f "x" } { f "y" } } 2array ;
217 : fixnum-value-jump ( op -- pair )
218 fixnum-jump { { f "x" } { [ small-tagged? ] "y" } } 2array ;
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 "out" operand "in" operand tag-mask get AND
236 "out" operand dup %tag-fixnum
238 { +input+ { { f "in" } } }
239 { +scratch+ { { f "out" } } }
240 { +output+ { "out" } }
245 "out" operand "obj" operand tag-mask get AND
246 ! Compare with object tag number (3).
247 "out" operand object tag-number CMP
248 ! Tag the tag if it is not equal to 3
249 "out" operand dup NE %tag-fixnum
250 ! Load the object header if tag is equal to 3
251 "out" operand "obj" operand object tag-number <-> EQ LDR
253 { +input+ { { f "obj" } } }
254 { +scratch+ { { f "out" } } }
255 { +output+ { "out" } }
261 "out" operand "obj" operand tag-mask get AND
262 ! Compare with tuple tag number (2).
263 "out" operand tuple tag-number CMP
264 "out" operand "obj" operand tuple-class-offset <+/-> EQ LDR
265 "out" operand dup class-hash-offset <+/-> EQ LDR
267 ! Compare with object tag number (3).
268 "out" operand object tag-number CMP
269 "out" operand "obj" operand object tag-number <-> EQ LDR
271 "out" operand dup NE %tag-fixnum
274 { +input+ { { f "obj" } } }
275 { +scratch+ { { f "out" } } }
276 { +output+ { "out" } }
280 #! Load the userenv pointer in a register.
281 "userenv" f rot compile-dlsym ;
284 "n" operand dup 1 <ASR> MOV
286 "x" operand "x" operand "n" operand <+> LDR
288 { +input+ { { f "n" } } }
289 { +scratch+ { { f "x" } } }
291 { +clobber+ { "n" } }
295 "n" operand dup 1 <ASR> MOV
297 "val" operand "x" operand "n" operand <+> STR
299 { +input+ { { f "val" } { f "n" } } }
300 { +scratch+ { { f "x" } } }
301 { +clobber+ { "n" } }
304 : %set-slot R11 swap cells <+> STR ;
310 : %fill-array swap 2 + %set-slot ;
313 tuple "n" get 2 + cells %allot
316 "class" operand 2 %set-slot
317 ! Zero out the rest of the tuple
318 "initial" operand f v>operand MOV
319 "n" get 1- [ 1+ "initial" operand %fill-array ] each
320 "out" get tuple %store-tagged
322 { +input+ { { f "class" } { [ inline-array? ] "n" } } }
323 { +scratch+ { { f "out" } { f "initial" } } }
324 { +output+ { "out" } }
328 array "n" get 2 + cells %allot
330 ! Store initial element
331 "n" get [ "initial" operand %fill-array ] each
332 "out" get object %store-tagged
334 { +input+ { { [ inline-array? ] "n" } { f "initial" } } }
335 { +scratch+ { { f "out" } } }
336 { +output+ { "out" } }
340 byte-array "n" get 2 cells + %allot
342 ! Store initial element
344 "n" get cell align cell /i [ R12 %fill-array ] each
345 "out" get object %store-tagged
347 { +input+ { { [ inline-array? ] "n" } } }
348 { +scratch+ { { f "out" } } }
349 { +output+ { "out" } }
354 "numerator" operand 1 %set-slot
355 "denominator" operand 2 %set-slot
356 "out" get ratio %store-tagged
358 { +input+ { { f "numerator" } { f "denominator" } } }
359 { +scratch+ { { f "out" } } }
360 { +output+ { "out" } }
364 complex 3 cells %allot
365 "real" operand 1 %set-slot
366 "imaginary" operand 2 %set-slot
367 ! Store tagged ptr in reg
368 "out" get complex %store-tagged
370 { +input+ { { f "real" } { f "imaginary" } } }
371 { +scratch+ { { f "out" } } }
372 { +output+ { "out" } }
376 wrapper 2 cells %allot
377 "obj" operand 1 %set-slot
378 ! Store tagged ptr in reg
379 "out" get object %store-tagged
381 { +input+ { { f "obj" } } }
382 { +scratch+ { { f "out" } } }
383 { +output+ { "out" } }
387 : %alien-accessor ( quot -- )
388 "offset" operand dup %untag-fixnum
389 "offset" operand dup "alien" operand ADD
390 "value" operand "offset" operand 0 <+> roll call ; inline
392 : alien-integer-get-template
395 { unboxed-c-ptr "alien" c-ptr }
396 { f "offset" fixnum }
398 { +scratch+ { { f "value" } } }
399 { +output+ { "value" } }
400 { +clobber+ { "offset" } }
403 : %alien-integer-get ( quot -- )
405 "value" operand dup %tag-fixnum ; inline
407 : alien-integer-set-template
411 { unboxed-c-ptr "alien" c-ptr }
412 { f "offset" fixnum }
414 { +clobber+ { "value" "offset" } }
417 : %alien-integer-set ( quot -- )
418 "offset" get "value" get = [
419 "value" operand dup %untag-fixnum
421 %alien-accessor ; inline
423 : define-alien-integer-intrinsics ( word get-quot word set-quot -- )
424 [ %alien-integer-set ] curry
425 alien-integer-set-template
427 [ %alien-integer-get ] curry
428 alien-integer-get-template
431 \ alien-unsigned-1 [ LDRB ]
432 \ set-alien-unsigned-1 [ STRB ]
433 define-alien-integer-intrinsics
435 : alien-cell-template
438 { unboxed-c-ptr "alien" c-ptr }
439 { f "offset" fixnum }
441 { +scratch+ { { unboxed-alien "value" } } }
442 { +output+ { "value" } }
443 { +clobber+ { "offset" } }
447 [ [ LDR ] %alien-accessor ]
448 alien-cell-template define-intrinsic
450 : set-alien-cell-template
453 { unboxed-c-ptr "value" pinned-c-ptr }
454 { unboxed-c-ptr "alien" c-ptr }
455 { f "offset" fixnum }
457 { +clobber+ { "offset" } }
461 [ [ STR ] %alien-accessor ]
462 set-alien-cell-template define-intrinsic