1 ! Copyright (C) 2007 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: alien alien.c-types arrays cpu.arm.assembler compiler
4 kernel kernel.private math namespaces words words.private
5 generator.registers generator.fixup generator cpu.architecture
7 IN: cpu.arm.architecture
11 ! ARM register assignments:
12 ! R0-R4, R7-R10 integer vregs
21 M: temp-reg v>operand drop R12 ;
23 M: int-regs return-reg drop R0 ;
24 M: int-regs param-regs drop { R0 R1 R2 R3 } ;
25 M: int-regs vregs drop { R0 R1 R2 R3 R4 R7 R8 R9 R10 } ;
28 M: float-regs param-regs drop { } ;
29 M: float-regs vregs drop { } ;
31 : <+/-> dup 0 < [ neg <-> ] [ <+> ] if ;
33 GENERIC: loc>operand ( loc -- reg addressing )
34 M: ds-loc loc>operand ds-loc-n cells neg ds-reg swap <+/-> ;
35 M: rs-loc loc>operand rs-loc-n cells neg rs-reg swap <+/-> ;
37 : load-cell ( reg -- )
51 ! Compute return address; we skip 3 instructions
55 ! Jump to target address
60 M: arm-backend load-indirect ( obj reg -- )
61 tuck load-cell rc-absolute-cell rel-literal
64 M: immediate load-literal
65 over v>operand small-enough? [
66 [ v>operand ] bi@ swap MOV
68 v>operand load-indirect
71 : lr-save ( n -- i ) cell - ;
72 : next-save ( n -- i ) 2 cells - ;
73 : xt-save ( n -- i ) 3 cells - ;
74 : factor-area-size 5 cells ;
76 M: arm-backend stack-frame ( n -- i )
77 factor-area-size + 8 align ;
79 M: arm-backend %save-word-xt ( -- )
82 M: arm-backend %save-dispatch-xt ( -- )
85 M: arm-backend %prologue ( n -- )
88 R11 SP pick next-save <+> STR
89 R12 SP pick xt-save <+> STR
90 LR SP rot lr-save <+> STR ;
92 M: arm-backend %epilogue ( n -- )
93 LR SP pick lr-save <+> LDR
96 : compile-dlsym ( symbol dll reg -- )
97 load-cell rc-absolute rel-dlsym ;
99 : %alien-global ( symbol dll reg -- )
100 [ compile-dlsym ] keep dup 0 <+> LDR ;
102 M: arm-backend %profiler-prologue ( -- )
103 #! We can clobber R0 here since it is undefined at the start
106 R0 R12 profile-count-offset <+> LDR
107 R0 R0 1 v>operand ADD
108 R0 R12 profile-count-offset <+> STR ;
110 M: arm-backend %call-label ( label -- ) BL ;
112 M: arm-backend %jump-label ( label -- ) B ;
114 : %prepare-primitive ( -- )
115 #! Save stack pointer to stack_chain->callstack_top, load XT
118 M: arm-backend %call-primitive ( word -- )
120 call-cell rc-absolute-cell rel-word ;
122 M: arm-backend %jump-primitive ( word -- )
124 ! Load target address
126 ! Jump to target address
129 0 , rc-absolute-cell rel-word ;
131 M: arm-backend %jump-t ( label -- )
132 "flag" operand f v>operand CMP NE B ;
134 : (%dispatch) ( word-table# -- )
135 #! Load jump table target address into reg.
136 "scratch" operand PC "n" operand 1 <LSR> ADD
137 "scratch" operand dup 0 <+> LDR
138 rc-indirect-arm rel-dispatch
139 "scratch" operand dup compiled-header-size ADD ;
141 M: arm-backend %call-dispatch ( word-table# -- )
144 "scratch" operand BLX
146 { +input+ { { f "n" } } }
147 { +scratch+ { { f "scratch" } } }
150 M: arm-backend %jump-dispatch ( word-table# -- )
156 { +input+ { { f "n" } } }
157 { +scratch+ { { f "scratch" } } }
160 M: arm-backend %return ( -- ) %epilogue-later PC LR MOV ;
162 M: arm-backend %unwind drop %return ;
164 M: arm-backend %peek >r v>operand r> loc>operand LDR ;
166 M: arm-backend %replace >r v>operand r> loc>operand STR ;
168 : (%inc) ( n reg -- )
169 dup rot cells dup 0 < [ neg SUB ] [ ADD ] if ;
171 M: arm-backend %inc-d ( n -- ) ds-reg (%inc) ;
173 M: arm-backend %inc-r ( n -- ) rs-reg (%inc) ;
175 : stack@ SP swap <+> ;
177 M: int-regs %save-param-reg drop swap stack@ STR ;
179 M: int-regs %load-param-reg drop swap stack@ LDR ;
181 M: stack-params %save-param-reg
183 R12 swap stack-frame* + stack@ LDR
184 R12 swap stack@ STR ;
186 M: stack-params %load-param-reg
189 R12 swap stack@ STR ;
191 M: arm-backend %prepare-unbox ( -- )
192 ! First parameter is top of stack
195 M: arm-backend %unbox ( n reg-class func -- )
196 ! Value must be in R0.
199 ! Store the return value on the C stack
200 over [ [ return-reg ] keep %save-param-reg ] [ 2drop ] if ;
202 M: arm-backend %unbox-long-long ( n func -- )
203 ! Value must be in R0:R1.
206 ! Store the return value on the C stack
209 R1 swap cell + stack@ STR
212 M: arm-backend %unbox-small-struct ( size -- )
213 #! Alien must be in R0.
215 "alien_offset" f %alien-invoke
219 M: arm-backend %unbox-large-struct ( n size -- )
220 #! Alien must be in R0.
221 ! Compute destination address
224 ! Copy the struct to the stack
225 "to_value_struct" f %alien-invoke ;
227 M: arm-backend %box ( n reg-class func -- )
228 ! If the source is a stack location, load it into freg #0.
229 ! If the source is f, then we assume the value is already in
232 over [ 0 over param-reg swap %load-param-reg ] [ 2drop ] if
235 M: arm-backend %box-long-long ( n func -- )
238 R1 swap cell + stack@ LDR
239 ] when* r> f %alien-invoke ;
241 M: arm-backend %box-small-struct ( size -- )
242 #! Box a 4-byte struct returned in R0.
244 "box_small_struct" f %alien-invoke ;
246 : temp@ stack-frame* factor-area-size - swap - ;
248 : struct-return@ ( size n -- n )
252 stack-frame* factor-area-size - swap -
255 M: arm-backend %prepare-box-struct ( size -- )
256 ! Compute target address for value struct return
257 R0 SP rot f struct-return@ ADD
258 ! Store it as the first parameter
261 M: arm-backend %box-large-struct ( n size -- )
262 ! Compute destination address
263 [ swap struct-return@ ] keep
266 ! Copy the struct from the C stack
267 "box_value_struct" f %alien-invoke ;
269 M: arm-backend struct-small-enough? ( size -- ? )
270 wince? [ drop f ] [ 4 <= ] if ;
272 M: arm-backend %prepare-alien-invoke
273 #! Save Factor stack pointers in case the C code calls a
274 #! callback which does a GC, which must reliably trace
276 "stack_chain" f R12 %alien-global
279 rs-reg R12 12 <+> STR ;
281 M: arm-backend %alien-invoke ( symbol dll -- )
282 call-cell rc-absolute-cell rel-dlsym ;
284 M: arm-backend %prepare-alien-indirect ( -- )
285 "unbox_alien" f %alien-invoke
286 R0 SP cell temp@ <+> STR ;
288 M: arm-backend %alien-indirect ( -- )
289 R12 SP cell temp@ <+> LDR
292 M: arm-backend %alien-callback ( quot -- )
294 "c_to_factor" f %alien-invoke ;
296 M: arm-backend %callback-value ( ctype -- )
297 ! Save top of data stack
299 R0 SP cell temp@ <+> STR
300 ! Restore data/call/retain stacks
301 "unnest_stacks" f %alien-invoke
302 ! Place former top of data stack in R0
303 R0 SP cell temp@ <+> LDR
307 M: arm-backend %cleanup ( alien-node -- ) drop ;
309 : %untag ( dest src -- ) BIN: 111 BIC ;
311 : %untag-fixnum ( dest src -- ) tag-bits get <ASR> MOV ;
313 : %tag-fixnum ( dest src -- ) tag-bits get <LSL> MOV ;
315 M: arm-backend value-structs? t ;
317 M: arm-backend small-enough? ( n -- ? ) 0 255 between? ;
319 M: long-long-type c-type-stack-align? drop wince? not ;
321 M: arm-backend fp-shadows-int? ( -- ? ) f ;
324 M: arm-backend %unbox-byte-array ( dst src -- )
325 [ v>operand ] bi@ byte-array-offset ADD ;
327 M: arm-backend %unbox-alien ( dst src -- )
328 [ v>operand ] bi@ alien-offset <+> LDR ;
330 M: arm-backend %unbox-f ( dst src -- )
331 drop v>operand 0 MOV ;
333 M: arm-backend %unbox-any-c-ptr ( dst src -- )
334 #! We need three registers here. R11 and R12 are reserved
335 #! temporary registers. The third one is R14, which we have
341 ! Address is computed in R11
343 ! Load object into R12
344 R12 swap v>operand MOV
345 ! We come back here with displaced aliens
346 "start" resolve-label
351 ! Is the object an alien?
352 R14 R12 header-offset <+/-> LDR
353 R14 alien type-number tag-fixnum CMP
354 ! Add byte array address to address being computed
356 ! Add an offset to start of byte array's data area
357 R11 R11 byte-array-offset NE ADD
359 ! If alien, load the offset
360 R14 R12 alien-offset <+/-> LDR
361 ! Add it to address being computed
363 ! Now recurse on the underlying alien
364 R12 R12 underlying-alien-offset <+/-> LDR
367 ! Done, store address in destination register