[GHC] #13614: Rewrite rules not applied exhaustively when simplifying from plugin

GHC ghc-devs at haskell.org
Wed Apr 26 17:59:13 UTC 2017


#13614: Rewrite rules not applied exhaustively when simplifying from plugin
-------------------------------------+-------------------------------------
        Reporter:  nomeata           |                Owner:  (none)
            Type:  bug               |               Status:  new
        Priority:  normal            |            Milestone:
       Component:  GHC API           |              Version:  8.1
      Resolution:                    |             Keywords:
Operating System:  Unknown/Multiple  |         Architecture:
                                     |  Unknown/Multiple
 Type of failure:  None/Unknown      |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:                    |  Differential Rev(s):
       Wiki Page:                    |
-------------------------------------+-------------------------------------
Changes (by nomeata):

 * status:  closed => new
 * resolution:  worksforme =>


Comment:

 Ok, so this works fine for locally defined things. But I run into the same
 (or a similar) problem where rules attached to globally defined things do
 not fire.

 Here is my test file (with commented-out rule):
 {{{
 {-# OPTIONS_GHC -O -fplugin TestPlugin #-}
 module Test where
 import GHC.Base (foldr)
 {- # RULES "foldr/id_mine" GHC.Base.foldr (:) [] = id #-}
 test :: [a] -> [a]
 test xs = map id xs
 }}}
 and here the plugin, with the fix from earlier:
 {{{
 module TestPlugin where

 import System.Exit
 import Control.Monad

 import GhcPlugins
 import Simplify
 import CoreStats
 import SimplMonad
 import FamInstEnv
 import SimplEnv
 import OccurAnal

 -- Plugin boiler plate

 plugin :: Plugin
 plugin = defaultPlugin { installCoreToDos = install }

 install :: [CommandLineOption] -> [CoreToDo] -> CoreM [CoreToDo]
 install _ (simpl:xs) = return $ simpl : pass : xs
   where pass = CoreDoPluginPass "Test" testPass

 -- The plugin

 testPass :: ModGuts -> CoreM ModGuts
 testPass guts = do
     let [expr] = [ e | NonRec v e <- mg_binds guts
                      , occNameString (occName v) == "test" ]
     simplified_expression <- simplify guts expr

     putMsg $
         text "Test" $$
         nest 4 (hang (text "Before" <> colon) 4 (ppr expr)) $$
         nest 4 (hang (text "After" <> colon) 4 (ppr
 simplified_expression))

     liftIO $ exitFailure

 -- A simplifier

 simplify :: ModGuts -> CoreExpr -> CoreM CoreExpr
 simplify guts expr = do
     dflags <- getDynFlags

     let dflags' = dflags { ufVeryAggressive = True }

     us <- liftIO $ mkSplitUniqSupply 's'
     let sz = exprSize expr

     rule_base <- getRuleBase
     vis_orphs <- getVisibleOrphanMods
     let rule_base2 = extendRuleBaseList rule_base (mg_rules guts)
     let rule_env = RuleEnv rule_base2 vis_orphs
     let top_lvls = bindersOfBinds (mg_binds guts)


     (expr', _) <- liftIO $ initSmpl dflags' rule_env emptyFamInstEnvs us
 sz $ do
         simplExpr (simplEnv top_lvls 1) (occurAnalyseExpr expr)
     return expr'



 simplEnv :: [Var] -> Int -> SimplEnv
 simplEnv vars p = env1
   where
     env1 = addNewInScopeIds env0 vars
     env0 =  mkSimplEnv $ SimplMode { sm_names = ["Test"]
                                    , sm_phase = Phase p
                                    , sm_rules = True
                                    , sm_inline = True
                                    , sm_eta_expand = True
                                    , sm_case_case = True }
 }}}

 If I run this I get:
 {{{
 $ ghc-head -O  -dynamic-too -package ghc Test.hs -fforce-recomp
 [1 of 2] Compiling TestPlugin       ( TestPlugin.hs, TestPlugin.o )
 [2 of 2] Compiling Test             ( Test.hs, Test.o )
 Test
     Before:
         \ (@ a) (xs :: [a]) ->
           GHC.Base.build
             @ a
             (\ (@ b1)
                (c [OS=OneShot] :: a -> b1 -> b1)
                (n [OS=OneShot] :: b1) ->
                GHC.Base.foldr @ a @ b1 c n xs)
     After:
         \ (@ a) (xs :: [a]) ->
           GHC.Base.foldr @ a @ [a] (GHC.Types.: @ a) (GHC.Types.[] @ a) xs
 }}}

 Note that `GHC.Base.foldr` is still there in the `After:`: expression,
 despite the `foldr/id` rule in `GHC.Base`, which should simplify this
 code!

 If I add that rule to my module (as hinted at above), it does fire:
 {{{
 $ ghc-head -O  -dynamic-too -package ghc Test.hs -fforce-recomp
 [1 of 2] Compiling TestPlugin       ( TestPlugin.hs, TestPlugin.o )
 [2 of 2] Compiling Test             ( Test.hs, Test.o )
 Test
     Before:
         \ (@ a) (xs :: [a]) ->
           GHC.Base.build
             @ a
             (\ (@ b1)
                (c [OS=OneShot] :: a -> b1 -> b1)
                (n [OS=OneShot] :: b1) ->
                GHC.Base.foldr @ a @ b1 c n xs)
     After: \ (@ a) (xs :: [a]) -> xs
 }}}

--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/13614#comment:5>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list