-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathCfg.hs
More file actions
164 lines (128 loc) · 6.12 KB
/
Cfg.hs
File metadata and controls
164 lines (128 loc) · 6.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
module Cfg (cfgFromProgram, Cfg(..), CfgNode(..)) where
import Ast
import Control.Monad.State
import Data.IntMap (IntMap)
import qualified Data.IntMap as UidMap
import Data.IntSet (IntSet)
import qualified Data.IntSet as UidSet
type Uid = Int
type UidSet = IntSet
type UidMap = IntMap
data Cfg = Cfg { cEntry :: CfgNode, cExit :: CfgNode }
data CfgNode = CAss { cStm :: Stm,
cPred :: [CfgNode], cSucc :: [CfgNode], cUid :: Uid }
| COutput { cExpr :: Expr,
cPred :: [CfgNode], cSucc :: [CfgNode], cUid :: Uid }
| CBranch { cExpr :: Expr, cTrue :: CfgNode, cFalse :: CfgNode, cStm :: Stm,
cPred :: [CfgNode], cSucc :: [CfgNode], cUid :: Uid }
| CDecl { cIds :: [Id],
cPred :: [CfgNode], cSucc :: [CfgNode], cUid :: Uid }
| CReturn { cExpr :: Expr,
cPred :: [CfgNode], cSucc :: [CfgNode], cUid :: Uid }
| CNop { cPred :: [CfgNode], cSucc :: [CfgNode], cUid :: Uid }
data CfgGenNode = GNAss { gnStm :: Stm,
gnPred :: UidSet, gnSucc :: UidSet }
| GNOutput { gnExpr :: Expr,
gnPred :: UidSet, gnSucc :: UidSet }
| GNBranch { gnExpr :: Expr, gnStm :: Stm, gnTrue :: Uid, gnFalse :: Uid,
gnPred :: UidSet, gnSucc :: UidSet }
| GNDecl { gnIds :: [Id],
gnPred :: UidSet, gnSucc :: UidSet }
| GNReturn { gnExpr :: Expr,
gnPred :: UidSet, gnSucc :: UidSet }
| GNNop { gnPred :: UidSet, gnSucc :: UidSet }
type UidState = State Uid
type CfgGen = StateT (UidMap CfgGenNode) UidState
-- Utility functions for handling state
nuid :: CfgGen Uid
nuid = lift $ modify (+1) >> get
modifyNodes :: (UidMap CfgGenNode -> UidMap CfgGenNode) -> CfgGen ()
modifyNodes f = modify f
modifyNode :: (CfgGenNode -> CfgGenNode) -> Uid -> CfgGen ()
modifyNode f = modifyNodes . UidMap.adjust f
setNode :: Uid -> CfgGenNode -> CfgGen ()
setNode uid = modifyNodes . UidMap.insert uid
-- Precondition: uid in map
getNode :: Uid -> CfgGen CfgGenNode
getNode uid = (UidMap.! uid) `liftM` get
-- Precondition: uid in map
getsNode :: (CfgGenNode -> a) -> Uid -> CfgGen a
getsNode f uid = f `liftM` getNode uid
-- Precondition: uid in map
getPreds :: Uid -> CfgGen [Uid]
getPreds = getsNode $ UidSet.toList . gnPred
-- Precondition: uid in map
getSuccs :: Uid -> CfgGen [Uid]
getSuccs = getsNode $ UidSet.toList . gnSucc
addPred :: Uid -> Uid -> CfgGen ()
addPred pred = modifyNode $ \n -> n { gnPred = UidSet.insert pred $ gnPred n }
addSucc :: Uid -> Uid -> CfgGen ()
addSucc succ = modifyNode $ \n -> n { gnSucc = UidSet.insert succ $ gnSucc n }
setPreds :: [Uid] -> Uid -> CfgGen ()
setPreds preds = modifyNode $ \n -> n { gnPred = UidSet.fromList preds }
setSuccs :: [Uid] -> Uid -> CfgGen ()
setSuccs succs = modifyNode $ \n -> n { gnSucc = UidSet.fromList succs }
-- Utility functions for handling CFG nodes
connect :: [Uid] -> [Uid] -> CfgGen ()
connect ps ss = forM_ ps $ \p -> forM_ ss $ \s -> addPred p s >> addSucc s p
nop :: CfgGen Uid
nop = do uid <- nuid
setNode uid $ GNNop UidSet.empty UidSet.empty
return uid
chain :: (Uid, Uid) -> (Uid, Uid) -> CfgGen (Uid, Uid)
chain (p1, s1) (p2, s2) = do s1ps <- getPreds s1
p2ss <- getSuccs p2
mapM_ (setPreds s1ps) p2ss
mapM_ (setSuccs p2ss) s1ps
return (p1, s2)
create :: (UidSet -> UidSet -> CfgGenNode) -> CfgGen (Uid, Uid)
create con = do p <- nop
s <- nop
n <- nuid
setNode n $ con UidSet.empty UidSet.empty
connect [p] [n]
connect [n] [s]
return (p, s)
-- Functions that return finished CFGs
cfgFromProgram :: Program -> Cfg
cfgFromProgram = undefined
fromProgram :: Program -> CfgGen Cfg
fromProgram = undefined
fromFunction :: Function -> CfgGen Cfg
fromFunction (FNamed name formals body retval) = do fs <- create $ GNDecl formals
bo <- fromStm body
re <- create $ GNReturn retval
most <- fs `chain` bo
whole <- most `chain` re
toCfg whole
fromFunction _ = error "Unweeded function"
toCfg :: (Uid, Uid) -> CfgGen Cfg
toCfg = undefined
-- Functions that build intermediate CFG representation
fromStm :: Stm -> CfgGen (Uid, Uid)
fromStm s@SAss{} = create $ GNAss s
fromStm s@SAssRef{} = create $ GNAss s
fromStm (SOutput e) = create $ GNOutput e
fromStm (SSeq ss@(_:_)) = mapM fromStm ss >>= \(s':ss') -> foldM chain s' ss'
fromStm (SSeq _) = error "Empty sequence of statements not weeded out"
fromStm s@(SIfElse cond th el) = do (tp, ts) <- fromStm th
(ep, es) <- fromStm el
np <- nop
ns <- nop
uid <- nuid
setNode uid $ GNBranch cond s tp ep UidSet.empty UidSet.empty
connect [np] [uid]
connect [uid] [tp, ep]
connect [ts, es] [ns]
return (np, ns)
fromStm s@(SWhile cond body) = do (bp, bs) <- fromStm body
np <- nop
ns <- nop
uid <- nuid
setNode uid $ GNBranch cond s bp bs UidSet.empty UidSet.empty
connect [np, bs] [uid]
connect [uid] [ns, bp]
return (np, ns)
fromStm (SDecl ids) = create $ GNDecl ids
fromStm (SReturn _) = error $ "Return statement not weeded out"
fromStm SNop = create GNNop