File: Dataflow.hs

package info (click to toggle)
kaya 0.4.4-6.2
  • links: PTS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 5,200 kB
  • ctags: 2,015
  • sloc: cpp: 9,556; haskell: 7,253; sh: 3,060; yacc: 910; makefile: 816; perl: 90
file content (221 lines) | stat: -rw-r--r-- 8,579 bytes parent folder | download | duplicates (4)
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
{-
    Kaya - My favourite toy language.
    Copyright (C) 2004-2007 Edwin Brady

    This file is distributed under the terms of the GNU General
    Public Licence. See COPYING for licence.
-}

module Dataflow where

-- Dataflow analysis, identifying interferences between local variables
-- (so that we can work out which to drop and which to reuse)

-- FIXME: This module is COMPLETELY BROKEN!

import Control.Monad.State
import Data.List

import Language

type Edge = (Loc, Loc) -- two names which interfere, order doesn't matter
type Graph = [Edge]

type Loc = Int

addEdge :: Loc -> Loc -> Graph -> Graph
addEdge x y es | x<y = nub ((x,y):es)
               | x==y = es
               | x>y = nub ((y,x):es)

-- A name is active from when it is assigned to, until the last point it is 
-- referenced before it is next assigned to. Any variables active at the
-- end of a while/do/for loop should also be counted as active at the start.
-- Any two variables active at the same time (with the sole exception of a
-- direct assignment x=y) are connected in the interference graph

-- If a variable is active at the start of a condition block, it also might
-- be active at the end if the block is skipped.

-- We analyse this by traversing an expression, effectively flattening it,
-- making a note of the point at which assignments and uses happen.
-- From that data, we can work out where there are overlapping uses.

data VarInfo = Assigned Loc Int -- assigned to name at location in code
             | Moved Loc Loc Int -- name is assigned from another name at loc
             | Used Loc Int -- name is accessed at location in code
             | Loop Int Int -- a loop entry point and exit point
             | Condition Int Int -- a conditional block span
   deriving (Show, Eq)

-- Order based on location

instance Ord VarInfo where
    compare x y = compare (loc x) (loc y)
       where loc (Assigned _ l) = l
             loc (Moved _ _ l) = l
             loc (Used _ l) = l
             loc (Loop s e) = s
             loc (Condition s e) = s

type VarState = (Int, -- program counter
                 Int, -- number of locals
                 [VarInfo]) -- what happens

addVS v = do (pc, locs, vs) <- get
             put (pc+1, locs, ((v pc):vs))

addPC = do (pc, locs, vs) <- get
           put (pc+1, locs, vs)
           return pc

addLoc = do (pc, locs, vs) <- get
            put (pc, locs+1, vs)
            return locs -- return variable number

-- Create a list of what happens to each variable. Make a note that 'var'
-- args are additionally used at the end of the function (their value is put
-- back where the caller's value was)

findInfo :: [ArgType] -> Expr Name -> (Int, [VarInfo])
findInfo ivs e = let (pc, numVars, st) = execState (findVarInfo e) (0, 0, [])
                 in (numVars, sort (st ++ useVars 0 pc ivs))
   where useVars i pc (Var:xs) = (Used i pc):(useVars (i+1) (pc+1) xs)
         useVars i pc (_:xs) = useVars (i+1) (pc+1) xs
         useVars i pc [] = []

findVarInfo :: Expr Name -> State VarState ()
-- Interesting cases first
findVarInfo (Loc i) = addVS $ Used i
findVarInfo (Assign (AName i) (Loc j)) = addVS $ Moved j i
findVarInfo (Assign (AName i) e) = do findVarInfo e
                                      addVS $ Assigned i
findVarInfo (Assign a e) = do findVarInfo e
                              findAInfo a
findVarInfo (AssignOp op a e) 
    = do findVarInfo e
         case a of 
             (AName i) -> addVS $ Assigned i
             _ -> findAInfo a
findVarInfo (AssignApp a e) 
    = do findVarInfo e
         case a of 
             (AName i) -> addVS $ Assigned i
             _ -> findAInfo a
findVarInfo (Case e alts) = do findVarInfo e
                               mapM_ findAltInfo alts
   where findAltInfo (Alt _ _ args res) = -- assign to args, run res
             do mapM_ findArgInfo args
                findVarCond res
         findAltInfo (ConstAlt _ _ e) = findVarCond e
         findAltInfo (ArrayAlt es e) = 
             do mapM_ findArgInfo es
                findVarCond e
         findAltInfo (Default e) = findVarCond e

         findArgInfo (Loc i) = addVS $ Assigned i
         findArgInfo _ = return ()
findVarInfo (While e b) = do pcStart <- addPC
                             findVarInfo e 
                             findVarInfo b
                             addVS $ Loop pcStart
findVarInfo (DoWhile e b) = do pcStart <- addPC
                               findVarInfo b
                               findVarInfo e
                               addVS $ Loop pcStart
findVarInfo (For i _ j a init body) 
    = do findVarInfo init
         pcStart <- addPC
         addVS $ Assigned i
         addVS $ Assigned j
         addVS $ Used i -- always used to keep the loop counter up to date
         addVS $ Used j -- always used to look up values from
         case a of
                (AName av) -> addVS $ Assigned av
                _ -> findAInfo a
         findVarInfo body
         addVS $ Loop pcStart
findVarInfo (If a t e) = do findVarInfo a
                            findVarCond t
                            findVarCond e
findVarInfo (Bind _ _ e1 e2) = do findVarInfo e1
                                  v <- addLoc
                                  addVS $ Assigned v
                                  findVarInfo e2
findVarInfo (Declare _ _ _ _ e) = do addLoc
                                     findVarInfo e
findVarInfo (NewTryCatch t cs) = do findVarInfo t
                                    mapM_ findCatchInfo cs
   where findCatchInfo (Catch (Left (_,args)) h) = do mapM_ findArgInfo args
                                                      findVarCond h
         findCatchInfo (Catch (Right n) h) = do findArgInfo n
                                                findVarCond h
         findArgInfo (Loc i) = addVS $ Assigned i
         findArgInfo _ = return ()

-- Arguments are evaluated before the function.
-- Arguments *may* be assigned to, in the case of a var function, but
-- the safe thing to do is to assume they aren't.
findVarInfo (Apply f es) = do mapM_ findVarInfo es ; findVarInfo f
findVarInfo (Foreign t n es) = mapM_ findVarInfo (map fst es)

-- Everything else structural
findVarInfo (Lambda _ _ e) = findVarInfo e
findVarInfo (Closure _ _ e) = findVarInfo e -- should have been lifted by now!
findVarInfo (Return e) = findVarInfo e
findVarInfo (Seq x y) = do findVarInfo x ; findVarInfo y
findVarInfo (ConApply f es) = do mapM_ findVarInfo es ; findVarInfo f
findVarInfo (Partial b f es _) = do mapM_ findVarInfo es ; findVarInfo f
findVarInfo (Throw e) = findVarInfo e
findVarInfo (NewExcept es) = mapM_ findVarInfo es
findVarInfo (Infix op l r) = do findVarInfo l
                                findVarInfo r
findVarInfo (RealInfix op l r) = do findVarInfo l
                                    findVarInfo r
findVarInfo (CmpExcept _ l r) = do findVarInfo l
                                   findVarInfo r
findVarInfo (CmpStr _ l r) = do findVarInfo l
                                findVarInfo r
findVarInfo (Append l r) = do findVarInfo l
                              findVarInfo r
findVarInfo (AppendChain es) = mapM_ findVarInfo es
findVarInfo (Unary _ e) = findVarInfo e
findVarInfo (RealUnary _ e) = findVarInfo e
findVarInfo (Coerce _ _ e) = findVarInfo e
findVarInfo (Index v i) = do findVarInfo i
                             findVarInfo v
findVarInfo (Field e _ _ _) = findVarInfo e
findVarInfo (ArrayInit es) = mapM_ findVarInfo es
findVarInfo (Length e) = findVarInfo e
findVarInfo (Annotation _ e) = findVarInfo e
findVarInfo _ = return ()

-- Helper for assigns

findAInfo (AName i) = -- looking inside, so it's a use not an assign
                      addVS $ Used i
findAInfo (AIndex a e) = do findVarInfo e
                            findAInfo a
findAInfo (AField a _ _ _) = findAInfo a
findAInfo _ = return ()

-- Helpfer for conditional blocks
findVarCond a = do cStart <- addPC
                   findVarInfo a
                   addVS $ Condition cStart

-- Now do some useful things with this information
-- Easy one: Spot variables which are assigned but never used. We can drop
-- all assignments to this.

-- XXXXX: Actually, Propagate.hs does this a much simpler way... 

neverUsed :: Int -> [VarInfo] -> [Int]
neverUsed 0 _ = []
neverUsed i vs = case filter (isUsed (i-1)) vs of
                        [] -> (i-1):(neverUsed (i-1) vs)
                        (_:_) -> neverUsed (i-1) vs

isUsed i (Used j _) | i == j = True
isUsed i (Moved j _ _) | i == j = True
isUsed _ _ = False