Fixed bug in dead code elimination

Now producer name introduction introduces new variables
for fetch-binding left-hand sides.

This change fixes a bug in DVE and DDE where these transformations
did not handle fetch-bindings correctly.
This commit is contained in:
Anabra 2018-11-25 15:14:29 +01:00
parent 8639a9acc4
commit adaefab92f
5 changed files with 51 additions and 0 deletions

1
.gitignore vendored
View File

@ -23,3 +23,4 @@ output/
*.ibc
*.agdai
.output
.grin-output/

View File

@ -48,11 +48,34 @@ Unspecified location:
- refactor dead code elimination so that is uses unspec loc for the types of #undefined
Producer name introduction:
- PNI introduces new variables at each producer site
- after PNI, the created-by analysis can be run on the resulting code
- PNI also introduces new variables for bindings with a fetch left-hand side
- this makes DVE and DDE simpler to implement (*)
- applying PNI multiple times can result in a lot of redundant code
- we can eliminate this redundancy by applying Copy Progagation & Simple Dead Variable Elimination
- but, we hae to exclude these two transformation from the optimizing pipeline
- and run them manually each time a transformation changes the AST
(* DDE and DVE simplification):
- DDE needs to remove dead fields from node patterns
- for this, it needs liveness and producer information
- for bindings of form: (CInt n) <- fetch p
- DDE would have to look through the pointer p
- derefernce it, and collect the information for the variable pointed at by it
- using this information, it could remove the dead fields of the pattern
- instead, we make sure that all fetch-bindings can only have variable patterns, so that producer information can flow more easily
- DVE needs to remove dead bindings and replace all occurences of deleted variables with #undefineds
- fetch accepts only names as its first parameter, so we cannot replace them with #undefined
(since #undefined is a value)
- this is not a problem, since DVE can remove such bindings altogether IF the pattern is only a variable
- however, if have a binding of form: (CInt n) <- fetch p
- DVE would have to collect all names in the node pattern
- and replace all those as well
- instead, we make sure that all fetch-bindings can only have variable patterns, so that replacing dead variables is simpler
Avoid looping optimization:
- use taboo sets of previous ASTs
- let e' be the resulting AST after running all possible optimizations

View File

@ -54,6 +54,11 @@ deadVariableElimination :: LVAResult -> TypeEnv -> Exp -> Either String Exp
deadVariableElimination lvaResult tyEnv
= runTrf . (deleteDeadBindings lvaResult tyEnv >=> replaceDeletedVars tyEnv)
{- NOTE: Fetches do not have to be handled separately,
since producer name introduction guarantees
that all bindings with a fetch LHS will have a Var PAT
(handled by the last case in alg).
-}
deleteDeadBindings :: LVAResult -> TypeEnv -> Exp -> Trf Exp
deleteDeadBindings lvaResult tyEnv = cataM alg where
alg :: ExpF Exp -> Trf Exp

View File

@ -37,6 +37,8 @@ producerNameIntroduction e = evalNameM e . cata alg $ e where
SReturnF x@VarTagNode{} -> bindVal SReturn x
SReturnF x@ConstTagNode{} -> bindVal SReturn x
SReturnF x@Undefined{} -> bindVal SReturn x
-- This is not a producer, but helps in the propagation of producer info (makes DDE simpler)
SFetchF p -> bindFetch p
expf -> fmap embed . sequence $ expf
-- binds a Val (usually a node) to a name, then puts it into some context
@ -44,3 +46,9 @@ producerNameIntroduction e = evalNameM e . cata alg $ e where
bindVal context val = do
nodeVar <- fmap Var newNodeName
return $ SBlock $ EBind (SReturn val) nodeVar (context nodeVar)
-- bind the lhs of a fetch-binding to a variable
bindFetch :: Name -> NameM Exp
bindFetch p = do
fetchResult <- fmap Var newNodeName
return $ SBlock $ EBind (SFetch p) fetchResult (SReturn fetchResult)

View File

@ -33,6 +33,20 @@ spec = do
|]
(pni before) `sameAs` after
it "fetch" $ do
let before = [prog|
grinMain p =
(CInt n) <- fetch p
pure n
|]
let after = [prog|
grinMain p =
v.0 <- fetch p
(CInt n) <- pure v.0
pure n
|]
(pni before) `sameAs` after
it "update" $ do
let before = [prog|
grinMain =