1 -- CmmNode type for representation using Hoopl graphs.
5 , UpdFrameOffset, Convention(..), ForeignConvention(..), ForeignTarget(..)
6 , mapExp, mapExpDeep, foldExp, foldExpDeep
18 import Prelude hiding (succ)
21 ------------------------
24 data CmmNode e x where
25 CmmEntry :: Label -> CmmNode C O
26 CmmComment :: FastString -> CmmNode O O
27 CmmAssign :: CmmReg -> CmmExpr -> CmmNode O O -- Assign to register
28 CmmStore :: CmmExpr -> CmmExpr -> CmmNode O O -- Assign to memory location. Size is
29 -- given by cmmExprType of the rhs.
30 CmmUnsafeForeignCall :: -- An unsafe foreign call; see Note [Foreign calls]
31 ForeignTarget -> -- call target
32 CmmFormals -> -- zero or more results
33 CmmActuals -> -- zero or more arguments
35 CmmBranch :: Label -> CmmNode O C -- Goto another block in the same procedure
36 CmmCondBranch :: { -- conditional branch
38 cml_true, cml_false :: Label
40 CmmSwitch :: CmmExpr -> [Maybe Label] -> CmmNode O C -- Table branch
41 -- The scrutinee is zero-based;
42 -- zero -> first block
43 -- one -> second block etc
44 -- Undefined outside range, and when there's a Nothing
45 CmmCall :: { -- A call (native or safe foreign)
46 cml_target :: CmmExpr, -- never a CmmPrim to a CallishMachOp!
48 cml_cont :: Maybe Label,
49 -- Label of continuation (Nothing for return or tail call)
52 -- Byte offset, from the *old* end of the Area associated with
53 -- the Label (if cml_cont = Nothing, then Old area), of
54 -- youngest outgoing arg. Set the stack pointer to this before
55 -- transferring control.
56 -- (NB: an update frame might also have been stored in the Old
57 -- area, but it'll be in an older part than the args.)
59 cml_ret_args :: ByteOff,
60 -- For calls *only*, the byte offset for youngest returned value
61 -- This is really needed at the *return* point rather than here
62 -- at the call, but in practice it's convenient to record it here.
64 cml_ret_off :: ByteOff
65 -- For calls *only*, the byte offset of the base of the frame that
66 -- must be described by the info table for the return point.
67 -- The older words are an update frames, which have their own
68 -- info-table and layout information
70 -- From a liveness point of view, the stack words older than
71 -- cml_ret_off are treated as live, even if the sequel of
72 -- the call goes into a loop.
74 CmmForeignCall :: { -- A safe foreign call; see Note [Foreign calls]
75 tgt :: ForeignTarget, -- call target and convention
76 res :: CmmFormals, -- zero or more results
77 args :: CmmActuals, -- zero or more arguments
78 succ :: Label, -- Label of continuation
79 updfr :: UpdFrameOffset, -- where the update frame is (for building infotable)
80 intrbl:: Bool -- whether or not the call is interruptible
83 {- Note [Foreign calls]
84 ~~~~~~~~~~~~~~~~~~~~~~~
85 A MidForeign call is used for *unsafe* foreign calls;
86 a LastForeign call is used for *safe* foreign calls.
87 Unsafe ones are easy: think of them as a "fat machine instruction".
89 Safe ones are trickier. A safe foreign call
92 push "return address" -- Never used to return to;
93 -- just points an info table
94 save registers into TSO
96 r = f(x) -- Make the call
100 We cannot "lower" a safe foreign call to this sequence of Cmms, because
101 after we've saved Sp all the Cmm optimiser's assumptions are broken.
102 Furthermore, currently the smart Cmm constructors know the calling
103 conventions for Haskell, the garbage collector, etc, and "lower" them
104 so that a LastCall passes no parameters or results. But the smart
105 constructors do *not* (currently) know the foreign call conventions.
107 Note that a safe foreign call needs an info table.
110 ---------------------------------------------
111 -- Eq instance of CmmNode
112 -- It is a shame GHC cannot infer it by itself :(
114 instance Eq (CmmNode e x) where
115 (CmmEntry a) == (CmmEntry a') = a==a'
116 (CmmComment a) == (CmmComment a') = a==a'
117 (CmmAssign a b) == (CmmAssign a' b') = a==a' && b==b'
118 (CmmStore a b) == (CmmStore a' b') = a==a' && b==b'
119 (CmmUnsafeForeignCall a b c) == (CmmUnsafeForeignCall a' b' c') = a==a' && b==b' && c==c'
120 (CmmBranch a) == (CmmBranch a') = a==a'
121 (CmmCondBranch a b c) == (CmmCondBranch a' b' c') = a==a' && b==b' && c==c'
122 (CmmSwitch a b) == (CmmSwitch a' b') = a==a' && b==b'
123 (CmmCall a b c d e) == (CmmCall a' b' c' d' e') = a==a' && b==b' && c==c' && d==d' && e==e'
124 (CmmForeignCall a b c d e f) == (CmmForeignCall a' b' c' d' e' f') = a==a' && b==b' && c==c' && d==d' && e==e' && f==f'
127 ----------------------------------------------
128 -- Hoopl instances of CmmNode
130 instance NonLocal CmmNode where
131 entryLabel (CmmEntry l) = l
132 -- entryLabel _ = error "CmmNode.entryLabel"
134 successors (CmmBranch l) = [l]
135 successors (CmmCondBranch {cml_true=t, cml_false=f}) = [f, t] -- meets layout constraint
136 successors (CmmSwitch _ ls) = catMaybes ls
137 successors (CmmCall {cml_cont=l}) = maybeToList l
138 successors (CmmForeignCall {succ=l}) = [l]
139 -- successors _ = error "CmmNode.successors"
142 instance HooplNode CmmNode where
143 mkBranchNode label = CmmBranch label
144 mkLabelNode label = CmmEntry label
146 --------------------------------------------------
147 -- Various helper types
149 type UpdFrameOffset = ByteOff
152 = NativeDirectCall -- Native C-- call skipping the node (closure) argument
153 | NativeNodeCall -- Native C-- call including the node argument
154 | NativeReturn -- Native C-- return
155 | Slow -- Slow entry points: all args pushed on the stack
156 | GC -- Entry to the garbage collector: uses the node reg!
157 | PrimOpCall -- Calling prim ops
158 | PrimOpReturn -- Returning from prim ops
159 | Foreign -- Foreign call/return
162 -- Used for control transfers within a (pre-CPS) procedure All
163 -- jump sites known, never pushed on the stack (hence no SRT)
164 -- You can choose whatever calling convention you please
165 -- (provided you make sure all the call sites agree)!
166 -- This data type eventually to be extended to record the convention.
169 data ForeignConvention
171 CCallConv -- Which foreign-call convention
172 [ForeignHint] -- Extra info about the args
173 [ForeignHint] -- Extra info about the result
176 data ForeignTarget -- The target of a foreign call
177 = ForeignTarget -- A foreign procedure
178 CmmExpr -- Its address
179 ForeignConvention -- Its calling convention
180 | PrimTarget -- A possibly-side-effecting machine operation
181 CallishMachOp -- Which one
184 --------------------------------------------------
185 -- Instances of register and slot users / definers
187 instance UserOfLocalRegs (CmmNode e x) where
188 foldRegsUsed f z n = case n of
189 CmmAssign _ expr -> fold f z expr
190 CmmStore addr rval -> fold f (fold f z addr) rval
191 CmmUnsafeForeignCall t _ args -> fold f (fold f z t) args
192 CmmCondBranch expr _ _ -> fold f z expr
193 CmmSwitch expr _ -> fold f z expr
194 CmmCall {cml_target=tgt} -> fold f z tgt
195 CmmForeignCall {tgt=tgt, args=args} -> fold f (fold f z tgt) args
197 where fold :: forall a b.
199 (b -> LocalReg -> b) -> b -> a -> b
200 fold f z n = foldRegsUsed f z n
202 instance UserOfLocalRegs ForeignTarget where
203 foldRegsUsed _f z (PrimTarget _) = z
204 foldRegsUsed f z (ForeignTarget e _) = foldRegsUsed f z e
206 instance DefinerOfLocalRegs (CmmNode e x) where
207 foldRegsDefd f z n = case n of
208 CmmAssign lhs _ -> fold f z lhs
209 CmmUnsafeForeignCall _ fs _ -> fold f z fs
210 CmmForeignCall {res=res} -> fold f z res
212 where fold :: forall a b.
213 DefinerOfLocalRegs a =>
214 (b -> LocalReg -> b) -> b -> a -> b
215 fold f z n = foldRegsDefd f z n
218 instance UserOfSlots (CmmNode e x) where
219 foldSlotsUsed f z n = case n of
220 CmmAssign _ expr -> fold f z expr
221 CmmStore addr rval -> fold f (fold f z addr) rval
222 CmmUnsafeForeignCall _ _ args -> fold f z args
223 CmmCondBranch expr _ _ -> fold f z expr
224 CmmSwitch expr _ -> fold f z expr
225 CmmCall {cml_target=tgt} -> fold f z tgt
226 CmmForeignCall {tgt=tgt, args=args} -> fold f (fold f z tgt) args
228 where fold :: forall a b.
230 (b -> SubArea -> b) -> b -> a -> b
231 fold f z n = foldSlotsUsed f z n
233 instance UserOfSlots ForeignTarget where
234 foldSlotsUsed f z (ForeignTarget e _) = foldSlotsUsed f z e
235 foldSlotsUsed _f z (PrimTarget _) = z
237 instance DefinerOfSlots (CmmNode e x) where
238 foldSlotsDefd f z n = case n of
239 CmmStore (CmmStackSlot a i) expr -> f z (a, i, widthInBytes $ typeWidth $ cmmExprType expr)
240 CmmForeignCall {res=res} -> fold f z $ map foreign_call_slot res
245 (b -> SubArea -> b) -> b -> a -> b
246 fold f z n = foldSlotsDefd f z n
247 foreign_call_slot r = case widthInBytes $ typeWidth $ localRegType r of w -> (RegSlot r, w, w)
249 -----------------------------------
250 -- mapping Expr in CmmNode
252 mapForeignTarget :: (CmmExpr -> CmmExpr) -> ForeignTarget -> ForeignTarget
253 mapForeignTarget exp (ForeignTarget e c) = ForeignTarget (exp e) c
254 mapForeignTarget _ m@(PrimTarget _) = m
256 -- Take a transformer on expressions and apply it recursively.
257 wrapRecExp :: (CmmExpr -> CmmExpr) -> CmmExpr -> CmmExpr
258 wrapRecExp f (CmmMachOp op es) = f (CmmMachOp op $ map (wrapRecExp f) es)
259 wrapRecExp f (CmmLoad addr ty) = f (CmmLoad (wrapRecExp f addr) ty)
262 mapExp :: (CmmExpr -> CmmExpr) -> CmmNode e x -> CmmNode e x
263 mapExp _ f@(CmmEntry _) = f
264 mapExp _ m@(CmmComment _) = m
265 mapExp f (CmmAssign r e) = CmmAssign r (f e)
266 mapExp f (CmmStore addr e) = CmmStore (f addr) (f e)
267 mapExp f (CmmUnsafeForeignCall tgt fs as) = CmmUnsafeForeignCall (mapForeignTarget f tgt) fs (map f as)
268 mapExp _ l@(CmmBranch _) = l
269 mapExp f (CmmCondBranch e ti fi) = CmmCondBranch (f e) ti fi
270 mapExp f (CmmSwitch e tbl) = CmmSwitch (f e) tbl
271 mapExp f (CmmCall tgt mb_id o i s) = CmmCall (f tgt) mb_id o i s
272 mapExp f (CmmForeignCall tgt fs as succ updfr intrbl) = CmmForeignCall (mapForeignTarget f tgt) fs (map f as) succ updfr intrbl
274 mapExpDeep :: (CmmExpr -> CmmExpr) -> CmmNode e x -> CmmNode e x
275 mapExpDeep f = mapExp $ wrapRecExp f
277 -----------------------------------
278 -- folding Expr in CmmNode
280 foldExpForeignTarget :: (CmmExpr -> z -> z) -> ForeignTarget -> z -> z
281 foldExpForeignTarget exp (ForeignTarget e _) z = exp e z
282 foldExpForeignTarget _ (PrimTarget _) z = z
284 -- Take a folder on expressions and apply it recursively.
285 wrapRecExpf :: (CmmExpr -> z -> z) -> CmmExpr -> z -> z
286 wrapRecExpf f e@(CmmMachOp _ es) z = foldr (wrapRecExpf f) (f e z) es
287 wrapRecExpf f e@(CmmLoad addr _) z = wrapRecExpf f addr (f e z)
288 wrapRecExpf f e z = f e z
290 foldExp :: (CmmExpr -> z -> z) -> CmmNode e x -> z -> z
291 foldExp _ (CmmEntry {}) z = z
292 foldExp _ (CmmComment {}) z = z
293 foldExp f (CmmAssign _ e) z = f e z
294 foldExp f (CmmStore addr e) z = f addr $ f e z
295 foldExp f (CmmUnsafeForeignCall t _ as) z = foldr f (foldExpForeignTarget f t z) as
296 foldExp _ (CmmBranch _) z = z
297 foldExp f (CmmCondBranch e _ _) z = f e z
298 foldExp f (CmmSwitch e _) z = f e z
299 foldExp f (CmmCall {cml_target=tgt}) z = f tgt z
300 foldExp f (CmmForeignCall {tgt=tgt, args=args}) z = foldr f (foldExpForeignTarget f tgt z) args
302 foldExpDeep :: (CmmExpr -> z -> z) -> CmmNode e x -> z -> z
303 foldExpDeep f = foldExp $ wrapRecExpf f