2 % (c) The GRASP/AQUA Project, Glasgow University, 1993-1996
4 \section[AbsCUtils]{Help functions for Abstract~C datatype}
7 #include "HsVersions.h"
11 mkAbstractCs, mkAbsCStmts,
14 getAmodeRep, amodeCanSurviveGC,
15 mixedTypeLocn, mixedPtrLocn,
19 -- printing/forcing stuff comes from PprAbsC
23 import {-# SOURCE #-} CLabel ( mkReturnPtLabel, CLabel )
24 -- The loop here is (CLabel -> CgRetConv -> AbsCUtils -> CLabel)
28 import Digraph ( stronglyConnComp, SCC(..) )
29 import HeapOffs ( possiblyEqualHeapOffset )
30 import Id ( fIRST_TAG, SYN_IE(ConTag) )
31 import Literal ( literalPrimRep, Literal(..) )
32 import PrimRep ( getPrimRepSize, PrimRep(..) )
33 import Unique ( Unique{-instance Eq-} )
34 import UniqSupply ( getUnique, getUniques, splitUniqSupply, UniqSupply )
35 import Util ( assocDefaultUsing, panic, Ord3(..) )
40 Check if there is any real code in some Abstract~C. If so, return it
41 (@Just ...@); otherwise, return @Nothing@. Don't be too strict!
43 It returns the "reduced" code in the Just part so that the work of
44 discarding AbsCNops isn't lost, and so that if the caller uses
45 the reduced version there's less danger of a big tree of AbsCNops getting
46 materialised and causing a space leak.
49 nonemptyAbsC :: AbstractC -> Maybe AbstractC
50 nonemptyAbsC AbsCNop = Nothing
51 nonemptyAbsC (AbsCStmts s1 s2) = case (nonemptyAbsC s1) of
52 Nothing -> nonemptyAbsC s2
53 Just x -> Just (AbsCStmts x s2)
54 nonemptyAbsC s@(CSimultaneous c) = case (nonemptyAbsC c) of
57 nonemptyAbsC other = Just other
61 mkAbstractCs :: [AbstractC] -> AbstractC
62 mkAbstractCs [] = AbsCNop
63 mkAbstractCs cs = foldr1 mkAbsCStmts cs
65 -- for fiddling around w/ killing off AbsCNops ... (ToDo)
66 mkAbsCStmts :: AbstractC -> AbstractC -> AbstractC
67 mkAbsCStmts = AbsCStmts
69 {- Discarded SLPJ June 95; it calls nonemptyAbsC too much!
70 = case (case (nonemptyAbsC abc2) of
72 Just d2 -> d2) of { abc2b ->
74 case (nonemptyAbsC abc1) of {
76 Just d1 -> AbsCStmts d1 abc2b
81 Get the sho' 'nuff statements out of an @AbstractC@.
83 mkAbsCStmtList :: AbstractC -> [AbstractC]
85 mkAbsCStmtList absC = mkAbsCStmtList' absC []
87 -- Optimised a la foldr/build!
89 mkAbsCStmtList' AbsCNop r = r
91 mkAbsCStmtList' (AbsCStmts s1 s2) r
92 = mkAbsCStmtList' s1 (mkAbsCStmtList' s2 r)
94 mkAbsCStmtList' s@(CSimultaneous c) r
95 = if null (mkAbsCStmtList c) then r else s : r
97 mkAbsCStmtList' other r = other : r
101 mkAlgAltsCSwitch :: CAddrMode -> [(ConTag, AbstractC)] -> AbstractC -> AbstractC
103 mkAlgAltsCSwitch scrutinee tagged_alts deflt_absc
104 = CSwitch scrutinee (adjust tagged_alts) deflt_absc
106 -- Adjust the tags in the switch to start at zero.
107 -- This is the convention used by primitive ops which return algebraic
108 -- data types. Why? Because for two-constructor types, zero is faster
109 -- to create and distinguish from 1 than are 1 and 2.
111 -- We also need to convert to Literals to keep the CSwitch happy
113 = [ (MachInt (toInteger (tag - fIRST_TAG)) False{-unsigned-}, abs_c)
114 | (tag, abs_c) <- tagged_alts ]
117 %************************************************************************
119 \subsubsection[AbsCUtils-kinds-from-MagicIds]{Kinds from MagicIds}
121 %************************************************************************
124 magicIdPrimRep BaseReg = PtrRep
125 magicIdPrimRep StkOReg = PtrRep
126 magicIdPrimRep (VanillaReg kind _) = kind
127 magicIdPrimRep (FloatReg _) = FloatRep
128 magicIdPrimRep (DoubleReg _) = DoubleRep
129 magicIdPrimRep TagReg = IntRep
130 magicIdPrimRep RetReg = RetRep
131 magicIdPrimRep SpA = PtrRep
132 magicIdPrimRep SuA = PtrRep
133 magicIdPrimRep SpB = PtrRep
134 magicIdPrimRep SuB = PtrRep
135 magicIdPrimRep Hp = PtrRep
136 magicIdPrimRep HpLim = PtrRep
137 magicIdPrimRep LivenessReg = IntRep
138 magicIdPrimRep StdUpdRetVecReg = PtrRep
139 magicIdPrimRep StkStubReg = PtrRep
140 magicIdPrimRep CurCostCentre = CostCentreRep
141 magicIdPrimRep VoidReg = VoidRep
144 %************************************************************************
146 \subsection[AbsCUtils-amode-kinds]{Finding @PrimitiveKinds@ of amodes}
148 %************************************************************************
150 See also the return conventions for unboxed things; currently living
151 in @CgCon@ (next to the constructor return conventions).
153 ToDo: tiny tweaking may be in order
155 getAmodeRep :: CAddrMode -> PrimRep
157 getAmodeRep (CVal _ kind) = kind
158 getAmodeRep (CAddr _) = PtrRep
159 getAmodeRep (CReg magic_id) = magicIdPrimRep magic_id
160 getAmodeRep (CTemp uniq kind) = kind
161 getAmodeRep (CLbl label kind) = kind
162 getAmodeRep (CUnVecLbl _ _) = PtrRep
163 getAmodeRep (CCharLike _) = PtrRep
164 getAmodeRep (CIntLike _) = PtrRep
165 getAmodeRep (CString _) = PtrRep
166 getAmodeRep (CLit lit) = literalPrimRep lit
167 getAmodeRep (CLitLit _ kind) = kind
168 getAmodeRep (COffset _) = IntRep
169 getAmodeRep (CCode abs_C) = CodePtrRep
170 getAmodeRep (CLabelledCode label abs_C) = CodePtrRep
171 getAmodeRep (CTableEntry _ _ kind) = kind
172 getAmodeRep (CMacroExpr kind _ _) = kind
174 getAmodeRep (CJoinPoint _ _) = panic "getAmodeRep:CJoinPoint"
175 getAmodeRep (CCostCentre _ _) = panic "getAmodeRep:CCostCentre"
179 @amodeCanSurviveGC@ tells, well, whether or not the amode is invariant
180 across a garbage collection. Used only for PrimOp arguments (not that
184 amodeCanSurviveGC :: CAddrMode -> Bool
186 amodeCanSurviveGC (CTableEntry base offset _)
187 = amodeCanSurviveGC base && amodeCanSurviveGC offset
188 -- "Fixed table, so it's OK" (JSM); code is slightly paranoid
190 amodeCanSurviveGC (CLbl _ _) = True
191 amodeCanSurviveGC (CUnVecLbl _ _) = True
192 amodeCanSurviveGC (CCharLike arg) = amodeCanSurviveGC arg
193 amodeCanSurviveGC (CIntLike arg) = amodeCanSurviveGC arg
194 amodeCanSurviveGC (CString _) = True
195 amodeCanSurviveGC (CLit _) = True
196 amodeCanSurviveGC (CLitLit _ _) = True
197 amodeCanSurviveGC (COffset _) = True
198 amodeCanSurviveGC (CMacroExpr _ _ args) = all amodeCanSurviveGC args
200 amodeCanSurviveGC _ = False
201 -- there are some amodes that "cannot occur" as args
202 -- to a PrimOp, but it is safe to return False (rather than panic)
205 @mixedTypeLocn@ tells whether an amode identifies an ``StgWord''
206 location; that is, one which can contain values of various types.
209 mixedTypeLocn :: CAddrMode -> Bool
211 mixedTypeLocn (CVal (NodeRel _) _) = True
212 mixedTypeLocn (CVal (SpBRel _ _) _) = True
213 mixedTypeLocn (CVal (HpRel _ _) _) = True
214 mixedTypeLocn other = False -- All the rest
217 @mixedPtrLocn@ tells whether an amode identifies a
218 location which can contain values of various pointer types.
221 mixedPtrLocn :: CAddrMode -> Bool
223 mixedPtrLocn (CVal (SpARel _ _) _) = True
224 mixedPtrLocn other = False -- All the rest
227 %************************************************************************
229 \subsection[AbsCUtils-flattening]{Flatten Abstract~C}
231 %************************************************************************
233 The following bits take ``raw'' Abstract~C, which may have all sorts of
234 nesting, and flattens it into one long @AbsCStmtList@. Mainly,
235 @CClosureInfos@ and code for switches are pulled out to the top level.
237 The various functions herein tend to produce
240 A {\em flattened} \tr{<something>} of interest for ``here'', and
242 Some {\em unflattened} Abstract~C statements to be carried up to the
243 top-level. The only real reason (now) that it is unflattened is
244 because it means the recursive flattening can be done in just one
245 place rather than having to remember lots of places.
248 Care is taken to reduce the occurrence of forward references, while still
249 keeping laziness a much as possible. Essentially, this means that:
252 {\em All} the top-level C statements resulting from flattening a
253 particular AbsC statement (whether the latter is nested or not) appear
254 before {\em any} of the code for a subsequent AbsC statement;
256 but stuff nested within any AbsC statement comes
257 out before the code for the statement itself.
260 The ``stuff to be carried up'' always includes a label: a
261 @CStaticClosure@, @CClosureUpdInfo@, @CRetUnVector@, @CFlatRetVector@, or
262 @CCodeBlock@. The latter turns into a C function, and is never
263 actually produced by the code generator. Rather it always starts life
264 as a @CLabelledCode@ addressing mode; when such an addr mode is
265 flattened, the ``tops'' stuff is a @CCodeBlock@.
268 flattenAbsC :: UniqSupply -> AbstractC -> AbstractC
271 = case (initFlt us (flatAbsC abs_C)) of { (here, tops) ->
272 here `mkAbsCStmts` tops }
275 %************************************************************************
277 \subsubsection{Flattening monadery}
279 %************************************************************************
281 The flattener is monadised. It's just a @UniqueSupply@, along with a
282 ``come-back-to-here'' label to pin on heap and stack checks.
290 initFlt :: UniqSupply -> FlatM a -> a
292 initFlt init_us m = m (panic "initFlt:CLabel") init_us
294 {-# INLINE thenFlt #-}
295 {-# INLINE returnFlt #-}
297 thenFlt :: FlatM a -> (a -> FlatM b) -> FlatM b
299 thenFlt expr cont label us
300 = case (splitUniqSupply us) of { (s1, s2) ->
301 case (expr label s1) of { result ->
302 cont result label s2 }}
304 returnFlt :: a -> FlatM a
305 returnFlt result label us = result
307 mapFlt :: (a -> FlatM b) -> [a] -> FlatM [b]
309 mapFlt f [] = returnFlt []
311 = f x `thenFlt` \ r ->
312 mapFlt f xs `thenFlt` \ rs ->
315 mapAndUnzipFlt :: (a -> FlatM (b,c)) -> [a] -> FlatM ([b],[c])
317 mapAndUnzipFlt f [] = returnFlt ([],[])
318 mapAndUnzipFlt f (x:xs)
319 = f x `thenFlt` \ (r1, r2) ->
320 mapAndUnzipFlt f xs `thenFlt` \ (rs1, rs2) ->
321 returnFlt (r1:rs1, r2:rs2)
323 getUniqFlt :: FlatM Unique
324 getUniqFlt label us = getUnique us
326 getUniqsFlt :: Int -> FlatM [Unique]
327 getUniqsFlt i label us = getUniques i us
329 setLabelFlt :: CLabel -> FlatM a -> FlatM a
330 setLabelFlt new_label cont label us = cont new_label us
332 getLabelFlt :: FlatM CLabel
333 getLabelFlt label us = label
336 %************************************************************************
338 \subsubsection{Flattening the top level}
340 %************************************************************************
343 flatAbsC :: AbstractC
344 -> FlatM (AbstractC, -- Stuff to put inline [Both are fully
345 AbstractC) -- Stuff to put at top level flattened]
347 flatAbsC AbsCNop = returnFlt (AbsCNop, AbsCNop)
349 flatAbsC (AbsCStmts s1 s2)
350 = flatAbsC s1 `thenFlt` \ (inline_s1, top_s1) ->
351 flatAbsC s2 `thenFlt` \ (inline_s2, top_s2) ->
352 returnFlt (mkAbsCStmts inline_s1 inline_s2,
353 mkAbsCStmts top_s1 top_s2)
355 flatAbsC (CClosureInfoAndCode cl_info slow maybe_fast upd descr liveness)
356 = flatAbsC slow `thenFlt` \ (slow_heres, slow_tops) ->
357 flat_maybe maybe_fast `thenFlt` \ (fast_heres, fast_tops) ->
358 flatAmode upd `thenFlt` \ (upd_lbl, upd_tops) ->
359 returnFlt (AbsCNop, mkAbstractCs [slow_tops, fast_tops, upd_tops,
360 CClosureInfoAndCode cl_info slow_heres fast_heres upd_lbl descr liveness]
363 flat_maybe :: Maybe AbstractC -> FlatM (Maybe AbstractC, AbstractC)
364 flat_maybe Nothing = returnFlt (Nothing, AbsCNop)
365 flat_maybe (Just abs_c) = flatAbsC abs_c `thenFlt` \ (heres, tops) ->
366 returnFlt (Just heres, tops)
368 flatAbsC (CCodeBlock label abs_C)
369 = flatAbsC abs_C `thenFlt` \ (absC_heres, absC_tops) ->
370 returnFlt (AbsCNop, absC_tops `mkAbsCStmts` CCodeBlock label absC_heres)
372 flatAbsC (CClosureUpdInfo info) = flatAbsC info
374 flatAbsC (CStaticClosure closure_lbl closure_info cost_centre amodes)
375 = flatAmodes (cost_centre:amodes) `thenFlt` \ (new_cc:new_amodes, tops) ->
376 returnFlt (AbsCNop, tops `mkAbsCStmts`
377 CStaticClosure closure_lbl closure_info new_cc new_amodes)
379 flatAbsC (CRetVector tbl_label stuff deflt)
380 = do_deflt deflt `thenFlt` \ (deflt_amode, deflt_tops) ->
381 mapAndUnzipFlt (do_alt deflt_amode) stuff `thenFlt` \ (alt_amodes, alt_tops) ->
382 returnFlt (AbsCNop, mkAbstractCs [deflt_tops,
383 mkAbstractCs alt_tops,
384 CFlatRetVector tbl_label alt_amodes])
387 do_deflt deflt = case nonemptyAbsC deflt of
388 Nothing -> returnFlt (bogus_default_label, AbsCNop)
389 Just deflt' -> flatAmode (CCode deflt) -- Deals correctly with the
390 -- CJump (CLabelledCode ...) case
392 do_alt deflt_amode Nothing = returnFlt (deflt_amode, AbsCNop)
393 do_alt deflt_amode (Just alt) = flatAmode alt
395 bogus_default_label = panic "flatAbsC: CRetVector: default needed and not available"
398 flatAbsC (CRetUnVector label amode)
399 = flatAmode amode `thenFlt` \ (new_amode, tops) ->
400 returnFlt (AbsCNop, tops `mkAbsCStmts` CRetUnVector label new_amode)
402 flatAbsC (CFlatRetVector label amodes)
403 = flatAmodes amodes `thenFlt` \ (new_amodes, tops) ->
404 returnFlt (AbsCNop, tops `mkAbsCStmts` CFlatRetVector label new_amodes)
406 flatAbsC cc@(CCostCentreDecl _ _) -- at top, already flat
407 = returnFlt (AbsCNop, cc)
409 -- now the real stmts:
411 flatAbsC (CAssign dest source)
412 = flatAmode dest `thenFlt` \ (dest_amode, dest_tops) ->
413 flatAmode source `thenFlt` \ (src_amode, src_tops) ->
414 returnFlt ( CAssign dest_amode src_amode, mkAbsCStmts dest_tops src_tops )
416 -- special case: jump to some anonymous code
417 flatAbsC (CJump (CCode abs_C)) = flatAbsC abs_C
419 flatAbsC (CJump target)
420 = flatAmode target `thenFlt` \ (targ_amode, targ_tops) ->
421 returnFlt ( CJump targ_amode, targ_tops )
423 flatAbsC (CFallThrough target)
424 = flatAmode target `thenFlt` \ (targ_amode, targ_tops) ->
425 returnFlt ( CFallThrough targ_amode, targ_tops )
427 flatAbsC (CReturn target return_info)
428 = flatAmode target `thenFlt` \ (targ_amode, targ_tops) ->
429 returnFlt ( CReturn targ_amode return_info, targ_tops )
431 flatAbsC (CSwitch discrim alts deflt)
432 = flatAmode discrim `thenFlt` \ (discrim_amode, discrim_tops) ->
433 mapAndUnzipFlt flat_alt alts `thenFlt` \ (flat_alts, flat_alts_tops) ->
434 flatAbsC deflt `thenFlt` \ (flat_def_alt, def_tops) ->
436 CSwitch discrim_amode flat_alts flat_def_alt,
437 mkAbstractCs (discrim_tops : def_tops : flat_alts_tops)
441 = flatAbsC absC `thenFlt` \ (alt_heres, alt_tops) ->
442 returnFlt ( (tag, alt_heres), alt_tops )
444 flatAbsC stmt@(CInitHdr a b cc u)
445 = flatAmode cc `thenFlt` \ (new_cc, tops) ->
446 returnFlt (CInitHdr a b new_cc u, tops)
448 flatAbsC stmt@(COpStmt results op args liveness_mask vol_regs)
449 = flatAmodes results `thenFlt` \ (results_here, tops1) ->
450 flatAmodes args `thenFlt` \ (args_here, tops2) ->
451 returnFlt (COpStmt results_here op args_here liveness_mask vol_regs,
452 mkAbsCStmts tops1 tops2)
454 flatAbsC stmt@(CSimultaneous abs_c)
455 = flatAbsC abs_c `thenFlt` \ (stmts_here, tops) ->
456 doSimultaneously stmts_here `thenFlt` \ new_stmts_here ->
457 returnFlt (new_stmts_here, tops)
459 flatAbsC stmt@(CMacroStmt macro amodes)
460 = flatAmodes amodes `thenFlt` \ (amodes_here, tops) ->
461 returnFlt (CMacroStmt macro amodes_here, tops)
463 flatAbsC stmt@(CCallProfCtrMacro str amodes)
464 = flatAmodes amodes `thenFlt` \ (amodes_here, tops) ->
465 returnFlt (CCallProfCtrMacro str amodes_here, tops)
467 flatAbsC stmt@(CCallProfCCMacro str amodes)
468 = flatAmodes amodes `thenFlt` \ (amodes_here, tops) ->
469 returnFlt (CCallProfCCMacro str amodes_here, tops)
471 flatAbsC stmt@(CSplitMarker) = returnFlt (AbsCNop, stmt)
474 %************************************************************************
476 \subsection[flat-amodes]{Flattening addressing modes}
478 %************************************************************************
481 flatAmode :: CAddrMode -> FlatM (CAddrMode, AbstractC)
484 flatAmode amode@(CVal _ _) = returnFlt (amode, AbsCNop)
486 flatAmode amode@(CAddr _) = returnFlt (amode, AbsCNop)
487 flatAmode amode@(CReg _) = returnFlt (amode, AbsCNop)
488 flatAmode amode@(CTemp _ _) = returnFlt (amode, AbsCNop)
489 flatAmode amode@(CLbl _ _) = returnFlt (amode, AbsCNop)
490 flatAmode amode@(CUnVecLbl _ _) = returnFlt (amode, AbsCNop)
491 flatAmode amode@(CString _) = returnFlt (amode, AbsCNop)
492 flatAmode amode@(CLit _) = returnFlt (amode, AbsCNop)
493 flatAmode amode@(CLitLit _ _) = returnFlt (amode, AbsCNop)
494 flatAmode amode@(COffset _) = returnFlt (amode, AbsCNop)
496 -- CIntLike must be a literal -- no flattening
497 flatAmode amode@(CIntLike int) = returnFlt(amode, AbsCNop)
499 -- CCharLike may be arbitrary value -- have to flatten
500 flatAmode amode@(CCharLike char)
501 = flatAmode char `thenFlt` \ (flat_char, tops) ->
502 returnFlt(CCharLike flat_char, tops)
504 flatAmode (CJoinPoint _ _) = panic "flatAmode:CJoinPoint"
506 flatAmode (CLabelledCode label abs_C)
507 -- Push the code (with this label) to the top level
508 = flatAbsC abs_C `thenFlt` \ (body_code, tops) ->
509 returnFlt (CLbl label CodePtrRep,
510 tops `mkAbsCStmts` CCodeBlock label body_code)
512 flatAmode (CCode abs_C)
513 = case mkAbsCStmtList abs_C of
514 [CJump amode] -> flatAmode amode -- Elide redundant labels
516 -- de-anonymous-ise the code and push it (labelled) to the top level
517 getUniqFlt `thenFlt` \ new_uniq ->
518 case (mkReturnPtLabel new_uniq) of { return_pt_label ->
519 flatAbsC abs_C `thenFlt` \ (body_code, tops) ->
521 CLbl return_pt_label CodePtrRep,
522 tops `mkAbsCStmts` CCodeBlock return_pt_label body_code
523 -- DO NOT TOUCH the stuff sent to the top...
526 flatAmode (CTableEntry base index kind)
527 = flatAmode base `thenFlt` \ (base_amode, base_tops) ->
528 flatAmode index `thenFlt` \ (ix_amode, ix_tops) ->
529 returnFlt ( CTableEntry base_amode ix_amode kind, mkAbsCStmts base_tops ix_tops )
531 flatAmode (CMacroExpr pk macro amodes)
532 = flatAmodes amodes `thenFlt` \ (amodes_here, tops) ->
533 returnFlt ( CMacroExpr pk macro amodes_here, tops )
535 flatAmode amode@(CCostCentre _ _) = returnFlt (amode, AbsCNop)
538 And a convenient way to do a whole bunch of 'em.
540 flatAmodes :: [CAddrMode] -> FlatM ([CAddrMode], AbstractC)
542 flatAmodes [] = returnFlt ([], AbsCNop)
545 = mapAndUnzipFlt flatAmode amodes `thenFlt` \ (amodes_here, tops) ->
546 returnFlt (amodes_here, mkAbstractCs tops)
549 %************************************************************************
551 \subsection[flat-simultaneous]{Doing things simultaneously}
553 %************************************************************************
556 doSimultaneously :: AbstractC -> FlatM AbstractC
559 Generate code to perform the @CAssign@s and @COpStmt@s in the
560 input simultaneously, using temporary variables when necessary.
562 We use the strongly-connected component algorithm, in which
563 * the vertices are the statements
564 * an edge goes from s1 to s2 iff
565 s1 assigns to something s2 uses
566 that is, if s1 should *follow* s2 in the final order
570 Wow - fancy stuff. But are we ever going to do anything other than
571 assignments in parallel? If not, wouldn't it be simpler to generate
574 x1, x2, x3 = e1, e2, e3
587 and leave it to the C compiler to figure out whether it needs al
590 (Likewise, why not let the C compiler delete silly code like
599 type CVertex = (Int, AbstractC) -- Give each vertex a unique number,
600 -- for fast comparison
602 type CEdge = (CVertex, CVertex)
604 doSimultaneously abs_c
606 enlisted = en_list abs_c
608 case enlisted of -- it's often just one stmt
609 [] -> returnFlt AbsCNop
611 _ -> doSimultaneously1 (zip [(1::Int)..] enlisted)
613 -- en_list puts all the assignments in a list, filtering out Nops and
614 -- assignments which do nothing
616 en_list (AbsCStmts a1 a2) = en_list a1 ++ en_list a2
617 en_list (CAssign am1 am2) | sameAmode am1 am2 = []
618 en_list other = [other]
620 sameAmode :: CAddrMode -> CAddrMode -> Bool
621 -- ToDo: Move this function, or make CAddrMode an instance of Eq
622 -- At the moment we put in just enough to catch the cases we want:
623 -- the second (destination) argument is always a CVal.
624 sameAmode (CReg r1) (CReg r2) = r1 == r2
625 sameAmode (CVal (SpARel r1 v1) _) (CVal (SpARel r2 v2) _) = r1 == r2 && v1 == v2
626 sameAmode (CVal (SpBRel r1 v1) _) (CVal (SpBRel r2 v2) _) = r1 == r2 && v1 == v2
627 sameAmode other1 other2 = False
629 doSimultaneously1 :: [CVertex] -> FlatM AbstractC
630 doSimultaneously1 vertices
632 edges = [ (vertex, key1, edges_from stmt1)
633 | vertex@(key1, stmt1) <- vertices
635 edges_from stmt1 = [ key2 | (key2, stmt2) <- vertices,
636 stmt1 `should_follow` stmt2
638 components = stronglyConnComp edges
640 -- do_components deal with one strongly-connected component
641 -- Not cyclic, or singleton? Just do it
642 do_component (AcyclicSCC (n,abs_c)) = returnFlt abs_c
643 do_component (CyclicSCC [(n,abs_c)]) = returnFlt abs_c
645 -- Cyclic? Then go via temporaries. Pick one to
646 -- break the loop and try again with the rest.
647 do_component (CyclicSCC ((n,first_stmt) : rest))
648 = doSimultaneously1 rest `thenFlt` \ abs_cs ->
649 go_via_temps first_stmt `thenFlt` \ (to_temps, from_temps) ->
650 returnFlt (mkAbstractCs [to_temps, abs_cs, from_temps])
652 go_via_temps (CAssign dest src)
653 = getUniqFlt `thenFlt` \ uniq ->
655 the_temp = CTemp uniq (getAmodeRep dest)
657 returnFlt (CAssign the_temp src, CAssign dest the_temp)
659 go_via_temps (COpStmt dests op srcs liveness_mask vol_regs)
660 = getUniqsFlt (length dests) `thenFlt` \ uniqs ->
662 the_temps = zipWith (\ u d -> CTemp u (getAmodeRep d)) uniqs dests
664 returnFlt (COpStmt the_temps op srcs liveness_mask vol_regs,
665 mkAbstractCs (zipWith CAssign dests the_temps))
667 mapFlt do_component components `thenFlt` \ abs_cs ->
668 returnFlt (mkAbstractCs abs_cs)
671 should_follow :: AbstractC -> AbstractC -> Bool
672 (CAssign dest1 _) `should_follow` (CAssign _ src2)
673 = dest1 `conflictsWith` src2
674 (COpStmt dests1 _ _ _ _) `should_follow` (CAssign _ src2)
675 = or [dest1 `conflictsWith` src2 | dest1 <- dests1]
676 (CAssign dest1 _)`should_follow` (COpStmt _ _ srcs2 _ _)
677 = or [dest1 `conflictsWith` src2 | src2 <- srcs2]
678 (COpStmt dests1 _ _ _ _) `should_follow` (COpStmt _ _ srcs2 _ _)
679 = or [dest1 `conflictsWith` src2 | dest1 <- dests1, src2 <- srcs2]
681 -- (COpStmt _ _ _ _ _) `should_follow` (CCallProfCtrMacro _ _) = False
682 -- (CCallProfCtrMacro _ _) `should_follow` (COpStmt _ _ _ _ _) = False
688 @conflictsWith@ tells whether an assignment to its first argument will
689 screw up an access to its second.
692 conflictsWith :: CAddrMode -> CAddrMode -> Bool
693 (CReg reg1) `conflictsWith` (CReg reg2) = reg1 == reg2
694 (CReg reg) `conflictsWith` (CVal reg_rel _) = reg `regConflictsWithRR` reg_rel
695 (CReg reg) `conflictsWith` (CAddr reg_rel) = reg `regConflictsWithRR` reg_rel
696 (CTemp u1 _) `conflictsWith` (CTemp u2 _) = u1 == u2
697 (CVal reg_rel1 k1) `conflictsWith` (CVal reg_rel2 k2)
698 = rrConflictsWithRR (getPrimRepSize k1) (getPrimRepSize k2) reg_rel1 reg_rel2
700 other1 `conflictsWith` other2 = False
701 -- CAddr and literals are impossible on the LHS of an assignment
703 regConflictsWithRR :: MagicId -> RegRelative -> Bool
705 regConflictsWithRR (VanillaReg k ILIT(1)) (NodeRel _) = True
707 regConflictsWithRR SpA (SpARel _ _) = True
708 regConflictsWithRR SpB (SpBRel _ _) = True
709 regConflictsWithRR Hp (HpRel _ _) = True
710 regConflictsWithRR _ _ = False
712 rrConflictsWithRR :: Int -> Int -- Sizes of two things
713 -> RegRelative -> RegRelative -- The two amodes
716 rrConflictsWithRR s1 s2 rr1 rr2 = rr rr1 rr2
718 rr (SpARel p1 o1) (SpARel p2 o2)
719 | s1 == 0 || s2 == 0 = False -- No conflict if either is size zero
720 | s1 == 1 && s2 == 1 = b1 == b2
721 | otherwise = (b1+s1) >= b2 &&
727 rr (SpBRel p1 o1) (SpBRel p2 o2)
728 | s1 == 0 || s2 == 0 = False -- No conflict if either is size zero
729 | s1 == 1 && s2 == 1 = b1 == b2
730 | otherwise = (b1+s1) >= b2 &&
736 rr (NodeRel o1) (NodeRel o2)
737 | s1 == 0 || s2 == 0 = False -- No conflict if either is size zero
738 | s1 == 1 && s2 == 1 = o1 `possiblyEqualHeapOffset` o2
739 | otherwise = True -- Give up
741 rr (HpRel _ _) (HpRel _ _) = True -- Give up
743 rr other1 other2 = False