1 module OptimizationFuel
2 ( OptimizationFuel, canRewriteWithFuel, maybeRewriteWithFuel, oneLessFuel
3 , OptFuelState, initOptFuelState --, setTotalFuel
4 , tankFilledTo, diffFuel
6 , FuelUsingMonad, FuelState
7 , lastFuelPass, fuelExhausted, fuelRemaining, fuelDecrement, fuelDec1
8 , runFuelIO, fuelConsumingPass
11 , lGraphOfGraph -- needs to be able to create a unique ID...
17 --import GHC.Exts (State#)
21 import StaticFlags (opt_Fuel)
24 #include "HsVersions.h"
27 -- We limit the number of transactions executed using a record of flags
28 -- stored in an HscEnv. The flags store the name of the last optimization
29 -- pass and the amount of optimization fuel remaining.
31 OptFuelState { pass_ref :: IORef String
32 , fuel_ref :: IORef OptimizationFuel
34 initOptFuelState :: IO OptFuelState
36 do pass_ref' <- newIORef "unoptimized program"
37 fuel_ref' <- newIORef (tankFilledTo opt_Fuel)
38 return OptFuelState {pass_ref = pass_ref', fuel_ref = fuel_ref'}
40 type FuelConsumer a = OptimizationFuel -> (a, OptimizationFuel)
42 canRewriteWithFuel :: OptimizationFuel -> Bool
43 oneLessFuel :: OptimizationFuel -> OptimizationFuel
44 maybeRewriteWithFuel :: OptimizationFuel -> Maybe a -> Maybe a
45 diffFuel :: OptimizationFuel -> OptimizationFuel -> Int
46 -- to measure consumption during compilation
47 tankFilledTo :: Int -> OptimizationFuel
50 newtype OptimizationFuel = OptimizationFuel Int
53 tankFilledTo = OptimizationFuel
54 canRewriteWithFuel (OptimizationFuel f) = f > 0
55 maybeRewriteWithFuel fuel ma = if canRewriteWithFuel fuel then ma else Nothing
56 oneLessFuel (OptimizationFuel f) = ASSERT (f > 0) (OptimizationFuel (f - 1))
57 diffFuel (OptimizationFuel f) (OptimizationFuel f') = f - f'
59 -- type OptimizationFuel = State# () -- would like this, but it won't work
60 data OptimizationFuel = OptimizationFuel
62 tankFilledTo _ = panic "tankFilledTo" -- should be impossible to evaluate
63 -- realWorld# might come in handy, too...
64 canRewriteWithFuel OptimizationFuel = True
65 maybeRewriteWithFuel _ ma = ma
70 data FuelState = FuelState { fs_fuellimit :: OptimizationFuel, fs_lastpass :: String }
71 newtype FuelMonad a = FuelMonad (FuelState -> UniqSM (a, FuelState))
73 fuelConsumingPass :: String -> FuelConsumer a -> FuelMonad a
74 fuelConsumingPass name f = do fuel <- fuelRemaining
75 let (a, fuel') = f fuel
76 fuelDecrement name fuel fuel'
79 runFuelIO :: OptFuelState -> FuelMonad a -> IO a
80 runFuelIO fs (FuelMonad f) =
81 do pass <- readIORef (pass_ref fs)
82 fuel <- readIORef (fuel_ref fs)
83 u <- mkSplitUniqSupply 'u'
84 let (a, FuelState fuel' pass') = initUs_ u $ f (FuelState fuel pass)
85 writeIORef (pass_ref fs) pass'
86 writeIORef (fuel_ref fs) fuel'
89 instance Monad FuelMonad where
90 FuelMonad f >>= k = FuelMonad (\s -> do (a, s') <- f s
91 let FuelMonad f' = k a in (f' s'))
92 return a = FuelMonad (\s -> return (a, s))
94 instance MonadUnique FuelMonad where
95 getUniqueSupplyM = liftUniq getUniqueSupplyM
96 getUniqueM = liftUniq getUniqueM
97 getUniquesM = liftUniq getUniquesM
98 liftUniq :: UniqSM x -> FuelMonad x
99 liftUniq x = FuelMonad (\s -> x >>= (\u -> return (u, s)))
101 class Monad m => FuelUsingMonad m where
102 fuelRemaining :: m OptimizationFuel
103 fuelDecrement :: String -> OptimizationFuel -> OptimizationFuel -> m ()
105 fuelExhausted :: m Bool
106 lastFuelPass :: m String
108 instance FuelUsingMonad FuelMonad where
109 fuelRemaining = extract fs_fuellimit
110 lastFuelPass = extract fs_lastpass
111 fuelExhausted = extract $ not . canRewriteWithFuel . fs_fuellimit
112 fuelDecrement p f f' = FuelMonad (\s -> return ((), fuelDecrementState p f f' s))
113 fuelDec1 = FuelMonad f
114 where f s = if canRewriteWithFuel (fs_fuellimit s) then
115 return ((), s { fs_fuellimit = oneLessFuel (fs_fuellimit s) })
116 else panic "Tried to use exhausted fuel supply"
118 extract :: (FuelState -> a) -> FuelMonad a
119 extract f = FuelMonad (\s -> return (f s, s))
122 :: String -> OptimizationFuel -> OptimizationFuel -> FuelState -> FuelState
123 fuelDecrementState new_optimizer old new s =
124 FuelState { fs_fuellimit = lim, fs_lastpass = optimizer }
125 where lim = if diffFuel old (fs_fuellimit s) == 0 then new
127 concat ["lost track of ", new_optimizer, "'s transactions"]
128 optimizer = if diffFuel old new > 0 then new_optimizer else fs_lastpass s
130 -- lGraphOfGraph is here because we need uniques to implement it.
131 lGraphOfGraph :: Graph m l -> FuelMonad (LGraph m l)
132 lGraphOfGraph (Graph tail blocks) =
133 do entry <- liftM BlockId $ getUniqueM
134 return $ LGraph entry (insertBlock (Block entry tail) blocks)