From deab9c5abd58d8c6b10a04cf759e377ccd1d4b39 Mon Sep 17 00:00:00 2001 From: MatthewDavidGoodman <67522125+MatthewDavidGoodman@users.noreply.github.com> Date: Tue, 25 Apr 2023 17:31:54 -0400 Subject: [PATCH 01/11] 1st draft of par optimization --- regression-tests/tests/newerparadd.ssl | 28 ++++++++++++++++++++ regression-tests/tests/newestparadd.ssl | 5 ++++ regression-tests/tests/par-tuple.ssl | 34 +++++++++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 regression-tests/tests/newerparadd.ssl create mode 100644 regression-tests/tests/newestparadd.ssl create mode 100644 regression-tests/tests/par-tuple.ssl diff --git a/regression-tests/tests/newerparadd.ssl b/regression-tests/tests/newerparadd.ssl new file mode 100644 index 00000000..3d3cc2fb --- /dev/null +++ b/regression-tests/tests/newerparadd.ssl @@ -0,0 +1,28 @@ + +add a b = a + b +main cin cout = + let q = par 2+3 + 3+4 + let q = par 2+3 + 3+4 + let q = par 2+3 + 3+4 + () + + + +/*add a b = a + b + +main cin cout = + let x = 2 + y = 3 + r = add x y + let q = par add 65 2 + add 66 3 + () + + + after 1, cout <- r + 48 // Should print 5 + wait cout + after 1, cout <- 10 + wait cout*/ \ No newline at end of file diff --git a/regression-tests/tests/newestparadd.ssl b/regression-tests/tests/newestparadd.ssl new file mode 100644 index 00000000..a3c271e6 --- /dev/null +++ b/regression-tests/tests/newestparadd.ssl @@ -0,0 +1,5 @@ +add a b = a + b +main cin cout = + let q = par add 2 3 + add 3 4 + () diff --git a/regression-tests/tests/par-tuple.ssl b/regression-tests/tests/par-tuple.ssl new file mode 100644 index 00000000..d5a4d4de --- /dev/null +++ b/regression-tests/tests/par-tuple.ssl @@ -0,0 +1,34 @@ +// checking that 2-tuples can be declared with new syntax +type Pair2 a b + Pair2 a b + +add a b = a + b + +printCharTuple putc p = + match p + (x,y) = putc x + putc 32 + putc y + +main cin cout = + let putc c = after 1, cout <- c + wait cout + let putnl _ = putc 10 + + let x = 66 + let y = 67 + let q = par add x 0 + add y 0 + let q =(add x 0, add y 0) + let r = (x,y) + printCharTuple putc r // this is okay + putnl () + //printCharTuple putc q // this causes type error + putnl () + +/* +###### Testing par-tuple +stack exec sslc -- tests/par-tuple.ssl > out/par-tuple.c +TypeError (ErrorMsg "Ill-typed expression. Expected Type Pair2 [Type Int32 [],Type Int32 []], but got Type (,) [Type Int32 [],Type Int32 []]") +###### FAILED +*/ \ No newline at end of file From 2ee462f4f563497936b388ca719eab787605cd71 Mon Sep 17 00:00:00 2001 From: MatthewDavidGoodman <67522125+MatthewDavidGoodman@users.noreply.github.com> Date: Tue, 25 Apr 2023 17:34:56 -0400 Subject: [PATCH 02/11] Draft 1 of optimize par --- src/IR/OptimizePar.hs | 177 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 159 insertions(+), 18 deletions(-) diff --git a/src/IR/OptimizePar.hs b/src/IR/OptimizePar.hs index c930e8fc..59641d8a 100644 --- a/src/IR/OptimizePar.hs +++ b/src/IR/OptimizePar.hs @@ -20,6 +20,7 @@ import Control.Monad.State.Lazy ( ) import IR.IR (Literal (LitIntegral)) import qualified IR.IR as I +import Data.Bifunctor -- | Optimization Environment @@ -70,29 +71,65 @@ Maps over top level definitions, removing unnecessary pars. optimizePar :: I.Program I.Type -> Compiler.Pass (I.Program I.Type) optimizePar p = runLiftFn $ do optimizedDefs <- mapM optimizeParTop $ I.programDefs p - return $ p{I.programDefs = optimizedDefs} + fail ("Number of Bad Par Exprs in " ++ show (map fst (map tupleMatch1 optimizedDefs)) ++ ": " ++ (show (map tupleMatch optimizedDefs))) + return $ p{I.programDefs = map tupleMatch1 optimizedDefs} +--helper to pattern match on optimizedDefs tuple + +tupleMatch :: (I.VarId, I.Expr I.Type, (Int,Int)) -> (Int, Int) +tupleMatch (_, _, theInt) = theInt + +--another helper to pattern match on optimizedDefs tuple + +tupleMatch1 :: (I.VarId, I.Expr I.Type, (Int,Int)) -> (I.VarId, I.Expr I.Type) +tupleMatch1 (nm,rhs, _) = (nm,rhs) + +-- TO DO make sure works correctly -- | Given a top-level definition, detect + replace unnecessary par expressions -optimizeParTop :: (I.VarId, I.Expr I.Type) -> OptParFn (I.VarId, I.Expr I.Type) +optimizeParTop :: (I.VarId, I.Expr I.Type) -> OptParFn (I.VarId, I.Expr I.Type, (Int, Int)) optimizeParTop (nm, rhs) = do - rhs' <- detectReplaceBadPar rhs - (rhs'', _) <- countPars rhs' -- calling this so we don't get an "unused" warning - (rhs''', _) <- countBadPars rhs'' -- calling this so we don't get an "unused" warning + + -- rhs' <- detectReplaceBadPar rhs + (badParCount) <- countPars rhs -- calling this so we don't get an "unused" warning + --(rhs''', _) <- countBadPars rhs' -- calling this so we don't get an "unused" warning -- uncomment the line below to test countPars -- (_, result) <- countPars rhs - -- _ <- fail (show nm ++ ": Number of Par Exprs: " ++ show result) + --_ <- fail (show nm ++ ": Number of Par Exprs: " ++ show theint) -- uncomment the two lines below to test countBadPars -- (_, result') <- countBadPars rhs -- _ <- fail (show nm ++ ": Number of Bad Par Exprs: " ++ show result') - return (nm, rhs''') + + -- if bad par + return (nm, rhs, badParCount) + -- return (nm, rhs', snd theint) -- | Detect Unnecessary Par Expressions + Replace With Equivalent Sequential Expression -detectReplaceBadPar :: I.Expr I.Type -> OptParFn (I.Expr I.Type) -detectReplaceBadPar e = do - pure e -- for now, just return the same thing (don't do anyting) +-- call is bad par on itself, if yess, change the par expression into a sequence of let expressions + --in par node, call detect and replace bad par, call is bad par, if am bad, return let + --return tuple of arguments of par +--list of stuff on par node is the arguments to the par expression, sos add x 0 and add y 0, both of those are expr nodes +-- let q = par add x 0 +-- add y 0 +-- let q =(add x 0, add y 0) +-- let r = (x,y) + +--detectReplaceBadPar :: I.Expr I.Type -> OptParFn (I.Expr I.Type) +--detectReplaceBadPar (rhs) = do + --pure e -- for now, just return the same thing (don't do anyting) +-- if isBad rhs == 0 then do + -- rhs' <- rhs + -- return rhs' + --else do + -- replaceBadPar rhs + + +--replaceBadPar :: I.Expr I.Type -> OptParFn (I.Expr I.Type) +--replaceBadPar (rhs) = do + --rhs' <- rhs + --return rhs' {- | 1) Count Par Nodes @@ -102,14 +139,81 @@ Traverse the IR representation of the body of a top level defintion, and count the number of par expressions present. Return the body unchanged, as well as the count numPars. -} -countPars :: I.Expr I.Type -> OptParFn (I.Expr I.Type, Int) -countPars e = do - -- currently a stub - -- PUT YOUR IMPLEMENTATION HERE - x <- getNumberOfPars - updateNumberOfPars (x + 0) -- calling this so we don't get an "unused" warning - return (e, x) +countPars :: I.Expr I.Type -> OptParFn (Int, Int) +--countPars e = do +--countPars var ( I.Var _ _) = pure (var, 0) +--countPars e = pure(e,87) +countPars ( I.Var thevar t) = pure(0,0) +countPars ( I.Data thedata t) = pure(0,0) +countPars ( I.Lit theliteral t) = pure(0,0) +countPars (I.Exception exceptype t) = pure(0,0) + +--To Do finish case for app and match + +countPars (I.App theExpr theExpr2 t) = do + counterFirst <- countPars theExpr + counterSecond <- countPars theExpr2 + let left = fst counterFirst + fst counterSecond + let right = snd counterFirst + snd counterSecond + return (left,right) + +countPars (I.Lambda _ exprbody t) = countPars exprbody + + + +{- +let x = 5 + y = 6 + x+y +I.Let [("x", 5),("y",6)] (I.Prim PrimOp [x,y]) +Let [(Binder, Expr t)] (Expr t) t +-} +--recurse on the exprlist and the exprbody and add them together +--in the right hand side, examine all of the contents of exprlist, recurse countPars on contents and recurse on Expr body and sum counts + +countPars( I.Let exprlist exprbody t) = do + (numGoodParsInBody,numBadParsInBody) <- countPars exprbody +--call countPars on all the 2nd index of the nodes in the exprList +--TO DO: make moore readable + listPars <- mapM countPars (map snd (exprlist)) + let unzipped = (unzip listPars) + let sumPars = bimap sum sum unzipped + -- (numGoodParsInBinders,numBadParsInBinders) <- bimap sum (unzip listPars) + + let finalGoodCount = numGoodParsInBody + fst sumPars + let finalBadCount = numBadParsInBody + snd sumPars + -- return (finalCount,counterBadPars + counterBadPars1) + return (finalGoodCount, finalBadCount) +-- tedius, check return types are tuples + -- change the names and types for below +--countPars (I.Prim ) +--pattern match for primitive, then do a case for the nickname of primitive if it is par, then increment +--look at IR.hs for Prim, might have to recurse on something in prim, determine if prim is a par, or something else, and increment + + +--countPars (I.Prim I.Par exprlist t) = do + --(numGoodParsInList,numBadParsInList) <- mapM countPars exprlist + --numBadParsInList <- numBadParsInList + fromEnum (isBad (I.Prim I.Par exprlist t)) + --let numGoodParsInList = numGoodParsInList + 1 + --return (numGoodParsInList, numBadParsInList) +--countPars (I.Prim thePrimitive exprlist t) = do + -- (numGoodParsInList,numBadParsInList) <- mapM countPars exprlist + --return (numGoodParsInList,numBadParsInList) + +countPars (I.Prim I.Par exprlist t) = do + listPars <- mapM countPars exprlist + let unzipped = (unzip listPars) + let sumPars = bimap sum sum unzipped + let finalGoodCount = fst sumPars + let finalBadCount = snd sumPars + fromEnum (isBad (I.Prim I.Par exprlist t)) + return (finalGoodCount, finalBadCount) +countPars (I.Prim thePrimitive exprlist t) = do + listPars <- mapM countPars (exprlist) + let unzipped = (unzip listPars) + let sumPars = bimap sum sum unzipped + return sumPars +countPars(_) = pure (0,0) {- | 1.5) Implement IsBad Predicate @@ -118,8 +222,42 @@ Returns true if par expr contains only instantaneous expressions as arguments. False otherwise. Useful for exercise 2. -} + +--helper function +--bad par expr: par nodes lisit of arguments contains a wait +-- we assume that all function calls are blocking +--variable are non blocking +--prim operatiions that are not wait are non blocking +--literals are non blockiing +-- function calls are application nodes App (Expr t) (Expr t) t +-- nested function application, +-- add x 0 -> App(App(add,x),0) +-- a@(App _ _ ) +--whenever there any any non blocking calls, reqrite the expression so that the non blocking calls +--outside with a let, and blocking call remain with the par +-- if par has just 0 or 1 blocking call, no need for par +-- take our non blocking, append to tuple in correct position + + +isNotWait :: I.Expr I.Type -> Bool +isNotWait (I.Prim I.Wait _ _) = False +isNotWait (_) = True + +isNotFunction :: I.Expr I.Type -> Bool +isNotFunction (I.App expr1 expr2 t) = False +isNotFunction ( _ ) = True + + isBad :: I.Expr I.Type -> Bool -isBad _ = False -- currently a stub +--isBad theExpr = False -- currently a stub +isBad (I.Prim I.Par exprlist _) = do + (and (map isNotWait exprlist)) || (and (map isNotFunction exprlist)) + + + +--isBad look at arguments to par if there is a wait priumitive, its bad + + {- | 2) Count Bad Par Nodes @@ -131,6 +269,9 @@ and count the number of BAD par expressions present. Use the helper predicate "isBad" in your implementation. Return the body unchanged, as well as the count numBadPars. -} + +--not using this + countBadPars :: I.Expr I.Type -> OptParFn (I.Expr I.Type, Int) countBadPars e = do -- currently a stub From fe7199a6862d89d2231f69cec04a433b46120e4a Mon Sep 17 00:00:00 2001 From: MatthewDavidGoodman <67522125+MatthewDavidGoodman@users.noreply.github.com> Date: Tue, 25 Apr 2023 17:37:41 -0400 Subject: [PATCH 03/11] draft 1 of optimize par --- src/IR/OptimizePar.hs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/IR/OptimizePar.hs b/src/IR/OptimizePar.hs index 59641d8a..f40ba57f 100644 --- a/src/IR/OptimizePar.hs +++ b/src/IR/OptimizePar.hs @@ -1,6 +1,11 @@ {-# LANGUAGE DerivingVia #-} {-# LANGUAGE OverloadedStrings #-} + +--make draft, add 2 test cases + +--to debug, look at the isBad + {- | Remove unnecessary Par expressions from the IR This pass detects unnecessary par expressions and then replaces them with equivalent sequential expressions. From 7afe0d68bf37dcb63d3cf2d10603cae6c881c2f2 Mon Sep 17 00:00:00 2001 From: EmilySillars Date: Sat, 29 Apr 2023 12:13:13 -0400 Subject: [PATCH 04/11] use SCYB to simplify pass --- src/IR/OptimizePar.hs | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/src/IR/OptimizePar.hs b/src/IR/OptimizePar.hs index f40ba57f..b58c1104 100644 --- a/src/IR/OptimizePar.hs +++ b/src/IR/OptimizePar.hs @@ -26,7 +26,10 @@ import Control.Monad.State.Lazy ( import IR.IR (Literal (LitIntegral)) import qualified IR.IR as I import Data.Bifunctor - +import Common.Identifiers(Identifier (Identifier), TVarId (..)) +import IR.Types.Type +import Data.Generics.Aliases ( mkM ) +import Data.Generics.Schemes ( everywhereM ) -- | Optimization Environment data OptParCtx = OptParCtx @@ -38,7 +41,7 @@ data OptParCtx = OptParCtx -- | OptPar Monad -newtype OptParFn a = LiftFn (StateT OptParCtx Compiler.Pass a) +newtype OptParFn a = OptParFn (StateT OptParCtx Compiler.Pass a) deriving (Functor) via (StateT OptParCtx Compiler.Pass) deriving (Applicative) via (StateT OptParCtx Compiler.Pass) deriving (Monad) via (StateT OptParCtx Compiler.Pass) @@ -58,9 +61,9 @@ updateNumberOfPars num = do modify $ \st -> st{numPars = num} --- | Run a LiftFn computation. -runLiftFn :: OptParFn a -> Compiler.Pass a -runLiftFn (LiftFn m) = +-- | Run a OptParFn computation. +runOptParFn :: OptParFn a -> Compiler.Pass a +runOptParFn (OptParFn m) = evalStateT m OptParCtx @@ -68,16 +71,30 @@ runLiftFn (LiftFn m) = , numBadPars = 0 } - {- | Entry-point to Par Optimization. Maps over top level definitions, removing unnecessary pars. -} optimizePar :: I.Program I.Type -> Compiler.Pass (I.Program I.Type) -optimizePar p = runLiftFn $ do - optimizedDefs <- mapM optimizeParTop $ I.programDefs p - fail ("Number of Bad Par Exprs in " ++ show (map fst (map tupleMatch1 optimizedDefs)) ++ ": " ++ (show (map tupleMatch optimizedDefs))) - return $ p{I.programDefs = map tupleMatch1 optimizedDefs} +optimizePar p = runOptParFn $ do + defs' <- everywhereM (mkM findFixBadPar) $ I.programDefs p + -- optimizedDefs <- mapM optimizeParTop $ I.programDefs p + -- fail ("Number of Bad Par Exprs in " ++ show (map fst (map tupleMatch1 optimizedDefs)) ++ ": " ++ (show (map tupleMatch optimizedDefs))) + -- return $ p{I.programDefs = map tupleMatch1 optimizedDefs} + return $ p{I.programDefs = defs'} + +{- | Given an Expr as input, if it turns out to be a bad Par expr, rewrite it. + +Otherwise, leave the expression alone. +-} +findFixBadPar :: I.Expr I.Type -> OptParFn (I.Expr I.Type) +findFixBadPar e@__ = if isBad e then rewrite e else pure e + where rewrite :: I.Expr I.Type -> OptParFn (I.Expr I.Type) + rewrite p@(I.Prim I.Par exprlist _) = pure dummy --TODO: rewrite the bad par as good one + rewrite _ = fail "rewrite should only be called on a Par IR node!" + dummy = I.Var (I.VarId (Identifier "PINEAPPLE")) (TVar $ TVarId (Identifier "dummy")) + + --helper to pattern match on optimizedDefs tuple @@ -257,6 +274,7 @@ isBad :: I.Expr I.Type -> Bool --isBad theExpr = False -- currently a stub isBad (I.Prim I.Par exprlist _) = do (and (map isNotWait exprlist)) || (and (map isNotFunction exprlist)) +isBad _ = False From 9b9a2d3a641f77fef7f4cfdd4ce3d626e73e5b7f Mon Sep 17 00:00:00 2001 From: MatthewDavidGoodman <67522125+MatthewDavidGoodman@users.noreply.github.com> Date: Sat, 29 Apr 2023 19:41:28 -0400 Subject: [PATCH 05/11] Par Optimization 2 --- regression-tests/tests/newerparadd.ssl | 4 ++-- regression-tests/tests/newparadd.ssl | 15 +++++++++++++++ src/IR/OptimizePar.hs | 13 +++++++++++-- 3 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 regression-tests/tests/newparadd.ssl diff --git a/regression-tests/tests/newerparadd.ssl b/regression-tests/tests/newerparadd.ssl index 3d3cc2fb..126db03e 100644 --- a/regression-tests/tests/newerparadd.ssl +++ b/regression-tests/tests/newerparadd.ssl @@ -2,9 +2,9 @@ add a b = a + b main cin cout = let q = par 2+3 - 3+4 + 3+4 let q = par 2+3 - 3+4 + 3+4 let q = par 2+3 3+4 () diff --git a/regression-tests/tests/newparadd.ssl b/regression-tests/tests/newparadd.ssl new file mode 100644 index 00000000..ca23b01b --- /dev/null +++ b/regression-tests/tests/newparadd.ssl @@ -0,0 +1,15 @@ +type Pair2 a b + Pair2 a b + +add a b = a + b + +main cin cout = + let x = 5 + y = 60 + let r = par add x y + add y x + match r + (0,0) = () + (a1,a2) = cout <- a2 + wait cout + _ = () \ No newline at end of file diff --git a/src/IR/OptimizePar.hs b/src/IR/OptimizePar.hs index b58c1104..dd347709 100644 --- a/src/IR/OptimizePar.hs +++ b/src/IR/OptimizePar.hs @@ -77,10 +77,14 @@ Maps over top level definitions, removing unnecessary pars. -} optimizePar :: I.Program I.Type -> Compiler.Pass (I.Program I.Type) optimizePar p = runOptParFn $ do + defs' <- everywhereM (mkM findFixBadPar) $ I.programDefs p -- optimizedDefs <- mapM optimizeParTop $ I.programDefs p -- fail ("Number of Bad Par Exprs in " ++ show (map fst (map tupleMatch1 optimizedDefs)) ++ ": " ++ (show (map tupleMatch optimizedDefs))) -- return $ p{I.programDefs = map tupleMatch1 optimizedDefs} + + --return $ p{I.programDefs = p} + --return $ p{I.programDefs = I.programDefs p} return $ p{I.programDefs = defs'} {- | Given an Expr as input, if it turns out to be a bad Par expr, rewrite it. @@ -90,7 +94,11 @@ Otherwise, leave the expression alone. findFixBadPar :: I.Expr I.Type -> OptParFn (I.Expr I.Type) findFixBadPar e@__ = if isBad e then rewrite e else pure e where rewrite :: I.Expr I.Type -> OptParFn (I.Expr I.Type) - rewrite p@(I.Prim I.Par exprlist _) = pure dummy --TODO: rewrite the bad par as good one + -- structure of IR + rewrite p@(I.Prim I.Par exprlist _) = let + + pure dummy --TODO: rewrite the bad par as good one + rewrite _ = fail "rewrite should only be called on a Par IR node!" dummy = I.Var (I.VarId (Identifier "PINEAPPLE")) (TVar $ TVarId (Identifier "dummy")) @@ -227,6 +235,8 @@ countPars (I.Prim I.Par exprlist t) = do listPars <- mapM countPars exprlist let unzipped = (unzip listPars) let sumPars = bimap sum sum unzipped + + -- potential change let finalGoodCount = fst sumPars let finalBadCount = snd sumPars + fromEnum (isBad (I.Prim I.Par exprlist t)) return (finalGoodCount, finalBadCount) @@ -260,7 +270,6 @@ Useful for exercise 2. -- if par has just 0 or 1 blocking call, no need for par -- take our non blocking, append to tuple in correct position - isNotWait :: I.Expr I.Type -> Bool isNotWait (I.Prim I.Wait _ _) = False isNotWait (_) = True From 88fc42bc3aaa1f7e4483fd82b2ddc6b0d0f86abf Mon Sep 17 00:00:00 2001 From: EmilySillars Date: Sat, 29 Apr 2023 22:07:46 -0400 Subject: [PATCH 06/11] plans for optimize par --- src/IR/OptimizePar.hs | 110 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 107 insertions(+), 3 deletions(-) diff --git a/src/IR/OptimizePar.hs b/src/IR/OptimizePar.hs index dd347709..efda4136 100644 --- a/src/IR/OptimizePar.hs +++ b/src/IR/OptimizePar.hs @@ -71,6 +71,12 @@ runOptParFn (OptParFn m) = , numBadPars = 0 } + +--traversing the ir replaced with everywhere + +--isbad par + +--rewrite of case1, transorm into tuple {- | Entry-point to Par Optimization. Maps over top level definitions, removing unnecessary pars. @@ -91,19 +97,117 @@ optimizePar p = runOptParFn $ do Otherwise, leave the expression alone. -} + +--import foldApp from IR.IR +-- import tempTupleId from IR.Types.Type findFixBadPar :: I.Expr I.Type -> OptParFn (I.Expr I.Type) findFixBadPar e@__ = if isBad e then rewrite e else pure e where rewrite :: I.Expr I.Type -> OptParFn (I.Expr I.Type) -- structure of IR - rewrite p@(I.Prim I.Par exprlist _) = let - - pure dummy --TODO: rewrite the bad par as good one + rewrite p@(I.Prim I.Par exprlist _) = pure x + where dataConstructorName = "Pair2" + t = (TVar $ TVarId (Identifier "dummy")) + --construct type that is tuple of arguments + x = (I.foldApp dConNode argsToTuple) + dConNode = I.Data (I.DConId (Identifier dataConstructorName)) t + argsToTuple = (zip exprlist (repeat t)) + + -- pure dummy --TODO: rewrite the bad par as good one rewrite _ = fail "rewrite should only be called on a Par IR node!" dummy = I.Var (I.VarId (Identifier "PINEAPPLE")) (TVar $ TVarId (Identifier "dummy")) +{- +case 1: +par 5 + 1 + 3 + 2 +^ we agree this par expr is bad +^ this par returns the value (5+1,3+2) + +We want to rewrite case 1 into +(5+1,3+2) +which really desugars into +(Pair2 5+1 3+2) +which as an IR node is +(I.App (I.App (I.DCon DConId "Pair2") (I.Prim (I.PrimOp PrimAdd) [(I.Lit 5), (I.Lit 1)])) (I.Prim (I.PrimOp PrimAdd) [(I.Lit 3), (I.Lit 1)])) + +What does par 5 + 1 look like as an IR node? + 3 + 2 +Prim I.Par [I.Prim (I.PrimOp PrimAdd) [(I.Lit 5), (I.Lit 1)], I.Prim (I.PrimOp PrimAdd) [(I.Lit 3), (I.Lit 1)]] t + +let arg1 = I.Prim (I.PrimOp PrimAdd) [(I.Lit 5), (I.Lit 1)] +let arg2 = I.Prim (I.PrimOp PrimAdd) [(I.Lit 3), (I.Lit 1)] +foldApp (I.Dcon I.DConId "Pair2") [arg1, arg2] +^foldApp returns a nested application such that "Pair2" is applied to a list of arguments + +(I.Prim I.Par exprlist _) + | + | + v +let tupleDataConstructorName = tempTupleId (length exprlist) // returns "Pair2" or "Pair3", or whatever you need +foldApp tupleDataConstructorName exprlist + + + + +--Case on type of Prime, whether has a Wait or a PrimOp +what is 5+1 as an IR node? +I.Prim (I.PrimOp PrimAdd) [(I.Lit 5), (I.Lit 1)] +^ do you agree with this? + +what is 3+2 as an IR node? +I.Prim (I.PrimOp PrimAdd) [(I.Lit 3), (I.Lit 1)] + + +What is (Pair2 5+1 3+2) as an IR node? +We know for reference: add 5 1 as an IR node is (I.App (I.App (I.Var VarId "add") (I.Lit 5)) (I.Lit 1)) +so we know that pair2 applied to its two arguments will look like in the IR as +(I.App (I.App (I.DCon DConId "Pair2") (I.Prim (I.PrimOp PrimAdd) [(I.Lit 5), (I.Lit 1)])) (I.Prim (I.PrimOp PrimAdd) [(I.Lit 3), (I.Lit 1)])) +We have a library function called foldApp that takes a function name and a list of arguments, +and wraps them up in application. +{- | Apply a function to zero or more arguments. +'foldApp' is the inverse of 'unfoldApp'. +-} +foldApp :: Expr t -> [(Expr t, t)] -> Expr t +foldApp = foldr $ \(a, t) f -> App f a t + +let arg1 = I.Prim (I.PrimOp PrimAdd) [(I.Lit 5), (I.Lit 1)] +let arg2 = I.Prim (I.PrimOp PrimAdd) [(I.Lit 3), (I.Lit 1)] +foldApp (I.Dcon I.DConId "Pair2") [arg1, arg2] + + Prim Primitive [Expr t] t + +(I.Lit 5) (I.PrimOp PrimAdd) [(I.Lit 1)] + + +(I.App I.DconId I.Literal I.PrimOp I.Literal I.Literal I.PrimOp I.Literal ) + + +//we will give tempTupleId the number of arguments par has, and if it has too many, it will throw an error + +case 2: we agree this par expr is bad, but only because of its second argument +par add 5 1 // (I.App (I.App (I.Var VarId "add") (I.Lit 5)) (I.Lit 1)) + 3 + 2 // I.Prim (I.PrimOp PrimAdd) [(I.Lit 3), (I.Lit 1)] + +We can't have a par with one argument, right? So this is really a case 1. + +case 3: we agree this par expr is bad, because has two instaneous arguments +par add 5 1 + add 6 7 + 4 + 3 +// here the par evaluates and then returns (add 5 1, add 6 7, 4+3) + +We want to rewrite case 3 to be +let x = 4 + 3 +let (a b) = par add 5 1 + add 6 7 +(a,b,x) + +For reference, let in the IR looks like: Let [(Binder, Expr t)] (Expr t) t + +-} --helper to pattern match on optimizedDefs tuple tupleMatch :: (I.VarId, I.Expr I.Type, (Int,Int)) -> (Int, Int) From 210a78696b0f9f69d30907896308b9b52d4a4e36 Mon Sep 17 00:00:00 2001 From: MatthewDavidGoodman <67522125+MatthewDavidGoodman@users.noreply.github.com> Date: Mon, 1 May 2023 11:29:15 -0400 Subject: [PATCH 07/11] Par Optimization Working, optimizes case1, par with instantaneous arguments --- regression-tests/tests/newerparadd.ssl | 4 ---- src/IR/OptimizePar.hs | 9 ++++++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/regression-tests/tests/newerparadd.ssl b/regression-tests/tests/newerparadd.ssl index 126db03e..9c7d75fa 100644 --- a/regression-tests/tests/newerparadd.ssl +++ b/regression-tests/tests/newerparadd.ssl @@ -3,10 +3,6 @@ add a b = a + b main cin cout = let q = par 2+3 3+4 - let q = par 2+3 - 3+4 - let q = par 2+3 - 3+4 () diff --git a/src/IR/OptimizePar.hs b/src/IR/OptimizePar.hs index efda4136..68afcc84 100644 --- a/src/IR/OptimizePar.hs +++ b/src/IR/OptimizePar.hs @@ -74,9 +74,12 @@ runOptParFn (OptParFn m) = --traversing the ir replaced with everywhere ---isbad par +--rewrite of case1, transorm into tuple is operational + +--isbad par testing on + +--case ---rewrite of case1, transorm into tuple {- | Entry-point to Par Optimization. Maps over top level definitions, removing unnecessary pars. @@ -386,7 +389,7 @@ isNotFunction ( _ ) = True isBad :: I.Expr I.Type -> Bool --isBad theExpr = False -- currently a stub isBad (I.Prim I.Par exprlist _) = do - (and (map isNotWait exprlist)) || (and (map isNotFunction exprlist)) + (and (map isNotWait exprlist)) && (and (map isNotFunction exprlist)) isBad _ = False From 7af7e1dac6fb4741c1001a9501f4706b77b7d1c1 Mon Sep 17 00:00:00 2001 From: MatthewDavidGoodman <67522125+MatthewDavidGoodman@users.noreply.github.com> Date: Tue, 2 May 2023 16:59:20 -0400 Subject: [PATCH 08/11] Par Optimization Operational with test cases --- regression-tests/tests/newerparadd.ssl | 3 + regression-tests/tests/newestparadd.ssl | 3 + regression-tests/tests/newparaddwait.ssl | 7 + regression-tests/tests/newparaddwait.ssl.fail | 7 + regression-tests/tests/parwait.ssl | 7 + src/IR/OptimizePar.hs | 206 ++---------------- 6 files changed, 44 insertions(+), 189 deletions(-) create mode 100644 regression-tests/tests/newparaddwait.ssl create mode 100644 regression-tests/tests/newparaddwait.ssl.fail create mode 100644 regression-tests/tests/parwait.ssl diff --git a/regression-tests/tests/newerparadd.ssl b/regression-tests/tests/newerparadd.ssl index 9c7d75fa..eee67b54 100644 --- a/regression-tests/tests/newerparadd.ssl +++ b/regression-tests/tests/newerparadd.ssl @@ -1,3 +1,6 @@ +type Pair2 a b + Pair2 a b + add a b = a + b main cin cout = diff --git a/regression-tests/tests/newestparadd.ssl b/regression-tests/tests/newestparadd.ssl index a3c271e6..ea985a67 100644 --- a/regression-tests/tests/newestparadd.ssl +++ b/regression-tests/tests/newestparadd.ssl @@ -1,3 +1,6 @@ +type Pair2 a b + Pair2 a b + add a b = a + b main cin cout = let q = par add 2 3 diff --git a/regression-tests/tests/newparaddwait.ssl b/regression-tests/tests/newparaddwait.ssl new file mode 100644 index 00000000..a2aa720c --- /dev/null +++ b/regression-tests/tests/newparaddwait.ssl @@ -0,0 +1,7 @@ +add a b = a + b +main cin cout = + let q = par 2+3 + 3+4 + wait cout + () + diff --git a/regression-tests/tests/newparaddwait.ssl.fail b/regression-tests/tests/newparaddwait.ssl.fail new file mode 100644 index 00000000..a2aa720c --- /dev/null +++ b/regression-tests/tests/newparaddwait.ssl.fail @@ -0,0 +1,7 @@ +add a b = a + b +main cin cout = + let q = par 2+3 + 3+4 + wait cout + () + diff --git a/regression-tests/tests/parwait.ssl b/regression-tests/tests/parwait.ssl new file mode 100644 index 00000000..f8bc7414 --- /dev/null +++ b/regression-tests/tests/parwait.ssl @@ -0,0 +1,7 @@ +add a b = a + b +main cin cout = + let q = par wait cout + wait cout + wait cout + () + diff --git a/src/IR/OptimizePar.hs b/src/IR/OptimizePar.hs index 68afcc84..74b10707 100644 --- a/src/IR/OptimizePar.hs +++ b/src/IR/OptimizePar.hs @@ -1,7 +1,5 @@ {-# LANGUAGE DerivingVia #-} {-# LANGUAGE OverloadedStrings #-} - - --make draft, add 2 test cases --to debug, look at the isBad @@ -76,9 +74,17 @@ runOptParFn (OptParFn m) = --rewrite of case1, transorm into tuple is operational ---isbad par testing on +--isbad is working + +-- run on all regression testss + +--check the types ---case +--can only take ut the instantenous expression if they occur before + + + +-- prepare for case 2 and casse 3 {- | Entry-point to Par Optimization. @@ -99,6 +105,12 @@ optimizePar p = runOptParFn $ do {- | Given an Expr as input, if it turns out to be a bad Par expr, rewrite it. Otherwise, leave the expression alone. + +checks for case1: + +case 1: +par 5 + 1 + 3 + 2 -} --import foldApp from IR.IR @@ -109,7 +121,7 @@ findFixBadPar e@__ = if isBad e then rewrite e else pure e -- structure of IR rewrite p@(I.Prim I.Par exprlist _) = pure x where dataConstructorName = "Pair2" - t = (TVar $ TVarId (Identifier "dummy")) + t = (TVar $ TVarId (Identifier "PINEAPPLE")) --construct type that is tuple of arguments x = (I.foldApp dConNode argsToTuple) dConNode = I.Data (I.DConId (Identifier dataConstructorName)) t @@ -168,191 +180,7 @@ so we know that pair2 applied to its two arguments will look like in the IR as We have a library function called foldApp that takes a function name and a list of arguments, and wraps them up in application. - -{- | Apply a function to zero or more arguments. - -'foldApp' is the inverse of 'unfoldApp'. --} -foldApp :: Expr t -> [(Expr t, t)] -> Expr t -foldApp = foldr $ \(a, t) f -> App f a t - -let arg1 = I.Prim (I.PrimOp PrimAdd) [(I.Lit 5), (I.Lit 1)] -let arg2 = I.Prim (I.PrimOp PrimAdd) [(I.Lit 3), (I.Lit 1)] -foldApp (I.Dcon I.DConId "Pair2") [arg1, arg2] - - Prim Primitive [Expr t] t - -(I.Lit 5) (I.PrimOp PrimAdd) [(I.Lit 1)] - - -(I.App I.DconId I.Literal I.PrimOp I.Literal I.Literal I.PrimOp I.Literal ) - - -//we will give tempTupleId the number of arguments par has, and if it has too many, it will throw an error - -case 2: we agree this par expr is bad, but only because of its second argument -par add 5 1 // (I.App (I.App (I.Var VarId "add") (I.Lit 5)) (I.Lit 1)) - 3 + 2 // I.Prim (I.PrimOp PrimAdd) [(I.Lit 3), (I.Lit 1)] - -We can't have a par with one argument, right? So this is really a case 1. - -case 3: we agree this par expr is bad, because has two instaneous arguments -par add 5 1 - add 6 7 - 4 + 3 -// here the par evaluates and then returns (add 5 1, add 6 7, 4+3) - -We want to rewrite case 3 to be -let x = 4 + 3 -let (a b) = par add 5 1 - add 6 7 -(a,b,x) - -For reference, let in the IR looks like: Let [(Binder, Expr t)] (Expr t) t - --} ---helper to pattern match on optimizedDefs tuple - -tupleMatch :: (I.VarId, I.Expr I.Type, (Int,Int)) -> (Int, Int) -tupleMatch (_, _, theInt) = theInt - ---another helper to pattern match on optimizedDefs tuple - -tupleMatch1 :: (I.VarId, I.Expr I.Type, (Int,Int)) -> (I.VarId, I.Expr I.Type) -tupleMatch1 (nm,rhs, _) = (nm,rhs) - --- TO DO make sure works correctly - --- | Given a top-level definition, detect + replace unnecessary par expressions -optimizeParTop :: (I.VarId, I.Expr I.Type) -> OptParFn (I.VarId, I.Expr I.Type, (Int, Int)) -optimizeParTop (nm, rhs) = do - - -- rhs' <- detectReplaceBadPar rhs - (badParCount) <- countPars rhs -- calling this so we don't get an "unused" warning - --(rhs''', _) <- countBadPars rhs' -- calling this so we don't get an "unused" warning - -- uncomment the line below to test countPars - -- (_, result) <- countPars rhs - --_ <- fail (show nm ++ ": Number of Par Exprs: " ++ show theint) - -- uncomment the two lines below to test countBadPars - -- (_, result') <- countBadPars rhs - -- _ <- fail (show nm ++ ": Number of Bad Par Exprs: " ++ show result') - - -- if bad par - return (nm, rhs, badParCount) - -- return (nm, rhs', snd theint) - - --- | Detect Unnecessary Par Expressions + Replace With Equivalent Sequential Expression - --- call is bad par on itself, if yess, change the par expression into a sequence of let expressions - --in par node, call detect and replace bad par, call is bad par, if am bad, return let - --return tuple of arguments of par ---list of stuff on par node is the arguments to the par expression, sos add x 0 and add y 0, both of those are expr nodes --- let q = par add x 0 --- add y 0 --- let q =(add x 0, add y 0) --- let r = (x,y) - ---detectReplaceBadPar :: I.Expr I.Type -> OptParFn (I.Expr I.Type) ---detectReplaceBadPar (rhs) = do - --pure e -- for now, just return the same thing (don't do anyting) --- if isBad rhs == 0 then do - -- rhs' <- rhs - -- return rhs' - --else do - -- replaceBadPar rhs - - ---replaceBadPar :: I.Expr I.Type -> OptParFn (I.Expr I.Type) ---replaceBadPar (rhs) = do - --rhs' <- rhs - --return rhs' - -{- | 1) Count Par Nodes - -Practice Exercise to Delete Later! - -Traverse the IR representation of the body of a top level defintion, -and count the number of par expressions present. -Return the body unchanged, as well as the count numPars. --} -countPars :: I.Expr I.Type -> OptParFn (Int, Int) ---countPars e = do ---countPars var ( I.Var _ _) = pure (var, 0) ---countPars e = pure(e,87) -countPars ( I.Var thevar t) = pure(0,0) -countPars ( I.Data thedata t) = pure(0,0) -countPars ( I.Lit theliteral t) = pure(0,0) -countPars (I.Exception exceptype t) = pure(0,0) - ---To Do finish case for app and match - -countPars (I.App theExpr theExpr2 t) = do - counterFirst <- countPars theExpr - counterSecond <- countPars theExpr2 - let left = fst counterFirst + fst counterSecond - let right = snd counterFirst + snd counterSecond - return (left,right) - -countPars (I.Lambda _ exprbody t) = countPars exprbody - - - -{- -let x = 5 - y = 6 - x+y -I.Let [("x", 5),("y",6)] (I.Prim PrimOp [x,y]) -Let [(Binder, Expr t)] (Expr t) t -} ---recurse on the exprlist and the exprbody and add them together ---in the right hand side, examine all of the contents of exprlist, recurse countPars on contents and recurse on Expr body and sum counts - -countPars( I.Let exprlist exprbody t) = do - (numGoodParsInBody,numBadParsInBody) <- countPars exprbody ---call countPars on all the 2nd index of the nodes in the exprList ---TO DO: make moore readable - listPars <- mapM countPars (map snd (exprlist)) - let unzipped = (unzip listPars) - let sumPars = bimap sum sum unzipped - -- (numGoodParsInBinders,numBadParsInBinders) <- bimap sum (unzip listPars) - - let finalGoodCount = numGoodParsInBody + fst sumPars - let finalBadCount = numBadParsInBody + snd sumPars - -- return (finalCount,counterBadPars + counterBadPars1) - return (finalGoodCount, finalBadCount) --- tedius, check return types are tuples - -- change the names and types for below - ---countPars (I.Prim ) ---pattern match for primitive, then do a case for the nickname of primitive if it is par, then increment ---look at IR.hs for Prim, might have to recurse on something in prim, determine if prim is a par, or something else, and increment - - ---countPars (I.Prim I.Par exprlist t) = do - --(numGoodParsInList,numBadParsInList) <- mapM countPars exprlist - --numBadParsInList <- numBadParsInList + fromEnum (isBad (I.Prim I.Par exprlist t)) - --let numGoodParsInList = numGoodParsInList + 1 - --return (numGoodParsInList, numBadParsInList) ---countPars (I.Prim thePrimitive exprlist t) = do - -- (numGoodParsInList,numBadParsInList) <- mapM countPars exprlist - --return (numGoodParsInList,numBadParsInList) - -countPars (I.Prim I.Par exprlist t) = do - listPars <- mapM countPars exprlist - let unzipped = (unzip listPars) - let sumPars = bimap sum sum unzipped - - -- potential change - let finalGoodCount = fst sumPars - let finalBadCount = snd sumPars + fromEnum (isBad (I.Prim I.Par exprlist t)) - return (finalGoodCount, finalBadCount) -countPars (I.Prim thePrimitive exprlist t) = do - listPars <- mapM countPars (exprlist) - let unzipped = (unzip listPars) - let sumPars = bimap sum sum unzipped - return sumPars -countPars(_) = pure (0,0) {- | 1.5) Implement IsBad Predicate From 1a31cbc7ebe910beecc774188250deefadec3ae3 Mon Sep 17 00:00:00 2001 From: EmilySillars Date: Tue, 2 May 2023 17:06:56 -0400 Subject: [PATCH 09/11] make type error viewable --- src/IR.hs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/IR.hs b/src/IR.hs index 3c9e5479..095b8d94 100644 --- a/src/IR.hs +++ b/src/IR.hs @@ -38,6 +38,7 @@ import Text.Show.Pretty -} data Mode = Continue + | DumpOptPar | DumpIR | DumpIRAnnotated | DumpIRTyped @@ -65,6 +66,11 @@ options = ["dump-ir"] (NoArg $ setMode DumpIR) "Print the IR immediately after lowering" + , Option + "" + ["dumpOptPar"] + (NoArg $ setMode DumpOptPar) + "Print the IR immediately after opt par pass" , Option "" ["dump-ir-annotated"] @@ -125,6 +131,7 @@ transform opt p = do p <- dConToFunc p p <- externToCall p p <- optimizePar p + when (mode opt == DumpOptPar) $ (throwError . Dump . ppShow) p p <- liftProgramLambdas p when (mode opt == DumpIRLifted) $ dump p p <- insertRefCounting p From 695c72d9ef25b103da69a85dac837399fdfa9676 Mon Sep 17 00:00:00 2001 From: EmilySillars Date: Thu, 15 Jun 2023 02:05:15 -0400 Subject: [PATCH 10/11] rename test files and get rid of build warnings --- .../{newerparadd.ssl => 1opt-par1.ssl.fail} | 0 .../{newestparadd.ssl => 1opt-par2.ssl.fail} | 0 .../{newparadd.ssl => 1opt-par3.ssl.fail} | 0 .../{newparaddwait.ssl => 1opt-par4.ssl.fail} | 0 ...paraddwait.ssl.fail => 1opt-par5.ssl.fail} | 0 .../{par-tuple.ssl => 1opt-par6.ssl.fail} | 0 .../tests/{parwait.ssl => 1opt-par7.ssl.fail} | 0 src/IR/OptimizePar.hs | 58 ++++++++++--------- 8 files changed, 30 insertions(+), 28 deletions(-) rename regression-tests/tests/{newerparadd.ssl => 1opt-par1.ssl.fail} (100%) rename regression-tests/tests/{newestparadd.ssl => 1opt-par2.ssl.fail} (100%) rename regression-tests/tests/{newparadd.ssl => 1opt-par3.ssl.fail} (100%) rename regression-tests/tests/{newparaddwait.ssl => 1opt-par4.ssl.fail} (100%) rename regression-tests/tests/{newparaddwait.ssl.fail => 1opt-par5.ssl.fail} (100%) rename regression-tests/tests/{par-tuple.ssl => 1opt-par6.ssl.fail} (100%) rename regression-tests/tests/{parwait.ssl => 1opt-par7.ssl.fail} (100%) diff --git a/regression-tests/tests/newerparadd.ssl b/regression-tests/tests/1opt-par1.ssl.fail similarity index 100% rename from regression-tests/tests/newerparadd.ssl rename to regression-tests/tests/1opt-par1.ssl.fail diff --git a/regression-tests/tests/newestparadd.ssl b/regression-tests/tests/1opt-par2.ssl.fail similarity index 100% rename from regression-tests/tests/newestparadd.ssl rename to regression-tests/tests/1opt-par2.ssl.fail diff --git a/regression-tests/tests/newparadd.ssl b/regression-tests/tests/1opt-par3.ssl.fail similarity index 100% rename from regression-tests/tests/newparadd.ssl rename to regression-tests/tests/1opt-par3.ssl.fail diff --git a/regression-tests/tests/newparaddwait.ssl b/regression-tests/tests/1opt-par4.ssl.fail similarity index 100% rename from regression-tests/tests/newparaddwait.ssl rename to regression-tests/tests/1opt-par4.ssl.fail diff --git a/regression-tests/tests/newparaddwait.ssl.fail b/regression-tests/tests/1opt-par5.ssl.fail similarity index 100% rename from regression-tests/tests/newparaddwait.ssl.fail rename to regression-tests/tests/1opt-par5.ssl.fail diff --git a/regression-tests/tests/par-tuple.ssl b/regression-tests/tests/1opt-par6.ssl.fail similarity index 100% rename from regression-tests/tests/par-tuple.ssl rename to regression-tests/tests/1opt-par6.ssl.fail diff --git a/regression-tests/tests/parwait.ssl b/regression-tests/tests/1opt-par7.ssl.fail similarity index 100% rename from regression-tests/tests/parwait.ssl rename to regression-tests/tests/1opt-par7.ssl.fail diff --git a/src/IR/OptimizePar.hs b/src/IR/OptimizePar.hs index 74b10707..8553ac9e 100644 --- a/src/IR/OptimizePar.hs +++ b/src/IR/OptimizePar.hs @@ -17,13 +17,11 @@ import qualified Common.Compiler as Compiler import Control.Monad.State.Lazy ( MonadState, StateT (..), - evalStateT, - gets, - modify, + evalStateT ) -import IR.IR (Literal (LitIntegral)) +-- import IR.IR (Literal (LitIntegral)) import qualified IR.IR as I -import Data.Bifunctor +-- import Data.Bifunctor import Common.Identifiers(Identifier (Identifier), TVarId (..)) import IR.Types.Type import Data.Generics.Aliases ( mkM ) @@ -49,14 +47,14 @@ newtype OptParFn a = OptParFn (StateT OptParCtx Compiler.Pass a) -- | Example func to delete later! Demonstrates how to extract a value from the OptParFn Monad -getNumberOfPars :: OptParFn Int -getNumberOfPars = gets numPars +-- getNumberOfPars :: OptParFn Int +-- getNumberOfPars = gets numPars -- | Example func to delete later! Demonstrates how to modify a value in the OptParFn Monad -updateNumberOfPars :: Int -> OptParFn () -updateNumberOfPars num = do - modify $ \st -> st{numPars = num} +-- updateNumberOfPars :: Int -> OptParFn () +-- updateNumberOfPars num = do +-- modify $ \st -> st{numPars = num} -- | Run a OptParFn computation. @@ -82,7 +80,7 @@ runOptParFn (OptParFn m) = --can only take ut the instantenous expression if they occur before - + -- prepare for case 2 and casse 3 @@ -97,7 +95,7 @@ optimizePar p = runOptParFn $ do -- optimizedDefs <- mapM optimizeParTop $ I.programDefs p -- fail ("Number of Bad Par Exprs in " ++ show (map fst (map tupleMatch1 optimizedDefs)) ++ ": " ++ (show (map tupleMatch optimizedDefs))) -- return $ p{I.programDefs = map tupleMatch1 optimizedDefs} - + --return $ p{I.programDefs = p} --return $ p{I.programDefs = I.programDefs p} return $ p{I.programDefs = defs'} @@ -116,21 +114,21 @@ par 5 + 1 --import foldApp from IR.IR -- import tempTupleId from IR.Types.Type findFixBadPar :: I.Expr I.Type -> OptParFn (I.Expr I.Type) -findFixBadPar e@__ = if isBad e then rewrite e else pure e +findFixBadPar e@__ = if isBad e then rewrite e else pure e where rewrite :: I.Expr I.Type -> OptParFn (I.Expr I.Type) -- structure of IR - rewrite p@(I.Prim I.Par exprlist _) = pure x + rewrite (I.Prim I.Par exprlist _) = pure x where dataConstructorName = "Pair2" - t = (TVar $ TVarId (Identifier "PINEAPPLE")) + t = TVar $ TVarId (Identifier "PINEAPPLE") --TODO: put in actual type here!!! --construct type that is tuple of arguments - x = (I.foldApp dConNode argsToTuple) + x = I.foldApp dConNode argsToTuple dConNode = I.Data (I.DConId (Identifier dataConstructorName)) t - argsToTuple = (zip exprlist (repeat t)) - + argsToTuple = zip exprlist (repeat t) + -- pure dummy --TODO: rewrite the bad par as good one rewrite _ = fail "rewrite should only be called on a Par IR node!" - dummy = I.Var (I.VarId (Identifier "PINEAPPLE")) (TVar $ TVarId (Identifier "dummy")) + -- dummy = I.Var (I.VarId (Identifier "PINEAPPLE")) (TVar $ TVarId (Identifier "dummy")) {- case 1: par 5 + 1 @@ -207,17 +205,21 @@ Useful for exercise 2. isNotWait :: I.Expr I.Type -> Bool isNotWait (I.Prim I.Wait _ _) = False -isNotWait (_) = True +isNotWait _ = True isNotFunction :: I.Expr I.Type -> Bool -isNotFunction (I.App expr1 expr2 t) = False -isNotFunction ( _ ) = True +isNotFunction I.App {} = False +isNotFunction _ = True +-- isNotFunction (I.App expr1 expr2 t) = False +-- isNotFunction ( _ ) = True isBad :: I.Expr I.Type -> Bool --isBad theExpr = False -- currently a stub isBad (I.Prim I.Par exprlist _) = do - (and (map isNotWait exprlist)) && (and (map isNotFunction exprlist)) + let left = all isNotWait exprlist + let right = all isNotFunction exprlist + left && right isBad _ = False @@ -239,8 +241,8 @@ Return the body unchanged, as well as the count numBadPars. --not using this -countBadPars :: I.Expr I.Type -> OptParFn (I.Expr I.Type, Int) -countBadPars e = do - -- currently a stub - let y = isBad (I.Lit (LitIntegral 5) (I.extract e)) -- calling this so we don't get an "unused" warning - return (e, fromEnum y) +-- countBadPars :: I.Expr I.Type -> OptParFn (I.Expr I.Type, Int) +-- countBadPars e = do +-- -- currently a stub +-- let y = isBad (I.Lit (LitIntegral 5) (I.extract e)) -- calling this so we don't get an "unused" warning +-- return (e, fromEnum y) From c808baa7a47736c7c84f8d36fc976922f8d91f10 Mon Sep 17 00:00:00 2001 From: EmilySillars Date: Thu, 15 Jun 2023 03:59:51 -0400 Subject: [PATCH 11/11] document test cases --- regression-tests/tests/1opt-par1.out | 1 + regression-tests/tests/1opt-par1.ssl.fail | 27 ------------- regression-tests/tests/1opt-par1.ssl.failing | 20 ++++++++++ regression-tests/tests/1opt-par2.out | 1 + regression-tests/tests/1opt-par2.ssl | 17 ++++++++ regression-tests/tests/1opt-par2.ssl.fail | 8 ---- regression-tests/tests/1opt-par3.out | 1 + regression-tests/tests/1opt-par3.ssl | 16 ++++++++ regression-tests/tests/1opt-par3.ssl.fail | 15 ------- regression-tests/tests/1opt-par4.out | 1 + regression-tests/tests/1opt-par4.ssl.fail | 7 ---- regression-tests/tests/1opt-par4.ssl.failing | 23 +++++++++++ regression-tests/tests/1opt-par5.out | 1 + regression-tests/tests/1opt-par5.ssl.fail | 7 ---- regression-tests/tests/1opt-par5.ssl.failing | 17 ++++++++ regression-tests/tests/1opt-par6.out | 1 + regression-tests/tests/1opt-par6.ssl.fail | 34 ---------------- regression-tests/tests/1opt-par6.ssl.failing | 16 ++++++++ regression-tests/tests/1opt-par7.failing | 41 ++++++++++++++++++++ regression-tests/tests/1opt-par7.out | 3 ++ regression-tests/tests/1opt-par7.ssl.fail | 7 ---- 21 files changed, 159 insertions(+), 105 deletions(-) create mode 100644 regression-tests/tests/1opt-par1.out delete mode 100644 regression-tests/tests/1opt-par1.ssl.fail create mode 100644 regression-tests/tests/1opt-par1.ssl.failing create mode 100644 regression-tests/tests/1opt-par2.out create mode 100644 regression-tests/tests/1opt-par2.ssl delete mode 100644 regression-tests/tests/1opt-par2.ssl.fail create mode 100644 regression-tests/tests/1opt-par3.out create mode 100644 regression-tests/tests/1opt-par3.ssl delete mode 100644 regression-tests/tests/1opt-par3.ssl.fail create mode 100644 regression-tests/tests/1opt-par4.out delete mode 100644 regression-tests/tests/1opt-par4.ssl.fail create mode 100644 regression-tests/tests/1opt-par4.ssl.failing create mode 100644 regression-tests/tests/1opt-par5.out delete mode 100644 regression-tests/tests/1opt-par5.ssl.fail create mode 100644 regression-tests/tests/1opt-par5.ssl.failing create mode 100644 regression-tests/tests/1opt-par6.out delete mode 100644 regression-tests/tests/1opt-par6.ssl.fail create mode 100644 regression-tests/tests/1opt-par6.ssl.failing create mode 100644 regression-tests/tests/1opt-par7.failing create mode 100644 regression-tests/tests/1opt-par7.out delete mode 100644 regression-tests/tests/1opt-par7.ssl.fail diff --git a/regression-tests/tests/1opt-par1.out b/regression-tests/tests/1opt-par1.out new file mode 100644 index 00000000..7ed6ff82 --- /dev/null +++ b/regression-tests/tests/1opt-par1.out @@ -0,0 +1 @@ +5 diff --git a/regression-tests/tests/1opt-par1.ssl.fail b/regression-tests/tests/1opt-par1.ssl.fail deleted file mode 100644 index eee67b54..00000000 --- a/regression-tests/tests/1opt-par1.ssl.fail +++ /dev/null @@ -1,27 +0,0 @@ -type Pair2 a b - Pair2 a b - - -add a b = a + b -main cin cout = - let q = par 2+3 - 3+4 - () - - - -/*add a b = a + b - -main cin cout = - let x = 2 - y = 3 - r = add x y - let q = par add 65 2 - add 66 3 - () - - - after 1, cout <- r + 48 // Should print 5 - wait cout - after 1, cout <- 10 - wait cout*/ \ No newline at end of file diff --git a/regression-tests/tests/1opt-par1.ssl.failing b/regression-tests/tests/1opt-par1.ssl.failing new file mode 100644 index 00000000..a0e00409 --- /dev/null +++ b/regression-tests/tests/1opt-par1.ssl.failing @@ -0,0 +1,20 @@ +// once non-application expressions are allowed inside a par, +// this test should pass. + +// check that optimize par pass does NOT rewrite par expressions +// that have at least one non-instantaneous argument + +type Pair2 a b + Pair2 a b + +add a b = a + b + +main cin cout = + let q = par 3+4 // instantaneous + add 3 4 // functions are not necessarily instantaneous + + // ^should NOT rewrite q as a tuple + after 1, cout <- 5 + 48 // Should print 5 + wait cout + after 1, cout <- 10 + wait cout diff --git a/regression-tests/tests/1opt-par2.out b/regression-tests/tests/1opt-par2.out new file mode 100644 index 00000000..7ed6ff82 --- /dev/null +++ b/regression-tests/tests/1opt-par2.out @@ -0,0 +1 @@ +5 diff --git a/regression-tests/tests/1opt-par2.ssl b/regression-tests/tests/1opt-par2.ssl new file mode 100644 index 00000000..7471880c --- /dev/null +++ b/regression-tests/tests/1opt-par2.ssl @@ -0,0 +1,17 @@ +// check that optimize par pass rewrites par expressions +// that have all instantaneous arguemnts as tuples + +type Pair2 a b + Pair2 a b + +add a b = a + b + +main cin cout = + let q = par 2+3 // instantaneous + 3+4 // instantaneous + + // ^should rewrite q as a tuple + after 1, cout <- 5 + 48 // Should print 5 + wait cout + after 1, cout <- 10 + wait cout diff --git a/regression-tests/tests/1opt-par2.ssl.fail b/regression-tests/tests/1opt-par2.ssl.fail deleted file mode 100644 index ea985a67..00000000 --- a/regression-tests/tests/1opt-par2.ssl.fail +++ /dev/null @@ -1,8 +0,0 @@ -type Pair2 a b - Pair2 a b - -add a b = a + b -main cin cout = - let q = par add 2 3 - add 3 4 - () diff --git a/regression-tests/tests/1opt-par3.out b/regression-tests/tests/1opt-par3.out new file mode 100644 index 00000000..7ed6ff82 --- /dev/null +++ b/regression-tests/tests/1opt-par3.out @@ -0,0 +1 @@ +5 diff --git a/regression-tests/tests/1opt-par3.ssl b/regression-tests/tests/1opt-par3.ssl new file mode 100644 index 00000000..f9565e56 --- /dev/null +++ b/regression-tests/tests/1opt-par3.ssl @@ -0,0 +1,16 @@ +// check that optimize par pass does NOT rewrite par expressions +// that have at least one non-instantaneous argument + +type Pair2 a b + Pair2 a b + +add a b = a + b + +main cin cout = + let q = par add 2 3 // functions are not necessarily instantaneous + add 3 4 // functions are not necessarily instantaneous + // ^should NOT rewrite q as a tuple + after 1, cout <- 5 + 48 // Should print 5 + wait cout + after 1, cout <- 10 + wait cout diff --git a/regression-tests/tests/1opt-par3.ssl.fail b/regression-tests/tests/1opt-par3.ssl.fail deleted file mode 100644 index ca23b01b..00000000 --- a/regression-tests/tests/1opt-par3.ssl.fail +++ /dev/null @@ -1,15 +0,0 @@ -type Pair2 a b - Pair2 a b - -add a b = a + b - -main cin cout = - let x = 5 - y = 60 - let r = par add x y - add y x - match r - (0,0) = () - (a1,a2) = cout <- a2 - wait cout - _ = () \ No newline at end of file diff --git a/regression-tests/tests/1opt-par4.out b/regression-tests/tests/1opt-par4.out new file mode 100644 index 00000000..f70f10e4 --- /dev/null +++ b/regression-tests/tests/1opt-par4.out @@ -0,0 +1 @@ +A diff --git a/regression-tests/tests/1opt-par4.ssl.fail b/regression-tests/tests/1opt-par4.ssl.fail deleted file mode 100644 index a2aa720c..00000000 --- a/regression-tests/tests/1opt-par4.ssl.fail +++ /dev/null @@ -1,7 +0,0 @@ -add a b = a + b -main cin cout = - let q = par 2+3 - 3+4 - wait cout - () - diff --git a/regression-tests/tests/1opt-par4.ssl.failing b/regression-tests/tests/1opt-par4.ssl.failing new file mode 100644 index 00000000..3ec1fe99 --- /dev/null +++ b/regression-tests/tests/1opt-par4.ssl.failing @@ -0,0 +1,23 @@ +// once codegen supports return value of tuples, +// this test should pass + +// check that optimize par pass does NOT rewrite par expressions +// that have at least one non-instantaneous argument + +type Pair2 a b + Pair2 a b + +add a b = a + b + +main cin cout = + let x = 5 + y = 60 + let r = par add x y // functions are not necessarily instantaneous + add y x // functions are not necessarily instantaneous + // ^should NOT rewrite r as a tuple + match r + (0,0) = () + (a1,a2) = after 1, cout <- a2 + wait cout + after 1, cout <- 10 + wait cout \ No newline at end of file diff --git a/regression-tests/tests/1opt-par5.out b/regression-tests/tests/1opt-par5.out new file mode 100644 index 00000000..7ed6ff82 --- /dev/null +++ b/regression-tests/tests/1opt-par5.out @@ -0,0 +1 @@ +5 diff --git a/regression-tests/tests/1opt-par5.ssl.fail b/regression-tests/tests/1opt-par5.ssl.fail deleted file mode 100644 index a2aa720c..00000000 --- a/regression-tests/tests/1opt-par5.ssl.fail +++ /dev/null @@ -1,7 +0,0 @@ -add a b = a + b -main cin cout = - let q = par 2+3 - 3+4 - wait cout - () - diff --git a/regression-tests/tests/1opt-par5.ssl.failing b/regression-tests/tests/1opt-par5.ssl.failing new file mode 100644 index 00000000..ba66dfc7 --- /dev/null +++ b/regression-tests/tests/1opt-par5.ssl.failing @@ -0,0 +1,17 @@ +// once non-application expressions are allowed inside a par, +// this test should pass. + +// check that optimize par pass does NOT rewrite par expressions +// that have at least one non-instantaneous argument + +add a b = a + b + +main cin cout = + let q = par 2+3 // instantaneous + 3+4 // instantaneous + wait cout // NOT instantaneous + // ^should NOT rewrite q as a tuple + after 1, cout <- 5 + 48 // Should print 5 + wait cout + after 1, cout <- 10 + wait cout diff --git a/regression-tests/tests/1opt-par6.out b/regression-tests/tests/1opt-par6.out new file mode 100644 index 00000000..7ed6ff82 --- /dev/null +++ b/regression-tests/tests/1opt-par6.out @@ -0,0 +1 @@ +5 diff --git a/regression-tests/tests/1opt-par6.ssl.fail b/regression-tests/tests/1opt-par6.ssl.fail deleted file mode 100644 index d5a4d4de..00000000 --- a/regression-tests/tests/1opt-par6.ssl.fail +++ /dev/null @@ -1,34 +0,0 @@ -// checking that 2-tuples can be declared with new syntax -type Pair2 a b - Pair2 a b - -add a b = a + b - -printCharTuple putc p = - match p - (x,y) = putc x - putc 32 - putc y - -main cin cout = - let putc c = after 1, cout <- c - wait cout - let putnl _ = putc 10 - - let x = 66 - let y = 67 - let q = par add x 0 - add y 0 - let q =(add x 0, add y 0) - let r = (x,y) - printCharTuple putc r // this is okay - putnl () - //printCharTuple putc q // this causes type error - putnl () - -/* -###### Testing par-tuple -stack exec sslc -- tests/par-tuple.ssl > out/par-tuple.c -TypeError (ErrorMsg "Ill-typed expression. Expected Type Pair2 [Type Int32 [],Type Int32 []], but got Type (,) [Type Int32 [],Type Int32 []]") -###### FAILED -*/ \ No newline at end of file diff --git a/regression-tests/tests/1opt-par6.ssl.failing b/regression-tests/tests/1opt-par6.ssl.failing new file mode 100644 index 00000000..d14df711 --- /dev/null +++ b/regression-tests/tests/1opt-par6.ssl.failing @@ -0,0 +1,16 @@ +// once non-application expressions are allowed inside a par, +// this test should pass. + +// check that optimize par pass does NOT rewrite par expressions +// that have at least one non-instantaneous argument + +add a b = a + b +main cin cout = + let q = par wait cout // NOT instantaneous + wait cout // NOT instantaneous + wait cout // NOT instantaneous + // ^should NOT rewrite q as a tuple + after 1, cout <- 5 + 48 // Should print 5 + wait cout + after 1, cout <- 10 + wait cout diff --git a/regression-tests/tests/1opt-par7.failing b/regression-tests/tests/1opt-par7.failing new file mode 100644 index 00000000..5b1662b4 --- /dev/null +++ b/regression-tests/tests/1opt-par7.failing @@ -0,0 +1,41 @@ +// once codegen supports return value of tuples, +// this test should pass + +type Pair2 a b + Pair2 a b + +add a b = a + b + +printCharTuple putc p = + match p + (x,y) = putc x + putc 32 + putc y + +main cin cout = + let putc c = after 1, cout <- c + wait cout + let putnl _ = putc 10 + + let x = 66 + let y = 67 + + // tuple with arguments evaluated sequentially + let w = (add x 0, add y 0) + // let's print it out + printCharTuple putc w // this is okay + putnl () + + // tuple with arguments already evaluated + let r = (x,y) + // let's print it out + printCharTuple putc r // this is okay + putnl () + + // code below causes segmentation fault + // par with arguments evaluated at the same time + let q = par add x 0 + add y 0 + // let's print it out + printCharTuple putc q // this is okay + putnl () \ No newline at end of file diff --git a/regression-tests/tests/1opt-par7.out b/regression-tests/tests/1opt-par7.out new file mode 100644 index 00000000..e7dda80d --- /dev/null +++ b/regression-tests/tests/1opt-par7.out @@ -0,0 +1,3 @@ +B C +B C +B C diff --git a/regression-tests/tests/1opt-par7.ssl.fail b/regression-tests/tests/1opt-par7.ssl.fail deleted file mode 100644 index f8bc7414..00000000 --- a/regression-tests/tests/1opt-par7.ssl.fail +++ /dev/null @@ -1,7 +0,0 @@ -add a b = a + b -main cin cout = - let q = par wait cout - wait cout - wait cout - () -