[Git][ghc/ghc][wip/spj-unf-size] Bale out altogether on very wide cases

Simon Peyton Jones (@simonpj) gitlab at gitlab.haskell.org
Mon Oct 30 12:18:28 UTC 2023



Simon Peyton Jones pushed to branch wip/spj-unf-size at Glasgow Haskell Compiler / GHC


Commits:
e0cdbe65 by Simon Peyton Jones at 2023-10-30T12:18:05+00:00
Bale out altogether on very wide cases

- - - - -


1 changed file:

- compiler/GHC/Core/Unfold.hs


Changes:

=====================================
compiler/GHC/Core/Unfold.hs
=====================================
@@ -156,7 +156,7 @@ data UnfoldingOpts = UnfoldingOpts
       -- ^ Penalize depth with 1/x
 
    , exprTreeCaseWidth :: !Int
-      -- ^ Don't make ExprTrees with a case width greater than this
+      -- ^ Bale out entirely with a case width greater than this
 
    , exprTreeCaseDepth :: !Int
       -- ^ Don't make ExprTrees with a case depth greater than this
@@ -198,7 +198,11 @@ defaultUnfoldingOpts = UnfoldingOpts
       -- Don't filter inlining decision reports
    , unfoldingReportPrefix = Nothing
 
-   , exprTreeCaseWidth = 4
+     -- Bale out at exprTreeCaseWidth
+     -- See Note [Bale out on very wide case expressions]
+   , exprTreeCaseWidth = 20
+
+     -- Don't record CaseOf beyond exprTreeCaseDepth
    , exprTreeCaseDepth = 4
    }
 
@@ -602,23 +606,20 @@ exprTree opts args expr
 
     -- Record a CaseOf
     go_case remaining_case_depth vs@(avs,lvs) scrut b alts
+      | alts `lengthExceeds` max_width
+      = Nothing   -- See Note [Bale out on very wide case expressions]
+
       | Just v <- interestingVarScrut vs scrut
       = go remaining_case_depth vs scrut `et_add`
-        (if   record_case
+        (if   remaining_case_depth > 0
          then do { alts' <- mapM (alt_alt_tree v) alts
                  ; etCaseOf bOMB_OUT_SIZE v b alts' }
          else Just (etScrutOf v caseElimDiscount) `et_add`
               -- When this scrutinee has structure, we expect to eliminate the case
-              go_alts rcd1 vs b alts)
+              go_alts remaining_case_depth vs b alts)
       where
         rcd1 = remaining_case_depth - 1
 
-        record_case :: Bool
-        -- True  <=> record CaseOf: case is not too deep, nor too wide
-        -- False <=> record ScrutOf
-        record_case = (remaining_case_depth > 0) &&
-                      (alts `lengthAtMost` max_width)
-
         alt_alt_tree :: Id -> Alt Var -> Maybe AltTree
         alt_alt_tree v (Alt con bs rhs)
           = do { rhs <- go rcd1 (add_alt_bndrs v val_bs) rhs
@@ -635,17 +636,18 @@ exprTree opts args expr
     go_case rcd vs scrut b alts    -- alts is non-empty
       = caseSize scrut alts     `metAddN`   -- A bit odd that this is only in one branch
         (altSize * length alts) `metAddN`
-            -- IMPORTANT: charge `altSize` for each alternative, else we
-            -- find that giant case nests are treated as practically free
-            -- A good example is Foreign.C.Error.errnoToIOError
         go rcd vs scrut `et_add` go_alts (rcd-1) vs b alts
 
     go_alts :: Int -> ETVars -> Id -> [CoreAlt] -> Maybe ExprTree
-    -- Add up the sizes of all RHSs
+    -- Add up the sizes of all RHSs.
+    -- IMPORTANT: charge `altSize` for each alternative, else we
+    -- find that giant case nests are treated as practically free
+    -- A good example is Foreign.C.Error.errnoToIOError
     go_alts rcd vs b alts = foldr1 et_add_alt (map alt_expr_tree alts)
       where
         alt_expr_tree :: Alt Var -> Maybe ExprTree
-        alt_expr_tree (Alt _con bs rhs) = go rcd (vs `add_lvs` (b:bs)) rhs
+        alt_expr_tree (Alt _con bs rhs) = altSize `metAddN`
+                                          go rcd (vs `add_lvs` (b:bs)) rhs
             -- Don't charge for bndrs, so that wrappers look cheap
             -- (See comments about wrappers with Case)
             -- Don't forget to add the case binder, b, to lvs.
@@ -768,7 +770,7 @@ classOpSize opts vs fn val_args voids
            -- If the class op is scrutinising a lambda bound dictionary then
            -- give it a discount, to encourage the inlining of this function
            -- The actual discount is rather arbitrarily chosen
-  | otherwise
+n  | otherwise
   = exprTreeN (vanillaCallSize (length val_args) voids)
 
 funSize :: UnfoldingOpts -> ETVars -> Id -> Int -> Int -> ExprTree
@@ -830,8 +832,28 @@ caseElimDiscount :: Discount
 -- Bonus for eliminating a case
 caseElimDiscount = 10
 
-{- Note [Constructor size and result discount]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+{- Note [Bale out on very wide case expressions]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+With very wide case trees (say N) we get a size N*altSize, which usually
+prevents inlining (e.g. 20*altSize = 200 currently, which is way above the
+inlining thresold of 90-ish).  Plus, we risk getting big CaseOf trees in the
+ExprTree.
+
+If we aren't going to inline it anyway, then retaining the unfolding in an
+interface file is plain silly; T5642 (involving Generics) is a good example.
+We had a very wide case whose branches mentioned dozens of data structures,
+each of which had very large types.
+
+Of course, if we apply such a function to a data constructor, we could in
+principle get a huge discount (because all but one branches fall away).
+So perhaps we could use a different setting
+* when generating an unfolding /within a module/
+* when generating an unfoldign /for an interface file/
+
+Currently we aren't doing this, but we could consider it.
+
+Note [Constructor size and result discount]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Treat a constructors application as size 10, regardless of how many
 arguments it has; we are keen to expose them (and we charge separately
 for their args).  We can't treat them as size zero, else we find that



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/e0cdbe6583a189d57ba6290253ef345ecb307c44

-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/e0cdbe6583a189d57ba6290253ef345ecb307c44
You're receiving this email because of your account on gitlab.haskell.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20231030/9821b1e8/attachment-0001.html>


More information about the ghc-commits mailing list