]> gitweb.factorcode.org Git - factor.git/blob - basis/bootstrap/assembler/x86.factor
factor: trim using lists
[factor.git] / basis / bootstrap / assembler / x86.factor
1 ! Copyright (C) 2007, 2011 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: bootstrap.image.private compiler.codegen.relocation
4 compiler.constants compiler.units cpu.x86.assembler
5 cpu.x86.assembler.operands kernel kernel.private layouts
6 locals.backend math math.private namespaces sequences
7 slots.private strings.private vocabs ;
8 IN: bootstrap.x86
9
10 : temp0/32 ( -- reg )
11     temp0 32-bit-version-of ;
12 : temp1/32 ( -- reg )
13     temp1 32-bit-version-of ;
14
15 big-endian off
16
17 ! C to Factor entry point
18 [
19     ! Optimizing compiler's side of callback accesses
20     ! arguments that are on the stack via the frame pointer.
21     ! On x86-32 fastcall, and x86-64, some arguments are passed
22     ! in registers, and so the only registers that are safe for
23     ! use here are frame-reg, nv-reg and vm-reg.
24     frame-reg PUSH
25     frame-reg stack-reg MOV
26
27     ! Save all non-volatile registers
28     nv-regs [ PUSH ] each
29
30     jit-save-tib
31
32     ! Load VM into vm-reg
33     vm-reg 0 MOV 0 rc-absolute-cell rel-vm
34
35     ! Save old context
36     nv-reg vm-reg vm-context-offset [+] MOV
37     nv-reg PUSH
38
39     ! Switch over to the spare context
40     nv-reg vm-reg vm-spare-context-offset [+] MOV
41     vm-reg vm-context-offset [+] nv-reg MOV
42
43     ! Save C callstack pointer
44     nv-reg context-callstack-save-offset [+] stack-reg MOV
45
46     ! Load Factor stack pointers
47     stack-reg nv-reg context-callstack-bottom-offset [+] MOV
48     nv-reg jit-update-tib
49     jit-install-seh
50
51     rs-reg nv-reg context-retainstack-offset [+] MOV
52     ds-reg nv-reg context-datastack-offset [+] MOV
53
54     ! Call into Factor code
55     link-reg 0 MOV f rc-absolute-cell rel-word
56     link-reg CALL
57
58     ! Load VM into vm-reg; only needed on x86-32, but doesn't
59     ! hurt on x86-64
60     vm-reg 0 MOV 0 rc-absolute-cell rel-vm
61
62     ! Load C callstack pointer
63     nv-reg vm-reg vm-context-offset [+] MOV
64     stack-reg nv-reg context-callstack-save-offset [+] MOV
65
66     ! Load old context
67     nv-reg POP
68     vm-reg vm-context-offset [+] nv-reg MOV
69
70     ! Restore non-volatile registers
71     jit-restore-tib
72
73     nv-regs <reversed> [ POP ] each
74
75     frame-reg POP
76
77     ! Callbacks which return structs, or use stdcall/fastcall/thiscall,
78     ! need a parameter here.
79
80     ! See the comment for M\ x86.32 stack-cleanup in cpu.x86.32
81     0xffff RET f rc-absolute-2 rel-untagged
82 ] CALLBACK-STUB jit-define
83
84 [
85     ! load literal
86     temp0 0 MOV f rc-absolute-cell rel-literal
87     ! increment datastack pointer
88     ds-reg bootstrap-cell ADD
89     ! store literal on datastack
90     ds-reg [] temp0 MOV
91 ] JIT-PUSH-LITERAL jit-define
92
93 [
94     0 CALL f rc-relative rel-word-pic
95 ] JIT-WORD-CALL jit-define
96
97 ! The *-signal-handler subprimitives are special-cased in vm/quotations.cpp
98 ! not to trigger generation of a stack frame, so they can
99 ! peform their own prolog/epilog preserving registers.
100 !
101 ! It is important that the total is 192/64 and that it matches the
102 ! constants in vm/cpu-x86.*.hpp
103 : jit-signal-handler-prolog ( -- )
104     ! Return address already on stack -> 8/4 bytes.
105
106     ! Push all registers. 15 regs/120 bytes on 64bit, 7 regs/28 bytes
107     ! on 32bit -> 128/32 bytes.
108     signal-handler-save-regs [ PUSH ] each
109
110     ! Push flags -> 136/36 bytes
111     PUSHF
112
113     ! Register parameter area 32 bytes, unused on platforms other than
114     ! windows 64 bit, but including it doesn't hurt. Plus
115     ! alignment. LEA used so we don't dirty flags -> 192/64 bytes.
116     stack-reg stack-reg 7 bootstrap-cells neg [+] LEA
117
118     jit-load-vm ;
119
120 : jit-signal-handler-epilog ( -- )
121     stack-reg stack-reg 7 bootstrap-cells [+] LEA
122     POPF
123     signal-handler-save-regs reverse [ POP ] each ;
124
125 [
126     ! load boolean
127     temp0 ds-reg [] MOV
128     ! pop boolean
129     ds-reg bootstrap-cell SUB
130     ! compare boolean with f
131     temp0 \ f type-number CMP
132     ! jump to true branch if not equal
133     0 JNE f rc-relative rel-word
134     ! jump to false branch if equal
135     0 JMP f rc-relative rel-word
136 ] JIT-IF jit-define
137
138 : jit->r ( -- )
139     rs-reg bootstrap-cell ADD
140     temp0 ds-reg [] MOV
141     ds-reg bootstrap-cell SUB
142     rs-reg [] temp0 MOV ;
143
144 : jit-2>r ( -- )
145     rs-reg 2 bootstrap-cells ADD
146     temp0 ds-reg [] MOV
147     temp1 ds-reg -1 bootstrap-cells [+] MOV
148     ds-reg 2 bootstrap-cells SUB
149     rs-reg [] temp0 MOV
150     rs-reg -1 bootstrap-cells [+] temp1 MOV ;
151
152 : jit-3>r ( -- )
153     rs-reg 3 bootstrap-cells ADD
154     temp0 ds-reg [] MOV
155     temp1 ds-reg -1 bootstrap-cells [+] MOV
156     temp2 ds-reg -2 bootstrap-cells [+] MOV
157     ds-reg 3 bootstrap-cells SUB
158     rs-reg [] temp0 MOV
159     rs-reg -1 bootstrap-cells [+] temp1 MOV
160     rs-reg -2 bootstrap-cells [+] temp2 MOV ;
161
162 : jit-r> ( -- )
163     ds-reg bootstrap-cell ADD
164     temp0 rs-reg [] MOV
165     rs-reg bootstrap-cell SUB
166     ds-reg [] temp0 MOV ;
167
168 : jit-2r> ( -- )
169     ds-reg 2 bootstrap-cells ADD
170     temp0 rs-reg [] MOV
171     temp1 rs-reg -1 bootstrap-cells [+] MOV
172     rs-reg 2 bootstrap-cells SUB
173     ds-reg [] temp0 MOV
174     ds-reg -1 bootstrap-cells [+] temp1 MOV ;
175
176 : jit-3r> ( -- )
177     ds-reg 3 bootstrap-cells ADD
178     temp0 rs-reg [] MOV
179     temp1 rs-reg -1 bootstrap-cells [+] MOV
180     temp2 rs-reg -2 bootstrap-cells [+] MOV
181     rs-reg 3 bootstrap-cells SUB
182     ds-reg [] temp0 MOV
183     ds-reg -1 bootstrap-cells [+] temp1 MOV
184     ds-reg -2 bootstrap-cells [+] temp2 MOV ;
185
186 [
187     jit->r
188     0 CALL f rc-relative rel-word
189     jit-r>
190 ] JIT-DIP jit-define
191
192 [
193     jit-2>r
194     0 CALL f rc-relative rel-word
195     jit-2r>
196 ] JIT-2DIP jit-define
197
198 [
199     jit-3>r
200     0 CALL f rc-relative rel-word
201     jit-3r>
202 ] JIT-3DIP jit-define
203
204 [
205     ! load from stack
206     temp0 ds-reg [] MOV
207     ! pop stack
208     ds-reg bootstrap-cell SUB
209 ]
210 [ temp0 word-entry-point-offset [+] CALL ]
211 [ temp0 word-entry-point-offset [+] JMP ]
212 \ (execute) define-combinator-primitive
213
214 [
215     temp0 ds-reg [] MOV
216     ds-reg bootstrap-cell SUB
217     temp0 word-entry-point-offset [+] JMP
218 ] JIT-EXECUTE jit-define
219
220 [
221     stack-reg stack-frame-size bootstrap-cell - SUB
222 ] JIT-PROLOG jit-define
223
224 [
225     stack-reg stack-frame-size bootstrap-cell - ADD
226 ] JIT-EPILOG jit-define
227
228 [ 0 RET ] JIT-RETURN jit-define
229
230 ! ! ! Polymorphic inline caches
231
232 ! The PIC stubs are not permitted to touch pic-tail-reg.
233
234 ! Load a value from a stack position
235 [
236     temp1 ds-reg 0x7f [+] MOV f rc-absolute-1 rel-untagged
237 ] PIC-LOAD jit-define
238
239 [ temp1/32 tag-mask get AND ] PIC-TAG jit-define
240
241 [
242     temp0 temp1 MOV
243     temp1/32 tag-mask get AND
244     temp1/32 tuple type-number CMP
245     [ JNE ]
246     [ temp1 temp0 tuple-class-offset [+] MOV ]
247     jit-conditional
248 ] PIC-TUPLE jit-define
249
250 [
251     temp1/32 0x7f CMP f rc-absolute-1 rel-untagged
252 ] PIC-CHECK-TAG jit-define
253
254 [ 0 JE f rc-relative rel-word ] PIC-HIT jit-define
255
256 ! ! ! Megamorphic caches
257
258 [
259     ! class = ...
260     temp0 temp1 MOV
261     temp1/32 tag-mask get AND
262     temp1/32 tag-bits get SHL
263     temp1/32 tuple type-number tag-fixnum CMP
264     [ JNE ]
265     [ temp1 temp0 tuple-class-offset [+] MOV ]
266     jit-conditional
267     ! cache = ...
268     temp0 0 MOV f rc-absolute-cell rel-literal
269     ! key = hashcode(class)
270     temp2 temp1 MOV
271     bootstrap-cell 4 = [ temp2 1 SHR ] when
272     ! key &= cache.length - 1
273     temp2 mega-cache-size get 1 - bootstrap-cell * AND
274     ! cache += array-start-offset
275     temp0 array-start-offset ADD
276     ! cache += key
277     temp0 temp2 ADD
278     ! if(get(cache) == class)
279     temp0 [] temp1 CMP
280     [ JNE ]
281     [
282         ! megamorphic_cache_hits++
283         temp1 0 MOV rc-absolute-cell rel-megamorphic-cache-hits
284         temp1 [] 1 ADD
285         ! goto get(cache + bootstrap-cell)
286         temp0 temp0 bootstrap-cell [+] MOV
287         temp0 word-entry-point-offset [+] JMP
288         ! fall-through on miss
289     ] jit-conditional
290 ] MEGA-LOOKUP jit-define
291
292 ! Comparisons
293 : jit-compare ( insn -- )
294     ! load t
295     temp3 0 MOV t rc-absolute-cell rel-literal
296     ! load f
297     temp1 \ f type-number MOV
298     ! load first value
299     temp0 ds-reg [] MOV
300     ! adjust stack pointer
301     ds-reg bootstrap-cell SUB
302     ! compare with second value
303     ds-reg [] temp0 CMP
304     ! move t if true
305     [ temp1 temp3 ] dip execute( dst src -- )
306     ! store
307     ds-reg [] temp1 MOV ;
308
309 ! Math
310 : jit-math ( insn -- )
311     ! load second input
312     temp0 ds-reg [] MOV
313     ! pop stack
314     ds-reg bootstrap-cell SUB
315     ! compute result
316     [ ds-reg [] temp0 ] dip execute( dst src -- ) ;
317
318 : jit-fixnum-/mod ( -- )
319     ! load second parameter
320     temp1 ds-reg [] MOV
321     ! load first parameter
322     div-arg ds-reg bootstrap-cell neg [+] MOV
323     ! make a copy
324     mod-arg div-arg MOV
325     ! sign-extend
326     mod-arg bootstrap-cell-bits 1 - SAR
327     ! divide
328     temp1 IDIV ;
329
330 ! # All x86 subprimitives
331 {
332     ! ## Fixnums
333
334     ! ### Add
335     { fixnum+fast [ \ ADD jit-math ] }
336
337     ! ### Bit stuff
338     { fixnum-bitand [ \ AND jit-math ] }
339     { fixnum-bitnot [
340         ! complement
341         ds-reg [] NOT
342         ! clear tag bits
343         ds-reg [] tag-mask get XOR
344     ] }
345     { fixnum-bitor [ \ OR jit-math ] }
346     { fixnum-bitxor [ \ XOR jit-math ] }
347     { fixnum-shift-fast [
348         ! load shift count
349         shift-arg ds-reg [] MOV
350         ! untag shift count
351         shift-arg tag-bits get SAR
352         ! adjust stack pointer
353         ds-reg bootstrap-cell SUB
354         ! load value
355         temp3 ds-reg [] MOV
356         ! make a copy
357         temp2 temp3 MOV
358         ! compute positive shift value in temp2
359         temp2 CL SHL
360         shift-arg NEG
361         ! compute negative shift value in temp3
362         temp3 CL SAR
363         temp3 tag-mask get bitnot AND
364         shift-arg 0 CMP
365         ! if shift count was negative, move temp0 to temp2
366         temp2 temp3 CMOVGE
367         ! push to stack
368         ds-reg [] temp2 MOV
369     ] }
370
371     ! ### Comparisons
372     { both-fixnums? [
373         temp0 ds-reg [] MOV
374         ds-reg bootstrap-cell SUB
375         temp0 ds-reg [] OR
376         temp0 tag-mask get TEST
377         temp0 \ f type-number MOV
378         temp1 1 tag-fixnum MOV
379         temp0 temp1 CMOVE
380         ds-reg [] temp0 MOV
381     ] }
382     { eq? [ \ CMOVE jit-compare ] }
383     { fixnum> [ \ CMOVG jit-compare ] }
384     { fixnum>= [ \ CMOVGE jit-compare ] }
385     { fixnum< [ \ CMOVL jit-compare ] }
386     { fixnum<= [ \ CMOVLE jit-compare ] }
387
388     ! ### Div/mod
389     { fixnum-mod [
390         jit-fixnum-/mod
391         ! adjust stack pointer
392         ds-reg bootstrap-cell SUB
393         ! push to stack
394         ds-reg [] mod-arg MOV
395     ] }
396     { fixnum/i-fast [
397         jit-fixnum-/mod
398         ! adjust stack pointer
399         ds-reg bootstrap-cell SUB
400         ! tag it
401         div-arg tag-bits get SHL
402         ! push to stack
403         ds-reg [] div-arg MOV
404     ] }
405     { fixnum/mod-fast [
406         jit-fixnum-/mod
407         ! tag it
408         div-arg tag-bits get SHL
409         ! push to stack
410         ds-reg [] mod-arg MOV
411         ds-reg bootstrap-cell neg [+] div-arg MOV
412     ] }
413
414     ! ### Mul
415     { fixnum*fast [
416         ! load second input
417         temp0 ds-reg [] MOV
418         ! pop stack
419         ds-reg bootstrap-cell SUB
420         ! load first input
421         temp1 ds-reg [] MOV
422         ! untag second input
423         temp0 tag-bits get SAR
424         ! multiply
425         temp0 temp1 IMUL2
426         ! push result
427         ds-reg [] temp0 MOV
428     ] }
429
430     ! ### Sub
431     { fixnum-fast [ \ SUB jit-math ] }
432
433     ! ## Locals
434     { drop-locals [
435         ! load local count
436         temp0 ds-reg [] MOV
437         ! adjust stack pointer
438         ds-reg bootstrap-cell SUB
439         ! turn local number into offset
440         fixnum>slot@
441         ! decrement retain stack pointer
442         rs-reg temp0 SUB
443     ] }
444     { get-local [
445         ! load local number
446         temp0 ds-reg [] MOV
447         ! turn local number into offset
448         fixnum>slot@
449         ! load local value
450         temp0 rs-reg temp0 [+] MOV
451         ! push to stack
452         ds-reg [] temp0 MOV
453     ] }
454     { load-local [ jit->r ] }
455
456     ! ## Objects
457     { slot [
458         ! load slot number
459         temp0 ds-reg [] MOV
460         ! adjust stack pointer
461         ds-reg bootstrap-cell SUB
462         ! load object
463         temp1 ds-reg [] MOV
464         ! turn slot number into offset
465         fixnum>slot@
466         ! mask off tag
467         temp1 tag-bits get SHR
468         temp1 tag-bits get SHL
469         ! load slot value
470         temp0 temp1 temp0 [+] MOV
471         ! push to stack
472         ds-reg [] temp0 MOV
473     ] }
474     { string-nth-fast [
475         ! load string index from stack
476         temp0 ds-reg bootstrap-cell neg [+] MOV
477         temp0 tag-bits get SHR
478         ! load string from stack
479         temp1 ds-reg [] MOV
480         ! load character
481         temp0 8-bit-version-of temp0 temp1 string-offset [++] MOV
482         temp0 temp0 8-bit-version-of MOVZX
483         temp0 tag-bits get SHL
484         ! store character to stack
485         ds-reg bootstrap-cell SUB
486         ds-reg [] temp0 MOV
487     ] }
488     { tag [
489         ! load from stack
490         temp0 ds-reg [] MOV
491         ! compute tag
492         temp0/32 tag-mask get AND
493         ! tag the tag
494         temp0/32 tag-bits get SHL
495         ! push to stack
496         ds-reg [] temp0 MOV
497     ] }
498
499     ! ## Shufflers
500
501     ! ### Drops
502     { drop [ ds-reg bootstrap-cell SUB ] }
503     { 2drop [ ds-reg 2 bootstrap-cells SUB ] }
504     { 3drop [ ds-reg 3 bootstrap-cells SUB ] }
505     { 4drop [ ds-reg 4 bootstrap-cells SUB ] }
506
507     ! ### Dups
508     { dup [
509         temp0 ds-reg [] MOV
510         ds-reg bootstrap-cell ADD
511         ds-reg [] temp0 MOV
512     ] }
513     { 2dup [
514         temp0 ds-reg [] MOV
515         temp1 ds-reg bootstrap-cell neg [+] MOV
516         ds-reg 2 bootstrap-cells ADD
517         ds-reg [] temp0 MOV
518         ds-reg bootstrap-cell neg [+] temp1 MOV
519     ] }
520     { 3dup [
521         temp0 ds-reg [] MOV
522         temp1 ds-reg -1 bootstrap-cells [+] MOV
523         temp3 ds-reg -2 bootstrap-cells [+] MOV
524         ds-reg 3 bootstrap-cells ADD
525         ds-reg [] temp0 MOV
526         ds-reg -1 bootstrap-cells [+] temp1 MOV
527         ds-reg -2 bootstrap-cells [+] temp3 MOV
528     ] }
529     { 4dup [
530         temp0 ds-reg [] MOV
531         temp1 ds-reg -1 bootstrap-cells [+] MOV
532         temp2 ds-reg -2 bootstrap-cells [+] MOV
533         temp3 ds-reg -3 bootstrap-cells [+] MOV
534         ds-reg 4 bootstrap-cells ADD
535         ds-reg [] temp0 MOV
536         ds-reg -1 bootstrap-cells [+] temp1 MOV
537         ds-reg -2 bootstrap-cells [+] temp2 MOV
538         ds-reg -3 bootstrap-cells [+] temp3 MOV
539     ] }
540     { dupd [
541         temp0 ds-reg [] MOV
542         temp1 ds-reg -1 bootstrap-cells [+] MOV
543         ds-reg [] temp1 MOV
544         ds-reg bootstrap-cell ADD
545         ds-reg [] temp0 MOV
546     ] }
547
548     ! ### Misc shufflers
549     { over [
550         temp0 ds-reg -1 bootstrap-cells [+] MOV
551         ds-reg bootstrap-cell ADD
552         ds-reg [] temp0 MOV
553     ] }
554     { pick [
555         temp0 ds-reg -2 bootstrap-cells [+] MOV
556         ds-reg bootstrap-cell ADD
557         ds-reg [] temp0 MOV
558     ] }
559
560     ! ### Nips
561     { nip [
562         temp0 ds-reg [] MOV
563         ds-reg bootstrap-cell SUB
564         ds-reg [] temp0 MOV
565     ] }
566     { 2nip [
567         temp0 ds-reg [] MOV
568         ds-reg 2 bootstrap-cells SUB
569         ds-reg [] temp0 MOV
570     ] }
571
572     ! ### Swaps
573     { -rot [
574         temp0 ds-reg [] MOV
575         temp1 ds-reg -1 bootstrap-cells [+] MOV
576         temp3 ds-reg -2 bootstrap-cells [+] MOV
577         ds-reg -2 bootstrap-cells [+] temp0 MOV
578         ds-reg -1 bootstrap-cells [+] temp3 MOV
579         ds-reg [] temp1 MOV
580     ] }
581     { rot [
582         temp0 ds-reg [] MOV
583         temp1 ds-reg -1 bootstrap-cells [+] MOV
584         temp3 ds-reg -2 bootstrap-cells [+] MOV
585         ds-reg -2 bootstrap-cells [+] temp1 MOV
586         ds-reg -1 bootstrap-cells [+] temp0 MOV
587         ds-reg [] temp3 MOV
588     ] }
589     { swap [
590         temp0 ds-reg [] MOV
591         temp1 ds-reg bootstrap-cell neg [+] MOV
592         ds-reg bootstrap-cell neg [+] temp0 MOV
593         ds-reg [] temp1 MOV
594     ] }
595     { swapd [
596         temp0 ds-reg -1 bootstrap-cells [+] MOV
597         temp1 ds-reg -2 bootstrap-cells [+] MOV
598         ds-reg -2 bootstrap-cells [+] temp0 MOV
599         ds-reg -1 bootstrap-cells [+] temp1 MOV
600     ] }
601
602     ! ## Signal handling
603     { leaf-signal-handler [
604         jit-signal-handler-prolog
605         jit-save-context
606         temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
607         temp0 CALL
608         jit-signal-handler-epilog
609         ! Pop the fake leaf frame along with our return address
610         leaf-stack-frame-size bootstrap-cell - RET
611     ] }
612     { signal-handler [
613         jit-signal-handler-prolog
614         jit-save-context
615         temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
616         temp0 CALL
617         jit-signal-handler-epilog
618         0 RET
619     ] }
620 } define-sub-primitives
621
622 [ "bootstrap.x86" forget-vocab ] with-compilation-unit