2 % (c) The AQUA Project, Glasgow University, 1993-1996
6 #include "HsVersions.h"
9 gmpTake1Return1, gmpTake2Return1, gmpTake2Return2, gmpCompare,
10 gmpInteger2Int, gmpInt2Integer, gmpString2Integer,
11 encodeFloatingKind, decodeFloatingKind
15 IMPORT_DELOOPER(NcgLoop) ( amodeToStix )
18 #if __GLASGOW_HASKELL__ >= 202
19 import MachRegs hiding (Addr)
24 import AbsCSyn -- bits and bobs...
25 import Constants ( mIN_MP_INT_SIZE )
26 import Literal ( Literal(..) )
27 import OrdList ( OrdList )
28 import PrimOp ( PrimOp(..) )
29 import PrimRep ( PrimRep(..) )
30 import SMRep ( SMRep(..), SMSpecRepKind, SMUpdateKind )
31 import Stix ( getUniqLabelNCG, sStLitLbl, stgHp, stgHpLim,
32 StixTree(..), SYN_IE(StixTreeList),
35 import StixMacro ( macroCode, heapCheck )
36 import UniqSupply ( returnUs, thenUs, SYN_IE(UniqSM) )
42 :: (CAddrMode,CAddrMode,CAddrMode) -- result (3 parts)
43 -> FAST_STRING -- function name
44 -> (CAddrMode, CAddrMode,CAddrMode,CAddrMode)
46 -> UniqSM StixTreeList
48 argument1 = mpStruct 1 -- out here to avoid CAF (sigh)
49 argument2 = mpStruct 2
53 init2 = StCall SLIT("mpz_init") VoidRep [result2]
54 init3 = StCall SLIT("mpz_init") VoidRep [result3]
55 init4 = StCall SLIT("mpz_init") VoidRep [result4]
57 gmpTake1Return1 res@(car,csr,cdr) rtn arg@(clive,caa,csa,cda)
62 liveness= amodeToStix clive
67 space = mpSpace 2 1 [sa]
68 oldHp = StIndex PtrRep stgHp (StPrim IntNegOp [space])
70 save = StAssign PtrRep safeHp oldHp
71 (a1,a2,a3) = toStruct argument1 (aa,sa,da)
72 mpz_op = StCall rtn VoidRep [result2, argument1]
73 restore = StAssign PtrRep stgHp safeHp
74 (r1,r2,r3) = fromStruct result2 (ar,sr,dr)
76 heapCheck liveness space (StInt 0) `thenUs` \ heap_chk ->
79 (\xs -> a1 : a2 : a3 : save : init2 : mpz_op : r1 : r2 : r3 : restore : xs))
82 :: (CAddrMode,CAddrMode,CAddrMode) -- result (3 parts)
83 -> FAST_STRING -- function name
84 -> (CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode)
85 -- liveness + 2 arguments (3 parts each)
86 -> UniqSM StixTreeList
88 gmpTake2Return1 res@(car,csr,cdr) rtn args@(clive, caa1,csa1,cda1, caa2,csa2,cda2)
93 liveness= amodeToStix clive
94 aa1 = amodeToStix caa1
95 sa1 = amodeToStix csa1
96 da1 = amodeToStix cda1
97 aa2 = amodeToStix caa2
98 sa2 = amodeToStix csa2
99 da2 = amodeToStix cda2
101 space = mpSpace 3 1 [sa1, sa2]
102 oldHp = StIndex PtrRep stgHp (StPrim IntNegOp [space])
104 save = StAssign PtrRep safeHp oldHp
105 (a1,a2,a3) = toStruct argument1 (aa1,sa1,da1)
106 (a4,a5,a6) = toStruct argument2 (aa2,sa2,da2)
107 mpz_op = StCall rtn VoidRep [result3, argument1, argument2]
108 restore = StAssign PtrRep stgHp safeHp
109 (r1,r2,r3) = fromStruct result3 (ar,sr,dr)
111 heapCheck liveness space (StInt 0) `thenUs` \ heap_chk ->
114 (\xs -> a1 : a2 : a3 : a4 : a5 : a6
115 : save : init3 : mpz_op : r1 : r2 : r3 : restore : xs))
118 :: (CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode)
119 -- 2 results (3 parts each)
120 -> FAST_STRING -- function name
121 -> (CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode)
122 -- liveness + 2 arguments (3 parts each)
123 -> UniqSM StixTreeList
125 gmpTake2Return2 res@(car1,csr1,cdr1, car2,csr2,cdr2)
126 rtn args@(clive, caa1,csa1,cda1, caa2,csa2,cda2)
128 ar1 = amodeToStix car1
129 sr1 = amodeToStix csr1
130 dr1 = amodeToStix cdr1
131 ar2 = amodeToStix car2
132 sr2 = amodeToStix csr2
133 dr2 = amodeToStix cdr2
134 liveness= amodeToStix clive
135 aa1 = amodeToStix caa1
136 sa1 = amodeToStix csa1
137 da1 = amodeToStix cda1
138 aa2 = amodeToStix caa2
139 sa2 = amodeToStix csa2
140 da2 = amodeToStix cda2
142 space = StPrim IntMulOp [mpSpace 2 1 [sa1, sa2], StInt 2]
143 oldHp = StIndex PtrRep stgHp (StPrim IntNegOp [space])
145 save = StAssign PtrRep safeHp oldHp
146 (a1,a2,a3) = toStruct argument1 (aa1,sa1,da1)
147 (a4,a5,a6) = toStruct argument2 (aa2,sa2,da2)
148 mpz_op = StCall rtn VoidRep [result3, result4, argument1, argument2]
149 restore = StAssign PtrRep stgHp safeHp
150 (r1,r2,r3) = fromStruct result3 (ar1,sr1,dr1)
151 (r4,r5,r6) = fromStruct result4 (ar2,sr2,dr2)
154 heapCheck liveness space (StInt 0) `thenUs` \ heap_chk ->
157 (\xs -> a1 : a2 : a3 : a4 : a5 : a6
158 : save : init3 : init4 : mpz_op
159 : r1 : r2 : r3 : r4 : r5 : r6 : restore : xs))
162 Although gmpCompare doesn't allocate space, it does temporarily use
163 some space just beyond the heap pointer. This is safe, because the
164 enclosing routine has already guaranteed that this space will be
165 available. (See ``primOpHeapRequired.'')
169 :: CAddrMode -- result (boolean)
170 -> (CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode)
171 -- alloc hp + 2 arguments (3 parts each)
172 -> UniqSM StixTreeList
174 gmpCompare res args@(chp, caa1,csa1,cda1, caa2,csa2,cda2)
176 result = amodeToStix res
178 aa1 = amodeToStix caa1
179 sa1 = amodeToStix csa1
180 da1 = amodeToStix cda1
181 aa2 = amodeToStix caa2
182 sa2 = amodeToStix csa2
183 da2 = amodeToStix cda2
186 argument2 = StIndex IntRep hp (StInt (toInteger mpIntSize))
187 (a1,a2,a3) = toStruct argument1 (aa1,sa1,da1)
188 (a4,a5,a6) = toStruct argument2 (aa2,sa2,da2)
189 mpz_cmp = StCall SLIT("mpz_cmp") IntRep [argument1, argument2]
190 r1 = StAssign IntRep result mpz_cmp
192 returnUs (\xs -> a1 : a2 : a3 : a4 : a5 : a6 : r1 : xs)
195 See the comment above regarding the heap check (or lack thereof).
199 :: CAddrMode -- result
200 -> (CAddrMode, CAddrMode,CAddrMode,CAddrMode) -- alloc hp + argument (3 parts)
201 -> UniqSM StixTreeList
203 gmpInteger2Int res args@(chp, caa,csa,cda)
205 result = amodeToStix res
211 (a1,a2,a3) = toStruct hp (aa,sa,da)
212 mpz_get_si = StCall SLIT("mpz_get_si") IntRep [hp]
213 r1 = StAssign IntRep result mpz_get_si
215 returnUs (\xs -> a1 : a2 : a3 : r1 : xs)
217 arrayOfData_info = sStLitLbl SLIT("ArrayOfData_info")
221 :: (CAddrMode, CAddrMode, CAddrMode) -- result (3 parts)
222 -> (CAddrMode, CAddrMode) -- allocated heap, Int to convert
223 -> UniqSM StixTreeList
225 gmpInt2Integer res@(car,csr,cdr) args@(chp, n)
226 = getUniqLabelNCG `thenUs` \ zlbl ->
227 getUniqLabelNCG `thenUs` \ nlbl ->
228 getUniqLabelNCG `thenUs` \ jlbl ->
236 h1 = StAssign PtrRep (StInd PtrRep hp) arrayOfData_info
237 size = varHdrSizeInWords (DataRep 0) + mIN_MP_INT_SIZE
238 h2 = StAssign IntRep (StInd IntRep (StIndex IntRep hp (StInt 1)))
239 (StInt (toInteger size))
240 cts = StInd IntRep (StIndex IntRep hp dataHS)
241 test1 = StPrim IntEqOp [i, StInt 0]
242 test2 = StPrim IntLtOp [i, StInt 0]
243 cjmp1 = StCondJump zlbl test1
244 cjmp2 = StCondJump nlbl test2
246 p1 = StAssign IntRep cts i
247 p2 = StAssign IntRep sr (StInt 1)
248 p3 = StJump (StCLbl jlbl)
251 n1 = StAssign IntRep cts (StPrim IntNegOp [i])
252 n2 = StAssign IntRep sr (StInt (-1))
253 n3 = StJump (StCLbl jlbl)
256 z1 = StAssign IntRep sr (StInt 0)
259 a1 = StAssign IntRep ar (StInt 1)
260 a2 = StAssign PtrRep dr hp
264 CLit (MachInt c _) ->
265 if c == 0 then h1 : h2 : z1 : a1 : a2 : xs
266 else if c > 0 then h1 : h2 : p1 : p2 : a1 : a2 : xs
267 else h1 : h2 : n1 : n2 : a1 : a2 : xs
268 _ -> h1 : h2 : cjmp1 : cjmp2 : p1 : p2 : p3
269 : n0 : n1 : n2 : n3 : z0 : z1
273 :: (CAddrMode, CAddrMode, CAddrMode) -- result (3 parts)
274 -> (CAddrMode, CAddrMode) -- liveness, string
275 -> UniqSM StixTreeList
277 gmpString2Integer res@(car,csr,cdr) (liveness, str)
278 = getUniqLabelNCG `thenUs` \ ulbl ->
285 (CString s) -> _LENGTH_ s
286 (CLit (MachStr s)) -> _LENGTH_ s
287 _ -> panic "String2Integer"
288 space = len `quot` 8 + 17 + mpIntSize +
289 varHdrSizeInWords (DataRep 0) + fixedHdrSizeInWords
290 oldHp = StIndex PtrRep stgHp (StInt (toInteger (-space)))
292 save = StAssign PtrRep safeHp oldHp
293 result = StIndex IntRep stgHpLim (StInt (toInteger (-mpIntSize)))
294 set_str = StCall SLIT("mpz_init_set_str") IntRep
295 [result, amodeToStix str, StInt 10]
296 test = StPrim IntEqOp [set_str, StInt 0]
297 cjmp = StCondJump ulbl test
298 abort = StCall SLIT("abort") VoidRep []
300 restore = StAssign PtrRep stgHp safeHp
301 (a1,a2,a3) = fromStruct result (ar,sr,dr)
303 macroCode HEAP_CHK [liveness, mkIntCLit space, mkIntCLit_0]
304 `thenUs` \ heap_chk ->
307 (\xs -> save : cjmp : abort : join : a1 : a2 : a3 : restore : xs))
309 mkIntCLit_0 = mkIntCLit 0 -- out here to avoid CAF (sigh)
313 -> CAddrMode -- result
314 -> (CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode)
315 -- heap pointer for result, integer argument (3 parts), exponent
316 -> UniqSM StixTreeList
318 encodeFloatingKind pk res args@(chp, caa,csa,cda, cexpon)
320 result = amodeToStix res
325 expon = amodeToStix cexpon
327 pk' = if sizeOf FloatRep == sizeOf DoubleRep
330 (a1,a2,a3) = toStruct hp (aa,sa,da)
332 FloatRep -> SLIT("__encodeFloat")
333 DoubleRep -> SLIT("__encodeDouble")
334 _ -> panic "encodeFloatingKind"
335 encode = StCall fn pk' [hp, expon]
336 r1 = StAssign pk' result encode
338 returnUs (\xs -> a1 : a2 : a3 : r1 : xs)
342 -> (CAddrMode, CAddrMode, CAddrMode, CAddrMode)
343 -- exponent result, integer result (3 parts)
344 -> (CAddrMode, CAddrMode)
345 -- heap pointer for exponent, floating argument
346 -> UniqSM StixTreeList
348 decodeFloatingKind pk res@(cexponr,car,csr,cdr) args@(chp, carg)
350 exponr = amodeToStix cexponr
355 arg = amodeToStix carg
357 pk' = if sizeOf FloatRep == sizeOf DoubleRep
360 setup = StAssign PtrRep mpData_mantissa (StIndex IntRep hp (StInt 1))
362 FloatRep -> SLIT("__decodeFloat")
363 DoubleRep -> SLIT("__decodeDouble")
364 _ -> panic "decodeFloatingKind"
365 decode = StCall fn VoidRep [mantissa, hp, arg]
366 (a1,a2,a3) = fromStruct mantissa (ar,sr,dr)
367 a4 = StAssign IntRep exponr (StInd IntRep hp)
369 returnUs (\xs -> setup : decode : a1 : a2 : a3 : a4 : xs)
371 mantissa = mpStruct 1 -- out here to avoid CAF (sigh)
372 mpData_mantissa = mpData mantissa
375 Support for the Gnu GMP multi-precision package.
380 mpAlloc, mpSize, mpData :: StixTree -> StixTree
381 mpAlloc base = StInd IntRep base
382 mpSize base = StInd IntRep (StIndex IntRep base (StInt 1))
383 mpData base = StInd PtrRep (StIndex IntRep base (StInt 2))
386 :: Int -- gmp structures needed
387 -> Int -- number of results
388 -> [StixTree] -- sizes to add for estimating result size
389 -> StixTree -- total space
391 mpSpace gmp res sizes
392 = foldr sum (StPrim IntAddOp [fixed, hdrs]) sizes
394 sum x y = StPrim IntAddOp [StPrim IntAbsOp [x], y]
395 fixed = StInt (toInteger (17 * res + gmp * mpIntSize))
396 hdrs = StPrim IntMulOp [dataHS, StInt (toInteger res)]
399 We don't have a truly portable way of allocating local temporaries, so
400 we cheat and use space at the end of the heap. (Thus, negative
401 offsets from HpLim are our temporaries.) Note that you must have
402 performed a heap check which includes the space needed for these
403 temporaries before you use them.
406 mpStruct :: Int -> StixTree
407 mpStruct n = StIndex IntRep stgHpLim (StInt (toInteger (-(n * mpIntSize))))
411 -> (StixTree, StixTree, StixTree)
412 -> (StixTree, StixTree, StixTree)
414 toStruct str (alloc,size,arr)
416 f1 = StAssign IntRep (mpAlloc str) alloc
417 f2 = StAssign IntRep (mpSize str) size
418 f3 = StAssign PtrRep (mpData str) (StIndex PtrRep arr dataHS)
424 -> (StixTree, StixTree, StixTree)
425 -> (StixTree, StixTree, StixTree)
427 fromStruct str (alloc,size,arr)
429 e1 = StAssign IntRep alloc (mpAlloc str)
430 e2 = StAssign IntRep size (mpSize str)
431 e3 = StAssign PtrRep arr (StIndex PtrRep (mpData str)
432 (StPrim IntNegOp [dataHS]))