| 1 | module CmmLiveZ |
|---|
| 2 | ( CmmLive |
|---|
| 3 | , cmmLivenessZ |
|---|
| 4 | , liveLattice |
|---|
| 5 | , middleLiveness |
|---|
| 6 | ) |
|---|
| 7 | where |
|---|
| 8 | |
|---|
| 9 | import BlockId |
|---|
| 10 | import CmmExpr |
|---|
| 11 | import CmmTx |
|---|
| 12 | import DFLattice |
|---|
| 13 | import PprCmm() |
|---|
| 14 | import PprCmmZ() |
|---|
| 15 | import ZDF5ex -- was ZipDataflow |
|---|
| 16 | import ZipCfgCmmRep |
|---|
| 17 | |
|---|
| 18 | import Maybes |
|---|
| 19 | import Outputable |
|---|
| 20 | import UniqSet |
|---|
| 21 | |
|---|
| 22 | ----------------------------------------------------------------------------- |
|---|
| 23 | -- Calculating what variables are live on entry to a basic block |
|---|
| 24 | ----------------------------------------------------------------------------- |
|---|
| 25 | |
|---|
| 26 | -- | The variables live on entry to a block |
|---|
| 27 | type CmmLive = RegSet |
|---|
| 28 | |
|---|
| 29 | -- | The dataflow lattice |
|---|
| 30 | liveLattice :: DataflowLattice CmmLive |
|---|
| 31 | liveLattice = DataflowLattice "live LocalReg's" emptyUniqSet add False |
|---|
| 32 | where add new old = |
|---|
| 33 | let join = unionUniqSets new old in |
|---|
| 34 | (if sizeUniqSet join > sizeUniqSet old then aTx else noTx) join |
|---|
| 35 | |
|---|
| 36 | -- | A mapping from block labels to the variables live on entry |
|---|
| 37 | type BlockEntryLiveness = BlockEnv CmmLive |
|---|
| 38 | |
|---|
| 39 | ----------------------------------------------------------------------------- |
|---|
| 40 | -- | Calculated liveness info for a CmmGraph |
|---|
| 41 | ----------------------------------------------------------------------------- |
|---|
| 42 | cmmLivenessZ :: CmmGraph -> BlockEntryLiveness |
|---|
| 43 | cmmLivenessZ g = zdfFpFacts $ check res |
|---|
| 44 | where res :: CmmBackwardFixedPoint CmmLive |
|---|
| 45 | res = zdfSolveFromBwd emptyBlockEnv "liveness analysis" |
|---|
| 46 | liveLattice transfers g |
|---|
| 47 | transfers = BackwardTransfers (flip const) mid last |
|---|
| 48 | mid m = gen_kill m . midLive m |
|---|
| 49 | last l = gen_kill l . lastLive l |
|---|
| 50 | check :: CmmBackwardFixedPoint CmmLive -> CmmBackwardFixedPoint CmmLive |
|---|
| 51 | check bfp = noLive (bfp_out_fact bfp) bfp |
|---|
| 52 | |
|---|
| 53 | gen_kill :: (DefinerOfLocalRegs a, UserOfLocalRegs a) => a -> CmmLive -> CmmLive |
|---|
| 54 | gen_kill a = gen a . kill a |
|---|
| 55 | |
|---|
| 56 | middleLiveness :: Middle -> CmmLive -> CmmLive |
|---|
| 57 | middleLiveness = gen_kill |
|---|
| 58 | |
|---|
| 59 | -- | On entry to the procedure, there had better not be any LocalReg's live-in. |
|---|
| 60 | noLive :: CmmLive -> a -> a |
|---|
| 61 | noLive in_fact x = |
|---|
| 62 | if isEmptyUniqSet in_fact then x |
|---|
| 63 | else pprPanic "LocalReg's live-in to graph" (ppr in_fact) |
|---|
| 64 | |
|---|
| 65 | -- | The transfer equations use the traditional 'gen' and 'kill' |
|---|
| 66 | -- notations, which should be familiar from the dragon book. |
|---|
| 67 | gen :: UserOfLocalRegs a => a -> RegSet -> RegSet |
|---|
| 68 | gen a live = foldRegsUsed extendRegSet live a |
|---|
| 69 | kill :: DefinerOfLocalRegs a => a -> RegSet -> RegSet |
|---|
| 70 | kill a live = foldRegsDefd delOneFromUniqSet live a |
|---|
| 71 | |
|---|
| 72 | midLive :: Middle -> CmmLive -> CmmLive |
|---|
| 73 | midLive (MidForeignCall {}) _ = emptyUniqSet |
|---|
| 74 | midLive _ live = live |
|---|
| 75 | |
|---|
| 76 | lastLive :: Last -> (BlockId -> CmmLive) -> CmmLive |
|---|
| 77 | lastLive l env = last l |
|---|
| 78 | where last (LastBranch id) = env id |
|---|
| 79 | last (LastCall _ _ _ _ _) = emptyUniqSet |
|---|
| 80 | last (LastCondBranch _ t f) = unionUniqSets (env t) (env f) |
|---|
| 81 | last (LastSwitch _ tbl) = unionManyUniqSets $ map env (catMaybes tbl) |
|---|
| 82 | |
|---|
| 83 | can't_match :: a |
|---|
| 84 | can't_match = panic "the GADT pattern matcher is too stupid to live" |
|---|