2 % (c) The AQUA Project, Glasgow University, 1993-1995
6 #include "HsVersions.h"
9 gmpTake1Return1, gmpTake2Return1, gmpTake2Return2,
10 gmpCompare, gmpInteger2Int, gmpInt2Integer, gmpString2Integer,
11 encodeFloatingKind, decodeFloatingKind
14 IMPORT_Trace -- ToDo: rm debugging
17 import CgCompInfo ( mIN_MP_INT_SIZE )
20 import AbsPrel ( PrimOp(..)
21 IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
22 IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
24 import SMRep ( SMRep(..), SMSpecRepKind, SMUpdateKind(..) )
36 -> [CAddrMode] -- result (3 parts)
37 -> FAST_STRING -- function name
38 -> [CAddrMode] -- argument (3 parts)
39 -> SUniqSM StixTreeList
41 argument1 = mpStruct 1 -- out here to avoid CAF (sigh)
42 argument2 = mpStruct 2
46 init2 = StCall SLIT("mpz_init") VoidKind [result2]
47 init3 = StCall SLIT("mpz_init") VoidKind [result3]
48 init4 = StCall SLIT("mpz_init") VoidKind [result4]
50 gmpTake1Return1 target res rtn arg =
51 let [ar,sr,dr] = map (amodeToStix target) res
52 [liveness, aa,sa,da] = map (amodeToStix target) arg
53 space = mpSpace target 2 1 [sa]
54 oldHp = StIndex PtrKind stgHp (StPrim IntNegOp [space])
55 safeHp = saveLoc target Hp
56 save = StAssign PtrKind safeHp oldHp
57 (a1,a2,a3) = toStruct target argument1 (aa,sa,da)
58 mpz_op = StCall rtn VoidKind [result2, argument1]
59 restore = StAssign PtrKind stgHp safeHp
60 (r1,r2,r3) = fromStruct target result2 (ar,sr,dr)
62 heapCheck target liveness space (StInt 0)
63 `thenSUs` \ heap_chk ->
66 (\xs -> a1 : a2 : a3 : save : init2 : mpz_op : r1 : r2 : r3 : restore : xs))
70 -> [CAddrMode] -- result (3 parts)
71 -> FAST_STRING -- function name
72 -> [CAddrMode] -- arguments (3 parts each)
73 -> SUniqSM StixTreeList
75 gmpTake2Return1 target res rtn args =
76 let [ar,sr,dr] = map (amodeToStix target) res
77 [liveness, aa1,sa1,da1, aa2,sa2,da2] = map (amodeToStix target) args
78 space = mpSpace target 3 1 [sa1, sa2]
79 oldHp = StIndex PtrKind stgHp (StPrim IntNegOp [space])
80 safeHp = saveLoc target Hp
81 save = StAssign PtrKind safeHp oldHp
82 (a1,a2,a3) = toStruct target argument1 (aa1,sa1,da1)
83 (a4,a5,a6) = toStruct target argument2 (aa2,sa2,da2)
84 mpz_op = StCall rtn VoidKind [result3, argument1, argument2]
85 restore = StAssign PtrKind stgHp safeHp
86 (r1,r2,r3) = fromStruct target result3 (ar,sr,dr)
88 heapCheck target liveness space (StInt 0)
89 `thenSUs` \ heap_chk ->
92 (\xs -> a1 : a2 : a3 : a4 : a5 : a6
93 : save : init3 : mpz_op : r1 : r2 : r3 : restore : xs))
97 -> [CAddrMode] -- results (3 parts each)
98 -> FAST_STRING -- function name
99 -> [CAddrMode] -- arguments (3 parts each)
100 -> SUniqSM StixTreeList
102 gmpTake2Return2 target res rtn args =
103 let [ar1,sr1,dr1, ar2,sr2,dr2] = map (amodeToStix target) res
104 [liveness, aa1,sa1,da1, aa2,sa2,da2] = map (amodeToStix target) args
105 space = StPrim IntMulOp [mpSpace target 2 1 [sa1, sa2], StInt 2]
106 oldHp = StIndex PtrKind stgHp (StPrim IntNegOp [space])
107 safeHp = saveLoc target Hp
108 save = StAssign PtrKind safeHp oldHp
109 (a1,a2,a3) = toStruct target argument1 (aa1,sa1,da1)
110 (a4,a5,a6) = toStruct target argument2 (aa2,sa2,da2)
111 mpz_op = StCall rtn VoidKind [result3, result4, argument1, argument2]
112 restore = StAssign PtrKind stgHp safeHp
113 (r1,r2,r3) = fromStruct target result3 (ar1,sr1,dr1)
114 (r4,r5,r6) = fromStruct target result4 (ar2,sr2,dr2)
117 heapCheck target liveness space (StInt 0)
118 `thenSUs` \ heap_chk ->
120 returnSUs (heap_chk .
121 (\xs -> a1 : a2 : a3 : a4 : a5 : a6
122 : save : init3 : init4 : mpz_op
123 : r1 : r2 : r3 : r4 : r5 : r6 : restore : xs))
127 Although gmpCompare doesn't allocate space, it does temporarily use some
128 space just beyond the heap pointer. This is safe, because the enclosing
129 routine has already guaranteed that this space will be available.
130 (See ``primOpHeapRequired.'')
136 -> CAddrMode -- result (boolean)
137 -> [CAddrMode] -- arguments (3 parts each)
138 -> SUniqSM StixTreeList
140 gmpCompare target res args =
141 let result = amodeToStix target res
142 [hp, aa1,sa1,da1, aa2,sa2,da2] = map (amodeToStix target) args
144 argument2 = StIndex IntKind hp (StInt (toInteger mpIntSize))
145 (a1,a2,a3) = toStruct target argument1 (aa1,sa1,da1)
146 (a4,a5,a6) = toStruct target argument2 (aa2,sa2,da2)
147 mpz_cmp = StCall SLIT("mpz_cmp") IntKind [argument1, argument2]
148 r1 = StAssign IntKind result mpz_cmp
150 returnSUs (\xs -> a1 : a2 : a3 : a4 : a5 : a6 : r1 : xs)
154 See the comment above regarding the heap check (or lack thereof).
160 -> CAddrMode -- result
161 -> [CAddrMode] -- argument (3 parts)
162 -> SUniqSM StixTreeList
164 gmpInteger2Int target res args =
165 let result = amodeToStix target res
166 [hp, aa,sa,da] = map (amodeToStix target) args
167 (a1,a2,a3) = toStruct target hp (aa,sa,da)
168 mpz_get_si = StCall SLIT("mpz_get_si") IntKind [hp]
169 r1 = StAssign IntKind result mpz_get_si
171 returnSUs (\xs -> a1 : a2 : a3 : r1 : xs)
173 arrayOfData_info = sStLitLbl SLIT("ArrayOfData_info")
177 -> [CAddrMode] -- result (3 parts)
178 -> [CAddrMode] -- allocated heap, int to convert
179 -> SUniqSM StixTreeList
181 gmpInt2Integer target res args@[_, n] =
182 getUniqLabelNCG `thenSUs` \ zlbl ->
183 getUniqLabelNCG `thenSUs` \ nlbl ->
184 getUniqLabelNCG `thenSUs` \ jlbl ->
185 let [ar,sr,dr] = map (amodeToStix target) res
186 [hp, i] = map (amodeToStix target) args
187 h1 = StAssign PtrKind (StInd PtrKind hp) arrayOfData_info
188 size = varHeaderSize target (DataRep 0) + mIN_MP_INT_SIZE
189 h2 = StAssign IntKind (StInd IntKind (StIndex IntKind hp (StInt 1)))
190 (StInt (toInteger size))
191 cts = StInd IntKind (StIndex IntKind hp (dataHS target))
192 test1 = StPrim IntEqOp [i, StInt 0]
193 test2 = StPrim IntLtOp [i, StInt 0]
194 cjmp1 = StCondJump zlbl test1
195 cjmp2 = StCondJump nlbl test2
197 p1 = StAssign IntKind cts i
198 p2 = StAssign IntKind sr (StInt 1)
199 p3 = StJump (StCLbl jlbl)
202 n1 = StAssign IntKind cts (StPrim IntNegOp [i])
203 n2 = StAssign IntKind sr (StInt (-1))
204 n3 = StJump (StCLbl jlbl)
207 z1 = StAssign IntKind sr (StInt 0)
210 a1 = StAssign IntKind ar (StInt 1)
211 a2 = StAssign PtrKind dr hp
215 CLit (MachInt c _) ->
216 if c == 0 then h1 : h2 : z1 : a1 : a2 : xs
217 else if c > 0 then h1 : h2 : p1 : p2 : a1 : a2 : xs
218 else h1 : h2 : n1 : n2 : a1 : a2 : xs
219 _ -> h1 : h2 : cjmp1 : cjmp2 : p1 : p2 : p3
220 : n0 : n1 : n2 : n3 : z0 : z1
225 -> [CAddrMode] -- result (3 parts)
226 -> [CAddrMode] -- liveness, string
227 -> SUniqSM StixTreeList
229 gmpString2Integer target res [liveness, str] =
230 getUniqLabelNCG `thenSUs` \ ulbl ->
231 let [ar,sr,dr] = map (amodeToStix target) res
233 (CString s) -> _LENGTH_ s
234 (CLit (MachStr s)) -> _LENGTH_ s
235 _ -> panic "String2Integer"
236 space = len `quot` 8 + 17 + mpIntSize +
237 varHeaderSize target (DataRep 0) + fixedHeaderSize target
238 oldHp = StIndex PtrKind stgHp (StInt (toInteger (-space)))
239 safeHp = saveLoc target Hp
240 save = StAssign PtrKind safeHp oldHp
241 result = StIndex IntKind stgHpLim (StInt (toInteger (-mpIntSize)))
242 set_str = StCall SLIT("mpz_init_set_str") IntKind
243 [result, amodeToStix target str, StInt 10]
244 test = StPrim IntEqOp [set_str, StInt 0]
245 cjmp = StCondJump ulbl test
246 abort = StCall SLIT("abort") VoidKind []
248 restore = StAssign PtrKind stgHp safeHp
249 (a1,a2,a3) = fromStruct target result (ar,sr,dr)
251 macroCode target HEAP_CHK [liveness, mkIntCLit space, mkIntCLit_0]
252 `thenSUs` \ heap_chk ->
254 returnSUs (heap_chk .
255 (\xs -> save : cjmp : abort : join : a1 : a2 : a3 : restore : xs))
257 mkIntCLit_0 = mkIntCLit 0 -- out here to avoid CAF (sigh)
262 -> [CAddrMode] -- result
263 -> [CAddrMode] -- heap pointer for result, integer argument (3 parts), exponent
264 -> SUniqSM StixTreeList
266 encodeFloatingKind pk target [res] args =
267 let result = amodeToStix target res
268 [hp, aa,sa,da, expon] = map (amodeToStix target) args
269 pk' = if sizeof target FloatKind == sizeof target DoubleKind then DoubleKind
271 (a1,a2,a3) = toStruct target hp (aa,sa,da)
273 FloatKind -> SLIT("__encodeFloat")
274 DoubleKind -> SLIT("__encodeDouble")
275 _ -> panic "encodeFloatingKind"
276 encode = StCall fn pk' [hp, expon]
277 r1 = StAssign pk' result encode
279 returnSUs (\xs -> a1 : a2 : a3 : r1 : xs)
284 -> [CAddrMode] -- exponent result, integer result (3 parts)
285 -> [CAddrMode] -- heap pointer for exponent, floating argument
286 -> SUniqSM StixTreeList
288 decodeFloatingKind pk target res args =
289 let [exponr,ar,sr,dr] = map (amodeToStix target) res
290 [hp, arg] = map (amodeToStix target) args
291 pk' = if sizeof target FloatKind == sizeof target DoubleKind then DoubleKind
293 setup = StAssign PtrKind mpData_mantissa (StIndex IntKind hp (StInt 1))
295 FloatKind -> SLIT("__decodeFloat")
296 DoubleKind -> SLIT("__decodeDouble")
297 _ -> panic "decodeFloatingKind"
298 decode = StCall fn VoidKind [mantissa, hp, arg]
299 (a1,a2,a3) = fromStruct target mantissa (ar,sr,dr)
300 a4 = StAssign IntKind exponr (StInd IntKind hp)
302 returnSUs (\xs -> setup : decode : a1 : a2 : a3 : a4 : xs)
304 mantissa = mpStruct 1 -- out here to avoid CAF (sigh)
305 mpData_mantissa = mpData mantissa
308 Support for the Gnu GMP multi-precision package.
314 mpAlloc, mpSize, mpData :: StixTree -> StixTree
315 mpAlloc base = StInd IntKind base
316 mpSize base = StInd IntKind (StIndex IntKind base (StInt 1))
317 mpData base = StInd PtrKind (StIndex IntKind base (StInt 2))
321 -> Int -- gmp structures needed
322 -> Int -- number of results
323 -> [StixTree] -- sizes to add for estimating result size
324 -> StixTree -- total space
326 mpSpace target gmp res sizes =
327 foldr sum (StPrim IntAddOp [fixed, hdrs]) sizes
329 sum x y = StPrim IntAddOp [StPrim IntAbsOp [x], y]
330 fixed = StInt (toInteger (17 * res + gmp * mpIntSize))
331 hdrs = StPrim IntMulOp [dataHS target, StInt (toInteger res)]
335 We don't have a truly portable way of allocating local temporaries, so we
336 cheat and use space at the end of the heap. (Thus, negative offsets from
337 HpLim are our temporaries.) Note that you must have performed a heap check
338 which includes the space needed for these temporaries before you use them.
342 mpStruct :: Int -> StixTree
343 mpStruct n = StIndex IntKind stgHpLim (StInt (toInteger (-(n * mpIntSize))))
348 -> (StixTree, StixTree, StixTree)
349 -> (StixTree, StixTree, StixTree)
351 toStruct target str (alloc,size,arr) =
353 f1 = StAssign IntKind (mpAlloc str) alloc
354 f2 = StAssign IntKind (mpSize str) size
355 f3 = StAssign PtrKind (mpData str) (StIndex PtrKind arr (dataHS target))
362 -> (StixTree, StixTree, StixTree)
363 -> (StixTree, StixTree, StixTree)
365 fromStruct target str (alloc,size,arr) =
367 e1 = StAssign IntKind alloc (mpAlloc str)
368 e2 = StAssign IntKind size (mpSize str)
369 e3 = StAssign PtrKind arr (StIndex PtrKind (mpData str)
370 (StPrim IntNegOp [dataHS target]))