tock-mirror/pass/PassList.hs

175 lines
6.5 KiB
Haskell

{-
Tock: a compiler for parallel languages
Copyright (C) 2007, 2008 University of Kent
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
-}
-- | Lists of passes
module PassList (calculatePassList, getPassList) where
import Control.Monad.State
import Data.List
import qualified Data.Map as Map
import Data.Set (Set)
import qualified Data.Set as Set
import qualified AST as A
import BackendPasses
import Check
import CheckFramework
import CompState
import Errors
import GenerateC
import GenerateCPPCSP
import ImplicitMobility
import Metadata
import OccamPasses
import Pass
import qualified Properties as Prop
import RainPasses
import SimplifyAbbrevs
import SimplifyComms
import SimplifyExprs
import SimplifyProcs
import SimplifyTypes
import Unnest
import Utils
commonPasses :: CompState -> [Pass]
commonPasses opts = concat $
-- Rain does simplifyTypes separately:
[ enablePassesWhen ((== FrontendOccam) . csFrontend) simplifyTypes
, [fixLowReplicators]
, enablePassesWhen csUsageChecking
[pass "Usage checking" Prop.agg_namesDone [Prop.parUsageChecked]
(passOnlyOnAST "usageCheckPass" usageCheckPass)]
-- If usage checking is turned off, the pass list will break unless we insert this dummy item:
, enablePassesWhen (not . csUsageChecking)
[pass "Usage checking turned OFF" Prop.agg_namesDone [Prop.parUsageChecked]
return]
, enablePassesWhen csClassicOccamMobility [mobiliseArrays, inferDeref, implicitMobility]
, simplifyAbbrevs
, simplifyComms
, simplifyExprs
, simplifyProcs
, unnest
, enablePassesWhen csUsageChecking
[abbrevCheckPass]
, backendPasses
-- , [pass "Removing unused variables" [] []
-- (passOnlyOnAST "checkUnusedVar" (runChecks checkUnusedVar))]
]
filterPasses :: CompState -> [Pass] -> [Pass]
filterPasses opts = filter (\p -> passEnabled p opts)
-- This pass is so small that we may as well just give it here:
nullStateBodies :: Pass
nullStateBodies = Pass
{passCode = \t ->
((get >>* \st -> st {csNames = Map.map nullProcFuncDefs (csNames st)}) >>= put)
>> return t
,passName = "Remove process and function bodies from compiler state"
,passPre = Set.empty
,passPost = Set.empty
,passEnabled = const True}
where
nullProcFuncDefs :: A.NameDef -> A.NameDef
nullProcFuncDefs (A.NameDef m n on (A.Proc m' sm fs _) am ns pl)
= (A.NameDef m n on (A.Proc m' sm fs (A.Skip m')) am ns pl)
nullProcFuncDefs (A.NameDef m n on (A.Function m' sm ts fs (Left _)) am ns pl)
= (A.NameDef m n on (A.Function m' sm ts fs (Left $ A.Several m' [])) am ns pl)
nullProcFuncDefs (A.NameDef m n on (A.Function m' sm ts fs (Right _)) am ns pl)
= (A.NameDef m n on (A.Function m' sm ts fs (Right $ A.Skip m')) am ns pl)
nullProcFuncDefs x = x
getPassList :: CompState -> [Pass]
getPassList optsPS = checkList $ filterPasses optsPS $ concat
[ [nullStateBodies]
, enablePassesWhen ((== FrontendOccam) . csFrontend)
occamPasses
, enablePassesWhen ((== FrontendRain) . csFrontend)
rainPasses
, commonPasses optsPS
, genCPasses
, genCPPCSPPasses
]
calculatePassList :: CSMR m => m [Pass]
calculatePassList
= do optsPS <- getCompState
let passes = getPassList optsPS
return $ if csSanityCheck optsPS
then addChecks passes
else passes
where
-- | Add extra passes to check that properties hold.
-- Each property will be checked after the last pass that provides it has
-- run.
addChecks :: [Pass] -> [Pass]
addChecks = reverse . (addChecks' Set.empty) . reverse
addChecks' :: Set Property -> [Pass] -> [Pass]
addChecks' _ [] = []
addChecks' checked (p:ps) = checks ++ [p] ++ addChecks' checked' ps
where
props = Set.difference (passPost p) checked
checked' = Set.union checked props
checks = [pass ("[" ++ propName prop ++ "]")
[]
[]
(passOnlyOnAST "prop" $ checkProp prop)
| prop <- Set.toList props]
checkProp :: Property -> A.AST -> PassM A.AST
checkProp prop ast = propCheck prop ast >> return ast
-- | If something isn't right, it gives back a list containing a single pass
-- that will give an error.
checkList :: [Pass] -> [Pass]
checkList passes
= case check [] passes of
Left err -> [pass "Pass list internal error"
[]
[]
(const $ dieP emptyMeta err)
]
Right ps -> ps
where
check :: [Pass] -> [Pass] -> Either String [Pass]
check prev [] = Right prev
check prev (p:ps)
= case filter givesPrereq (p:ps) of
-- Check that our pre-requisites are not supplied by a later pass
-- or supplied by the pass that needs them:
(x:_) ->
Left $ "Pass order not correct; one of the pre-requisites"
++ " for pass: " ++ (passName p) ++ " is supplied in a later"
++ " pass: " ++ (passName x) ++ ", pre-requisites in question"
++ " are: " ++ show (Set.intersection (passPost x) (passPre p))
-- Now check that someone supplied our pre-requisites:
[] -> if Set.null (passPre p) || any givesPrereq prev
then check (prev ++ [p]) ps
else Left $ "Pass order not correct; one of the pre-requisites"
++ " for pass: " ++ (passName p) ++ "is not supplied"
++ " by a prior pass, pre-requisites are: "
++ show (passPre p)
where
givesPrereq :: Pass -> Bool
givesPrereq p' = not $ Set.null $
Set.intersection (passPost p') (passPre p)