2 % (c) The AQUA Project, Glasgow University, 1993-1996
7 gmpTake1Return1, gmpTake2Return1, gmpTake2Return2, gmpCompare,
8 gmpInteger2Int, gmpInteger2Word,
9 gmpInt2Integer, gmpString2Integer,
10 encodeFloatingKind, decodeFloatingKind
13 #include "HsVersions.h"
15 import {-# SOURCE #-} StixPrim ( amodeToStix )
19 import AbsCSyn -- bits and bobs...
20 import CallConv ( cCallConv )
21 import Constants ( mIN_MP_INT_SIZE )
22 import Literal ( Literal(..) )
23 import OrdList ( OrdList )
24 import PrimOp ( PrimOp(..) )
25 import PrimRep ( PrimRep(..) )
26 import SMRep ( SMRep(..), SMSpecRepKind, SMUpdateKind )
27 import Stix ( getUniqLabelNCG, sStLitLbl, stgHp, stgHpLim,
28 StixTree(..), StixTreeList,
31 import StixMacro ( macroCode, heapCheck )
32 import UniqSupply ( returnUs, thenUs, UniqSM )
38 :: (CAddrMode,CAddrMode,CAddrMode) -- result (3 parts)
39 -> FAST_STRING -- function name
40 -> (CAddrMode, CAddrMode,CAddrMode,CAddrMode)
42 -> UniqSM StixTreeList
44 argument1 = mpStruct 1 -- out here to avoid CAF (sigh)
45 argument2 = mpStruct 2
49 init2 = StCall SLIT("mpz_init") cCallConv VoidRep [result2]
50 init3 = StCall SLIT("mpz_init") cCallConv VoidRep [result3]
51 init4 = StCall SLIT("mpz_init") cCallConv VoidRep [result4]
53 gmpTake1Return1 res@(car,csr,cdr) rtn arg@(clive,caa,csa,cda)
58 liveness= amodeToStix clive
63 space = mpSpace 2 1 [sa]
64 oldHp = StIndex PtrRep stgHp (StPrim IntNegOp [space])
66 save = StAssign PtrRep safeHp oldHp
67 (a1,a2,a3) = toStruct argument1 (aa,sa,da)
68 mpz_op = StCall rtn cCallConv VoidRep [result2, argument1]
69 restore = StAssign PtrRep stgHp safeHp
70 (r1,r2,r3) = fromStruct result2 (ar,sr,dr)
72 heapCheck liveness space (StInt 0) `thenUs` \ heap_chk ->
75 (\xs -> a1 : a2 : a3 : save : init2 : mpz_op : r1 : r2 : r3 : restore : xs))
78 :: (CAddrMode,CAddrMode,CAddrMode) -- result (3 parts)
79 -> FAST_STRING -- function name
80 -> (CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode)
81 -- liveness + 2 arguments (3 parts each)
82 -> UniqSM StixTreeList
84 gmpTake2Return1 res@(car,csr,cdr) rtn args@(clive, caa1,csa1,cda1, caa2,csa2,cda2)
89 liveness= amodeToStix clive
90 aa1 = amodeToStix caa1
91 sa1 = amodeToStix csa1
92 da1 = amodeToStix cda1
93 aa2 = amodeToStix caa2
94 sa2 = amodeToStix csa2
95 da2 = amodeToStix cda2
97 space = mpSpace 3 1 [sa1, sa2]
98 oldHp = StIndex PtrRep stgHp (StPrim IntNegOp [space])
100 save = StAssign PtrRep safeHp oldHp
101 (a1,a2,a3) = toStruct argument1 (aa1,sa1,da1)
102 (a4,a5,a6) = toStruct argument2 (aa2,sa2,da2)
103 mpz_op = StCall rtn cCallConv VoidRep [result3, argument1, argument2]
104 restore = StAssign PtrRep stgHp safeHp
105 (r1,r2,r3) = fromStruct result3 (ar,sr,dr)
107 heapCheck liveness space (StInt 0) `thenUs` \ heap_chk ->
110 (\xs -> a1 : a2 : a3 : a4 : a5 : a6
111 : save : init3 : mpz_op : r1 : r2 : r3 : restore : xs))
114 :: (CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode)
115 -- 2 results (3 parts each)
116 -> FAST_STRING -- function name
117 -> (CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode)
118 -- liveness + 2 arguments (3 parts each)
119 -> UniqSM StixTreeList
121 gmpTake2Return2 res@(car1,csr1,cdr1, car2,csr2,cdr2)
122 rtn args@(clive, caa1,csa1,cda1, caa2,csa2,cda2)
124 ar1 = amodeToStix car1
125 sr1 = amodeToStix csr1
126 dr1 = amodeToStix cdr1
127 ar2 = amodeToStix car2
128 sr2 = amodeToStix csr2
129 dr2 = amodeToStix cdr2
130 liveness= amodeToStix clive
131 aa1 = amodeToStix caa1
132 sa1 = amodeToStix csa1
133 da1 = amodeToStix cda1
134 aa2 = amodeToStix caa2
135 sa2 = amodeToStix csa2
136 da2 = amodeToStix cda2
138 space = StPrim IntMulOp [mpSpace 2 1 [sa1, sa2], StInt 2]
139 oldHp = StIndex PtrRep stgHp (StPrim IntNegOp [space])
141 save = StAssign PtrRep safeHp oldHp
142 (a1,a2,a3) = toStruct argument1 (aa1,sa1,da1)
143 (a4,a5,a6) = toStruct argument2 (aa2,sa2,da2)
144 mpz_op = StCall rtn cCallConv VoidRep [result3, result4, argument1, argument2]
145 restore = StAssign PtrRep stgHp safeHp
146 (r1,r2,r3) = fromStruct result3 (ar1,sr1,dr1)
147 (r4,r5,r6) = fromStruct result4 (ar2,sr2,dr2)
150 heapCheck liveness space (StInt 0) `thenUs` \ heap_chk ->
153 (\xs -> a1 : a2 : a3 : a4 : a5 : a6
154 : save : init3 : init4 : mpz_op
155 : r1 : r2 : r3 : r4 : r5 : r6 : restore : xs))
158 Although gmpCompare doesn't allocate space, it does temporarily use
159 some space just beyond the heap pointer. This is safe, because the
160 enclosing routine has already guaranteed that this space will be
161 available. (See ``primOpHeapRequired.'')
165 :: CAddrMode -- result (boolean)
166 -> (CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode)
167 -- alloc hp + 2 arguments (3 parts each)
168 -> UniqSM StixTreeList
170 gmpCompare res args@(chp, caa1,csa1,cda1, caa2,csa2,cda2)
172 result = amodeToStix res
174 aa1 = amodeToStix caa1
175 sa1 = amodeToStix csa1
176 da1 = amodeToStix cda1
177 aa2 = amodeToStix caa2
178 sa2 = amodeToStix csa2
179 da2 = amodeToStix cda2
182 argument2 = StIndex IntRep hp (StInt (toInteger mpIntSize))
183 (a1,a2,a3) = toStruct argument1 (aa1,sa1,da1)
184 (a4,a5,a6) = toStruct argument2 (aa2,sa2,da2)
185 mpz_cmp = StCall SLIT("mpz_cmp") cCallConv IntRep [argument1, argument2]
186 r1 = StAssign IntRep result mpz_cmp
188 returnUs (\xs -> a1 : a2 : a3 : a4 : a5 : a6 : r1 : xs)
191 See the comment above regarding the heap check (or lack thereof).
195 :: CAddrMode -- result
196 -> (CAddrMode, CAddrMode,CAddrMode,CAddrMode) -- alloc hp + argument (3 parts)
197 -> UniqSM StixTreeList
199 gmpInteger2Int res args@(chp, caa,csa,cda)
201 result = amodeToStix res
207 (a1,a2,a3) = toStruct hp (aa,sa,da)
208 mpz_get_si = StCall SLIT("mpz_get_si") cCallConv IntRep [hp]
209 r1 = StAssign IntRep result mpz_get_si
211 returnUs (\xs -> a1 : a2 : a3 : r1 : xs)
214 :: CAddrMode -- result
215 -> (CAddrMode, CAddrMode,CAddrMode,CAddrMode) -- alloc hp + argument (3 parts)
216 -> UniqSM StixTreeList
218 gmpInteger2Word res args@(chp, caa,csa,cda)
220 result = amodeToStix res
226 (a1,a2,a3) = toStruct hp (aa,sa,da)
227 mpz_get_ui = StCall SLIT("mpz_get_ui") cCallConv IntRep [hp]
228 r1 = StAssign WordRep result mpz_get_ui
230 returnUs (\xs -> a1 : a2 : a3 : r1 : xs)
232 arrayOfData_info = sStLitLbl SLIT("ArrayOfData_info")
236 :: (CAddrMode, CAddrMode, CAddrMode) -- result (3 parts)
237 -> (CAddrMode, CAddrMode) -- allocated heap, Int to convert
238 -> UniqSM StixTreeList
240 gmpInt2Integer res@(car,csr,cdr) args@(chp, n)
241 = getUniqLabelNCG `thenUs` \ zlbl ->
242 getUniqLabelNCG `thenUs` \ nlbl ->
243 getUniqLabelNCG `thenUs` \ jlbl ->
251 h1 = StAssign PtrRep (StInd PtrRep hp) arrayOfData_info
252 size = varHdrSizeInWords (DataRep 0) + mIN_MP_INT_SIZE
253 h2 = StAssign IntRep (StInd IntRep (StIndex IntRep hp (StInt 1)))
254 (StInt (toInteger size))
255 cts = StInd IntRep (StIndex IntRep hp dataHS)
256 test1 = StPrim IntEqOp [i, StInt 0]
257 test2 = StPrim IntLtOp [i, StInt 0]
258 cjmp1 = StCondJump zlbl test1
259 cjmp2 = StCondJump nlbl test2
261 p1 = StAssign IntRep cts i
262 p2 = StAssign IntRep sr (StInt 1)
263 p3 = StJump (StCLbl jlbl)
266 n1 = StAssign IntRep cts (StPrim IntNegOp [i])
267 n2 = StAssign IntRep sr (StInt (-1))
268 n3 = StJump (StCLbl jlbl)
271 z1 = StAssign IntRep sr (StInt 0)
274 a1 = StAssign IntRep ar (StInt 1)
275 a2 = StAssign PtrRep dr hp
279 CLit (MachInt c _) ->
280 if c == 0 then h1 : h2 : z1 : a1 : a2 : xs
281 else if c > 0 then h1 : h2 : p1 : p2 : a1 : a2 : xs
282 else h1 : h2 : n1 : n2 : a1 : a2 : xs
283 _ -> h1 : h2 : cjmp1 : cjmp2 : p1 : p2 : p3
284 : n0 : n1 : n2 : n3 : z0 : z1
288 :: (CAddrMode, CAddrMode, CAddrMode) -- result (3 parts)
289 -> (CAddrMode, CAddrMode) -- liveness, string
290 -> UniqSM StixTreeList
292 gmpString2Integer res@(car,csr,cdr) (liveness, str)
293 = getUniqLabelNCG `thenUs` \ ulbl ->
300 (CString s) -> _LENGTH_ s
301 (CLit (MachStr s)) -> _LENGTH_ s
302 _ -> panic "String2Integer"
303 space = len `quot` 8 + 17 + mpIntSize +
304 varHdrSizeInWords (DataRep 0) + fixedHdrSizeInWords
305 oldHp = StIndex PtrRep stgHp (StInt (toInteger (-space)))
307 save = StAssign PtrRep safeHp oldHp
308 result = StIndex IntRep stgHpLim (StInt (toInteger (-mpIntSize)))
309 set_str = StCall SLIT("mpz_init_set_str") cCallConv IntRep
310 [result, amodeToStix str, StInt 10]
311 test = StPrim IntEqOp [set_str, StInt 0]
312 cjmp = StCondJump ulbl test
313 abort = StCall SLIT("abort") cCallConv VoidRep []
315 restore = StAssign PtrRep stgHp safeHp
316 (a1,a2,a3) = fromStruct result (ar,sr,dr)
318 macroCode HEAP_CHK [liveness, mkIntCLit space, mkIntCLit_0]
319 `thenUs` \ heap_chk ->
322 (\xs -> save : cjmp : abort : join : a1 : a2 : a3 : restore : xs))
324 mkIntCLit_0 = mkIntCLit 0 -- out here to avoid CAF (sigh)
328 -> CAddrMode -- result
329 -> (CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode)
330 -- heap pointer for result, integer argument (3 parts), exponent
331 -> UniqSM StixTreeList
333 encodeFloatingKind pk res args@(chp, caa,csa,cda, cexpon)
335 result = amodeToStix res
340 expon = amodeToStix cexpon
342 pk' = if sizeOf FloatRep == sizeOf DoubleRep
345 (a1,a2,a3) = toStruct hp (aa,sa,da)
347 FloatRep -> SLIT("__encodeFloat")
348 DoubleRep -> SLIT("__encodeDouble")
349 _ -> panic "encodeFloatingKind"
350 encode = StCall fn cCallConv pk' [hp, expon]
351 r1 = StAssign pk' result encode
353 returnUs (\xs -> a1 : a2 : a3 : r1 : xs)
357 -> (CAddrMode, CAddrMode, CAddrMode, CAddrMode)
358 -- exponent result, integer result (3 parts)
359 -> (CAddrMode, CAddrMode)
360 -- heap pointer for exponent, floating argument
361 -> UniqSM StixTreeList
363 decodeFloatingKind pk res@(cexponr,car,csr,cdr) args@(chp, carg)
365 exponr = amodeToStix cexponr
370 arg = amodeToStix carg
372 pk' = if sizeOf FloatRep == sizeOf DoubleRep
375 setup = StAssign PtrRep mpData_mantissa (StIndex IntRep hp (StInt 1))
377 FloatRep -> SLIT("__decodeFloat")
378 DoubleRep -> SLIT("__decodeDouble")
379 _ -> panic "decodeFloatingKind"
380 decode = StCall fn cCallConv VoidRep [mantissa, hp, arg]
381 (a1,a2,a3) = fromStruct mantissa (ar,sr,dr)
382 a4 = StAssign IntRep exponr (StInd IntRep hp)
384 returnUs (\xs -> setup : decode : a1 : a2 : a3 : a4 : xs)
386 mantissa = mpStruct 1 -- out here to avoid CAF (sigh)
387 mpData_mantissa = mpData mantissa
390 Support for the Gnu GMP multi-precision package.
393 -- size (in words) of __MP_INT
396 mpAlloc, mpSize, mpData :: StixTree -> StixTree
397 mpAlloc base = StInd IntRep base
398 mpSize base = StInd IntRep (StIndex IntRep base (StInt 1))
399 mpData base = StInd PtrRep (StIndex IntRep base (StInt 2))
402 :: Int -- gmp structures needed
403 -> Int -- number of results
404 -> [StixTree] -- sizes to add for estimating result size
405 -> StixTree -- total space
407 mpSpace gmp res sizes
408 = foldr sum (StPrim IntAddOp [fixed, hdrs]) sizes
410 sum x y = StPrim IntAddOp [StPrim IntAbsOp [x], y]
411 -- what's the magical 17 for?
412 fixed = StInt (toInteger (17 * res + gmp * mpIntSize))
413 hdrs = StPrim IntMulOp [dataHS, StInt (toInteger res)]
416 We don't have a truly portable way of allocating local temporaries, so
417 we cheat and use space at the end of the heap. (Thus, negative
418 offsets from HpLim are our temporaries.) Note that you must have
419 performed a heap check which includes the space needed for these
420 temporaries before you use them.
423 mpStruct :: Int -> StixTree
424 mpStruct n = StIndex IntRep stgHpLim (StInt (toInteger (-(n * mpIntSize))))
428 -> (StixTree, StixTree, StixTree)
429 -> (StixTree, StixTree, StixTree)
431 toStruct str (alloc,size,arr)
433 f1 = StAssign IntRep (mpAlloc str) alloc
434 f2 = StAssign IntRep (mpSize str) size
435 f3 = StAssign PtrRep (mpData str) (StIndex PtrRep arr dataHS)
441 -> (StixTree, StixTree, StixTree)
442 -> (StixTree, StixTree, StixTree)
444 fromStruct str (alloc,size,arr)
446 e1 = StAssign IntRep alloc (mpAlloc str)
447 e2 = StAssign IntRep size (mpSize str)
448 e3 = StAssign PtrRep arr (StIndex PtrRep (mpData str)
449 (StPrim IntNegOp [dataHS]))