Add a pass for folding constants in occam.
The existing constant-folding code in the parser is still there, since it needs to know whether things are constant, and A.Dimension expects an Int. However, this pass is useful because it does a better job of constant folding than the parser would on its own: it can fold subexpressions of expressions that are as a whole not constant.
This commit is contained in:
parent
3340e95806
commit
3005dfb506
|
@ -164,6 +164,7 @@ tocktest_SOURCES += common/TestFramework.hs
|
||||||
tocktest_SOURCES += common/TestHarness.hs
|
tocktest_SOURCES += common/TestHarness.hs
|
||||||
tocktest_SOURCES += common/TestUtils.hs
|
tocktest_SOURCES += common/TestUtils.hs
|
||||||
tocktest_SOURCES += flow/FlowGraphTest.hs
|
tocktest_SOURCES += flow/FlowGraphTest.hs
|
||||||
|
tocktest_SOURCES += frontends/OccamPassesTest.hs
|
||||||
tocktest_SOURCES += frontends/ParseRainTest.hs
|
tocktest_SOURCES += frontends/ParseRainTest.hs
|
||||||
tocktest_SOURCES += frontends/PreprocessOccamTest.hs
|
tocktest_SOURCES += frontends/PreprocessOccamTest.hs
|
||||||
tocktest_SOURCES += frontends/RainPassesTest.hs
|
tocktest_SOURCES += frontends/RainPassesTest.hs
|
||||||
|
|
|
@ -28,6 +28,8 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
--
|
--
|
||||||
-- * "GenerateCTest"
|
-- * "GenerateCTest"
|
||||||
--
|
--
|
||||||
|
-- * "OccamPassesTest"
|
||||||
|
--
|
||||||
-- * "ParseRainTest"
|
-- * "ParseRainTest"
|
||||||
--
|
--
|
||||||
-- * "PassTest"
|
-- * "PassTest"
|
||||||
|
@ -56,6 +58,7 @@ import qualified BackendPassesTest (qcTests)
|
||||||
import qualified CommonTest (tests)
|
import qualified CommonTest (tests)
|
||||||
import qualified FlowGraphTest (qcTests)
|
import qualified FlowGraphTest (qcTests)
|
||||||
import qualified GenerateCTest (tests)
|
import qualified GenerateCTest (tests)
|
||||||
|
import qualified OccamPassesTest (tests)
|
||||||
import qualified ParseRainTest (tests)
|
import qualified ParseRainTest (tests)
|
||||||
import qualified PassTest (tests)
|
import qualified PassTest (tests)
|
||||||
import qualified PreprocessOccamTest (tests)
|
import qualified PreprocessOccamTest (tests)
|
||||||
|
@ -170,6 +173,7 @@ main = do (opts, nonOpts, errs) <- getArgs >>* getOpt RequireOrder options
|
||||||
,noqc CommonTest.tests
|
,noqc CommonTest.tests
|
||||||
,return FlowGraphTest.qcTests
|
,return FlowGraphTest.qcTests
|
||||||
,noqc GenerateCTest.tests
|
,noqc GenerateCTest.tests
|
||||||
|
,noqc OccamPassesTest.tests
|
||||||
,noqc ParseRainTest.tests
|
,noqc ParseRainTest.tests
|
||||||
,noqc PassTest.tests
|
,noqc PassTest.tests
|
||||||
,noqc PreprocessOccamTest.tests
|
,noqc PreprocessOccamTest.tests
|
||||||
|
|
|
@ -168,6 +168,13 @@ defineName :: CSM m => A.Name -> A.NameDef -> m ()
|
||||||
defineName n nd
|
defineName n nd
|
||||||
= modify $ (\ps -> ps { csNames = Map.insert (A.nameName n) nd (csNames ps) })
|
= modify $ (\ps -> ps { csNames = Map.insert (A.nameName n) nd (csNames ps) })
|
||||||
|
|
||||||
|
-- | Modify the definition of a name.
|
||||||
|
modifyName :: CSM m => A.Name -> (A.NameDef -> A.NameDef) -> m ()
|
||||||
|
modifyName n f
|
||||||
|
= modify $ (\ps -> ps { csNames = modifyName $ csNames ps })
|
||||||
|
where
|
||||||
|
modifyName = Map.adjust f (A.nameName n)
|
||||||
|
|
||||||
-- | Find the definition of a name.
|
-- | Find the definition of a name.
|
||||||
lookupName :: (CSMR m, Die m) => A.Name -> m A.NameDef
|
lookupName :: (CSMR m, Die m) => A.Name -> m A.NameDef
|
||||||
lookupName n = lookupNameOrError n (dieP (findMeta n) $ "cannot find name " ++ A.nameName n)
|
lookupName n = lookupNameOrError n (dieP (findMeta n) $ "cannot find name " ++ A.nameName n)
|
||||||
|
|
|
@ -17,24 +17,55 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
-}
|
-}
|
||||||
|
|
||||||
-- | The occam-specific frontend passes.
|
-- | The occam-specific frontend passes.
|
||||||
module OccamPasses (occamPasses) where
|
module OccamPasses (occamPasses, foldConstants) where
|
||||||
|
|
||||||
import Data.Generics
|
import Data.Generics
|
||||||
|
|
||||||
|
import qualified AST as A
|
||||||
import CompState
|
import CompState
|
||||||
|
import EvalConstants
|
||||||
import Pass
|
import Pass
|
||||||
import qualified Properties as Prop
|
import qualified Properties as Prop
|
||||||
|
|
||||||
-- | Occam-specific frontend passes.
|
-- | Occam-specific frontend passes.
|
||||||
occamPasses :: [Pass]
|
occamPasses :: [Pass]
|
||||||
occamPasses = makePassesDep' ((== FrontendOccam) . csFrontend)
|
occamPasses = makePassesDep' ((== FrontendOccam) . csFrontend)
|
||||||
[ ("Dummy occam pass", dummyOccamPass,
|
[ ("Fold constants", foldConstants,
|
||||||
[],
|
[],
|
||||||
Prop.agg_namesDone ++ [Prop.constantsFolded, Prop.expressionTypesChecked,
|
[Prop.constantsFolded])
|
||||||
|
, ("Dummy occam pass", dummyOccamPass,
|
||||||
|
[],
|
||||||
|
Prop.agg_namesDone ++ [Prop.expressionTypesChecked,
|
||||||
Prop.inferredTypesRecorded, Prop.mainTagged,
|
Prop.inferredTypesRecorded, Prop.mainTagged,
|
||||||
Prop.processTypesChecked])
|
Prop.processTypesChecked])
|
||||||
]
|
]
|
||||||
|
|
||||||
|
-- | Fold constant expressions.
|
||||||
|
foldConstants :: Data t => t -> PassM t
|
||||||
|
foldConstants = doGeneric `extM` doSpecification `extM` doExpression
|
||||||
|
where
|
||||||
|
doGeneric :: Data t => t -> PassM t
|
||||||
|
doGeneric = makeGeneric foldConstants
|
||||||
|
|
||||||
|
-- When an expression is abbreviated, try to fold it, and update its
|
||||||
|
-- definition so that it can be used when folding later expressions.
|
||||||
|
doSpecification :: A.Specification -> PassM A.Specification
|
||||||
|
doSpecification s@(A.Specification m n (A.IsExpr m' am t e))
|
||||||
|
= do e' <- doExpression e
|
||||||
|
let st' = A.IsExpr m' am t e'
|
||||||
|
modifyName n (\nd -> nd { A.ndType = st' })
|
||||||
|
return $ A.Specification m n st'
|
||||||
|
doSpecification s = doGeneric s
|
||||||
|
|
||||||
|
-- For all other expressions, just try to fold them.
|
||||||
|
-- We recurse into the expression first so that we fold subexpressions of
|
||||||
|
-- non-constant expressions too.
|
||||||
|
doExpression :: A.Expression -> PassM A.Expression
|
||||||
|
doExpression e
|
||||||
|
= do e' <- doGeneric e
|
||||||
|
(e'', _, _) <- constantFold e'
|
||||||
|
return e''
|
||||||
|
|
||||||
-- | A dummy pass for things that haven't been separated out into passes yet.
|
-- | A dummy pass for things that haven't been separated out into passes yet.
|
||||||
dummyOccamPass :: Data t => t -> PassM t
|
dummyOccamPass :: Data t => t -> PassM t
|
||||||
dummyOccamPass = return
|
dummyOccamPass = return
|
||||||
|
|
114
frontends/OccamPassesTest.hs
Normal file
114
frontends/OccamPassesTest.hs
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
{-
|
||||||
|
Tock: a compiler for parallel languages
|
||||||
|
Copyright (C) 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/>.
|
||||||
|
-}
|
||||||
|
|
||||||
|
-- #ignore-exports
|
||||||
|
|
||||||
|
-- | Tests for 'OccamPasses'.
|
||||||
|
|
||||||
|
module OccamPassesTest (tests) where
|
||||||
|
|
||||||
|
import Control.Monad.State
|
||||||
|
import Data.Generics
|
||||||
|
import Test.HUnit hiding (State)
|
||||||
|
|
||||||
|
import qualified AST as A
|
||||||
|
import CompState
|
||||||
|
import Metadata
|
||||||
|
import qualified OccamPasses
|
||||||
|
import TestUtils
|
||||||
|
|
||||||
|
m :: Meta
|
||||||
|
m = emptyMeta
|
||||||
|
|
||||||
|
-- | Test 'OccamPasses.foldConstants'.
|
||||||
|
testFoldConstants :: Test
|
||||||
|
testFoldConstants = TestList
|
||||||
|
[
|
||||||
|
-- Trivial stuff
|
||||||
|
testSame 0 one
|
||||||
|
, testSame 1 var
|
||||||
|
|
||||||
|
-- Things that shouldn't fold
|
||||||
|
, testSame 10 (add var one)
|
||||||
|
, testSame 11 (add one var)
|
||||||
|
, testSame 12 (add var (add one var))
|
||||||
|
, testSame 13 (add one (add var one))
|
||||||
|
, testSame 14 (add var (add one var))
|
||||||
|
|
||||||
|
-- Things that should fold
|
||||||
|
, test 20 (add one one) two
|
||||||
|
, test 21 (add one (add one one)) three
|
||||||
|
, test 22 (add (add one one) one) three
|
||||||
|
, test 23 (add one two) three
|
||||||
|
, test 24 (add one (add one (add one one))) four
|
||||||
|
, test 25 (add (add one (add one one)) one) four
|
||||||
|
, test 26 (add (add (add one one) one) one) four
|
||||||
|
|
||||||
|
-- Folding subexpressions of a non-constant expression
|
||||||
|
, test 30 (add var (add one one)) (add var two)
|
||||||
|
, test 31 (add (add one one) var) (add two var)
|
||||||
|
, test 32 (add var (add var (add one one))) (add var (add var two))
|
||||||
|
|
||||||
|
-- Folding existing constant variables
|
||||||
|
, test 40 const two
|
||||||
|
, test 41 (add const (add one one)) four
|
||||||
|
, test 42 (add (add one one) const) four
|
||||||
|
, test 43 (add const (add const (add one one))) six
|
||||||
|
, test 44 (add var const) (add var two)
|
||||||
|
, test 45 (add const var) (add two var)
|
||||||
|
, test 46 (add const const) four
|
||||||
|
, test 47 (add const (add var one)) (add two (add var one))
|
||||||
|
, test 48 (add var (add const one)) (add var three)
|
||||||
|
]
|
||||||
|
where
|
||||||
|
test :: Data a => Int -> a -> a -> Test
|
||||||
|
test n orig exp = TestCase $ testPass ("testFoldConstants" ++ show n)
|
||||||
|
exp (OccamPasses.foldConstants orig)
|
||||||
|
startState
|
||||||
|
|
||||||
|
startState :: State CompState ()
|
||||||
|
startState = defineConst "const" A.Int two
|
||||||
|
|
||||||
|
defineConst :: String -> A.Type -> A.Expression -> State CompState ()
|
||||||
|
defineConst s t e = defineName (simpleName s) $
|
||||||
|
A.NameDef {
|
||||||
|
A.ndMeta = m,
|
||||||
|
A.ndName = "const",
|
||||||
|
A.ndOrigName = "const",
|
||||||
|
A.ndNameType = A.VariableName,
|
||||||
|
A.ndType = A.IsExpr m A.ValAbbrev t e,
|
||||||
|
A.ndAbbrevMode = A.ValAbbrev,
|
||||||
|
A.ndPlacement = A.Unplaced
|
||||||
|
}
|
||||||
|
|
||||||
|
testSame :: Int -> A.Expression -> Test
|
||||||
|
testSame n orig = test n orig orig
|
||||||
|
|
||||||
|
add e f = A.Dyadic m A.Add e f
|
||||||
|
var = exprVariable "var"
|
||||||
|
const = exprVariable "const"
|
||||||
|
one = intLiteral 1
|
||||||
|
two = intLiteral 2
|
||||||
|
three = intLiteral 3
|
||||||
|
four = intLiteral 4
|
||||||
|
six = intLiteral 6
|
||||||
|
|
||||||
|
tests :: Test
|
||||||
|
tests = TestLabel "OccamPassesTest" $ TestList
|
||||||
|
[ testFoldConstants
|
||||||
|
]
|
Loading…
Reference in New Issue
Block a user