Andreas Klebinger pushed to branch wip/apk/unfold-dicts at Glasgow Haskell Compiler / GHC

Commits:

1 changed file:

Changes:

  • compiler/GHC/Core/Unfold.hs
    ... ... @@ -335,6 +335,10 @@ isValFun :: CoreExpr -> Bool
    335 335
     -- one top-level value lambda
    
    336 336
     isValFun (Lam b e) | isRuntimeVar b = True
    
    337 337
                        | otherwise      = isValFun e
    
    338
    +-- A tick can be code which *can* change the runtime semantics here.
    
    339
    +-- But we want to ignore it anyway. See Note [Ticks and Cast should not impact unfolding guidance]
    
    340
    +isValFun (Tick _t e)                = isValFun e
    
    341
    +isValFun (Cast e _co)               = isValFun e
    
    338 342
     isValFun _                          = False
    
    339 343
     
    
    340 344
     calcUnfoldingGuidance
    
    ... ... @@ -669,6 +673,11 @@ sizeExpr opts !bOMB_OUT_SIZE top_args expr
    669 673
               is_inline_scrut (Var v) =
    
    670 674
                 isUnliftedType (idType v)
    
    671 675
                   -- isUnliftedType is OK here: scrutinees have a fixed RuntimeRep (search for FRRCase)
    
    676
    +          -- Even if this makes the check technically wrong we want to
    
    677
    +          -- look through ticks here.
    
    678
    +          -- See Note [Ticks and Cast should not impact unfolding guidance]
    
    679
    +          is_inline_scrut (Tick _t e)  = is_inline_scrut e
    
    680
    +          is_inline_scrut (Cast e _co) = is_inline_scrut e
    
    672 681
               is_inline_scrut scrut
    
    673 682
                   | (Var f, _) <- collectArgs scrut
    
    674 683
                     = case idDetails f of
    
    ... ... @@ -709,7 +718,7 @@ sizeExpr opts !bOMB_OUT_SIZE top_args expr
    709 718
                FCallId _                     -> sizeN (callSize (length val_args) voids)
    
    710 719
                DataConWorkId dc              -> conSize    dc (length val_args)
    
    711 720
                PrimOpId op _                 -> primOpSize op (length val_args)
    
    712
    -           ClassOpId cls _               -> classOpSize opts cls top_args val_args
    
    721
    +           ClassOpId cls _               -> classOpSize opts cls top_args val_args voids
    
    713 722
                _ | fun `hasKey` buildIdKey   -> buildSize
    
    714 723
                  | fun `hasKey` augmentIdKey -> augmentSize
    
    715 724
                  | otherwise                 -> funSize opts top_args fun (length val_args) voids
    
    ... ... @@ -761,9 +770,11 @@ sizeExpr opts !bOMB_OUT_SIZE top_args expr
    761 770
         -- and typePrimRep will crash
    
    762 771
         isZeroBitId id = not (isJoinId id) && isZeroBitTy (idType id)
    
    763 772
     
    
    764
    -    isZeroBitExpr (Var id)   = isZeroBitId id
    
    765
    -    isZeroBitExpr (Tick _ e) = isZeroBitExpr e
    
    766
    -    isZeroBitExpr _          = False
    
    773
    +    -- [Ticks and Cast should not impact unfolding guidance]
    
    774
    +    isZeroBitExpr (Var id)     = isZeroBitId id
    
    775
    +    isZeroBitExpr (Tick _t e)  = isZeroBitExpr e
    
    776
    +    isZeroBitExpr (Cast e _co) = isZeroBitExpr e
    
    777
    +    isZeroBitExpr _            = False
    
    767 778
     
    
    768 779
     -- | Finds a nominal size of a string literal.
    
    769 780
     litSize :: Literal -> Int
    
    ... ... @@ -777,21 +788,29 @@ litSize _other = 0 -- Must match size of nullary constructors
    777 788
                           -- Key point: if  x |-> 4, then x must inline unconditionally
    
    778 789
                           --            (eg via case binding)
    
    779 790
     
    
    780
    -classOpSize :: UnfoldingOpts -> Class -> [Id] -> [CoreExpr] -> ExprSize
    
    791
    +classOpSize :: UnfoldingOpts -> Class -> [Id] -> [CoreExpr] -> Int -> ExprSize
    
    781 792
     -- See (IA1) in Note [Interesting arguments] in GHC.Core.Opt.Simplify.Utils
    
    782
    -classOpSize _opts _cls _top_args []
    
    793
    +classOpSize _opts _cls _top_args [] _voids
    
    783 794
       = sizeZero   -- A non-applied classop
    
    784
    -classOpSize opts cls top_args (dict_arg:other_val_args)
    
    785
    -  = SizeIs size (arg_discount dict_arg) 0
    
    795
    +classOpSize opts cls top_args (dict_arg:other_val_args) voids
    
    796
    +  = SizeIs size dict_arg_discount 0
    
    786 797
       where
    
    787
    -    size | isUnaryClass cls = 0    -- See (UCM4) in Note [Unary class magic] in GHC.Core.TyCon
    
    788
    -         | otherwise        = 20 + (10 * length other_val_args)
    
    798
    +    -- See (UCM4) in Note [Unary class magic] in GHC.Core.TyCon
    
    799
    +    op_app_size = if isUnaryClass cls then 0 else 20
    
    800
    +
    
    801
    +    -- Size penalty for applying the extracted class method to it's
    
    802
    +    -- arguments.
    
    803
    +    method_app_size = callSize (length other_val_args) voids
    
    804
    +
    
    805
    +    size = op_app_size + method_app_size
    
    789 806
     
    
    790 807
         -- If the class op is scrutinising a lambda bound dictionary then
    
    791 808
         -- give it a discount, to encourage the inlining of this function
    
    792
    -    arg_discount (Cast arg _co)                    = arg_discount arg
    
    793
    -    arg_discount (Var dict) | dict `elem` top_args = unitBag (dict, dict_discount)
    
    794
    -    arg_discount _                                 = emptyBag
    
    809
    +    dict_arg_discount = case getIdFromTrivialExpr_maybe dict_arg of
    
    810
    +      Nothing -> emptyBag
    
    811
    +      Just var
    
    812
    +        | var `elem` top_args -> unitBag (var, dict_discount)
    
    813
    +        | otherwise -> emptyBag
    
    795 814
     
    
    796 815
         -- If we have (class-op d arg1 .. argn) then it's super-good to inline
    
    797 816
         -- to expose `d`; not only can we do the dictionary selection
    
    ... ... @@ -1051,6 +1070,23 @@ In a function application (f a b)
    1051 1070
         get a saturated application)
    
    1052 1071
     
    
    1053 1072
     Code for manipulating sizes
    
    1073
    +
    
    1074
    +Note [Ticks and Cast should not impact unfolding guidance]
    
    1075
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    1076
    +We want to ignore ticks and casts when
    
    1077
    +computing unfolding guidance. The reason is simple:
    
    1078
    +
    
    1079
    +We want inlining to be robust if a user changes a type alias
    
    1080
    +to a newtype, if the code is otherwise the same.
    
    1081
    +
    
    1082
    +Similarly we want inlining to behave the same for a core expression
    
    1083
    +(<tick> e) as it does for `e`.
    
    1084
    +This is **independent** of the kind of tick we are dealing with.
    
    1085
    +Even for ticks that represent code at runtime we generally want
    
    1086
    +to inline as-if no tick is present. This way profiled code will
    
    1087
    +be closer to non-profiled code, which leads to more accurate profiles.
    
    1088
    +
    
    1089
    +So we take care to look through Cast/Ticks wherever possible.
    
    1054 1090
     -}
    
    1055 1091
     
    
    1056 1092
     -- | The size of a candidate expression for unfolding