From adaefab92f1880e0e561be1a7bb5be2e64cd0a46 Mon Sep 17 00:00:00 2001 From: Anabra Date: Sun, 25 Nov 2018 15:14:29 +0100 Subject: [PATCH] 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. --- .gitignore | 1 + dead-code-elimination.todo | 23 +++++++++++++++++++ .../Optimising/DeadVariableElimination.hs | 5 ++++ .../Simplifying/ProducerNameIntroduction.hs | 8 +++++++ .../ProducerNameIntroductionSpec.hs | 14 +++++++++++ 5 files changed, 51 insertions(+) diff --git a/.gitignore b/.gitignore index 3b2181a0..b767be68 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ output/ *.ibc *.agdai .output +.grin-output/ diff --git a/dead-code-elimination.todo b/dead-code-elimination.todo index 96fd42e9..f28fafb4 100644 --- a/dead-code-elimination.todo +++ b/dead-code-elimination.todo @@ -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 diff --git a/grin/src/Transformations/Optimising/DeadVariableElimination.hs b/grin/src/Transformations/Optimising/DeadVariableElimination.hs index 1774eb53..a3fce688 100644 --- a/grin/src/Transformations/Optimising/DeadVariableElimination.hs +++ b/grin/src/Transformations/Optimising/DeadVariableElimination.hs @@ -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 diff --git a/grin/src/Transformations/Simplifying/ProducerNameIntroduction.hs b/grin/src/Transformations/Simplifying/ProducerNameIntroduction.hs index 7d72262e..f468c6b1 100644 --- a/grin/src/Transformations/Simplifying/ProducerNameIntroduction.hs +++ b/grin/src/Transformations/Simplifying/ProducerNameIntroduction.hs @@ -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) \ No newline at end of file diff --git a/grin/test/Transformations/Simplifying/ProducerNameIntroductionSpec.hs b/grin/test/Transformations/Simplifying/ProducerNameIntroductionSpec.hs index 5088151d..54caa038 100644 --- a/grin/test/Transformations/Simplifying/ProducerNameIntroductionSpec.hs +++ b/grin/test/Transformations/Simplifying/ProducerNameIntroductionSpec.hs @@ -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 =