Simon Peyton Jones pushed to branch wip/spj-try-opt-coercion at Glasgow Haskell Compiler / GHC

Commits:

9 changed files:

Changes:

  • compiler/GHC/Core/Map/Expr.hs
    ... ... @@ -26,6 +26,7 @@ import GHC.Prelude
    26 26
     import GHC.Data.TrieMap
    
    27 27
     import GHC.Core.Map.Type
    
    28 28
     import GHC.Core
    
    29
    +import GHC.Core.Coercion( coercionRKind )
    
    29 30
     import GHC.Core.Type
    
    30 31
     import GHC.Types.Tickish
    
    31 32
     import GHC.Types.Var
    
    ... ... @@ -150,13 +151,16 @@ instance Eq (DeBruijn CoreExpr) where
    150 151
     
    
    151 152
     eqDeBruijnExpr :: DeBruijn CoreExpr -> DeBruijn CoreExpr -> Bool
    
    152 153
     eqDeBruijnExpr (D env1 e1) (D env2 e2) = go e1 e2 where
    
    153
    -    go (Var v1) (Var v2)             = eqDeBruijnVar (D env1 v1) (D env2 v2)
    
    154
    -    go (Lit lit1)    (Lit lit2)      = lit1 == lit2
    
    155
    -    go (Type t1)    (Type t2)        = eqDeBruijnType (D env1 t1) (D env2 t2)
    
    156
    -    -- See Note [Alpha-equality for Coercion arguments]
    
    157
    -    go (Coercion {}) (Coercion {}) = True
    
    158
    -    go (Cast e1 co1) (Cast e2 co2) = D env1 co1 == D env2 co2 && go e1 e2
    
    159
    -    go (App f1 a1)   (App f2 a2)   = go f1 f2 && go a1 a2
    
    154
    +    go (Var v1)       (Var v2)       = eqDeBruijnVar (D env1 v1) (D env2 v2)
    
    155
    +    go (Lit lit1)     (Lit lit2)     = lit1 == lit2
    
    156
    +    go (Type t1)      (Type t2)      = eqDeBruijnType     (D env1 t1)  (D env2 t2)
    
    157
    +    go (Coercion co1) (Coercion co2) = eqDeBruijnCoercion (D env1 co1) (D env2 co2)
    
    158
    +    go (Cast e1 co1)  (Cast e2 co2)  = go e1 e2 && eqDeBruijnType (D env1 (coercionRKind co1))
    
    159
    +                                                                  (D env2 (coercionRKind co2))
    
    160
    +    go (App f1 a1)    (App f2 a2)
    
    161
    +      | isCoArg a1, isCoArg a2     = go f1 f2
    
    162
    +      | otherwise                  = go f1 f2 && go a1 a2
    
    163
    +      -- isCoArg: see Note [Coercions in expressions]
    
    160 164
         go (Tick n1 e1) (Tick n2 e2)
    
    161 165
           =  eqDeBruijnTickish (D env1 n1) (D env2 n2)
    
    162 166
           && go e1 e2
    
    ... ... @@ -204,12 +208,17 @@ eqDeBruijnTickish (D env1 t1) (D env2 t2) = go t1 t2 where
    204 208
     eqCoreExpr :: CoreExpr -> CoreExpr -> Bool
    
    205 209
     eqCoreExpr e1 e2 = eqDeBruijnExpr (deBruijnize e1) (deBruijnize e2)
    
    206 210
     
    
    207
    -{- Note [Alpha-equality for Coercion arguments]
    
    208
    -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    209
    -The 'Coercion' constructor only appears in argument positions, and so, if the
    
    210
    -functions are equal, then the arguments must have equal types. Because the
    
    211
    -comparison for coercions (correctly) checks only their types, checking for
    
    212
    -alpha-equality of the coercions is redundant.
    
    211
    +{- Note [Coercions in expressions]
    
    212
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    213
    +When a coercion appears in an expression, we mainly use `eqDeBruijnCoercion`
    
    214
    +(see Note [Equality for coercions] in GHC.Core.Map.Type).  But we can optimise
    
    215
    +  * Applications: f1 (CO: co1)  =  f2 (CO: co2)
    
    216
    +    If the two functions are equal their argument coercions must have equal
    
    217
    +    types, so no need to compare the coercions at all.
    
    218
    +
    
    219
    +  * Casts:  e1 |> co1   =    e2 |> co2
    
    220
    +    If e1 and e2 are equal, the coercionLKinds of the coercions are equal;
    
    221
    +    so we only need to compare the coercionRKinds
    
    213 222
     -}
    
    214 223
     
    
    215 224
     {- Note [Alpha-equality for let-bindings]
    

  • compiler/GHC/Core/Map/Type.hs
    ... ... @@ -20,6 +20,7 @@ module GHC.Core.Map.Type (
    20 20
        TypeMapG, CoercionMapG,
    
    21 21
     
    
    22 22
        DeBruijn(..), deBruijnize, eqDeBruijnType, eqDeBruijnVar,
    
    23
    +   eqDeBruijnCoercion,
    
    23 24
     
    
    24 25
        BndrMap, xtBndr, lkBndr,
    
    25 26
        VarMap, xtVar, lkVar, lkDFreeVar, xtDFreeVar,
    
    ... ... @@ -78,9 +79,14 @@ import Control.Monad ( (>=>) )
    78 79
     ************************************************************************
    
    79 80
     -}
    
    80 81
     
    
    81
    --- We should really never care about the contents of a coercion. Instead,
    
    82
    --- just look up the coercion's type.
    
    82
    +{- Note [Equality for coercions]
    
    83
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    84
    +A coercion is a proof, and any one proof is as good as any other.
    
    85
    +So to compare coercions we just compare their types.
    
    86
    +-}
    
    87
    +
    
    83 88
     newtype CoercionMap a = CoercionMap (CoercionMapG a)
    
    89
    +  -- See [Equality for coercions]
    
    84 90
     
    
    85 91
     -- TODO(22292): derive
    
    86 92
     instance Functor CoercionMap where
    
    ... ... @@ -98,6 +104,9 @@ instance TrieMap CoercionMap where
    98 104
     
    
    99 105
     type CoercionMapG = GenMap CoercionMapX
    
    100 106
     newtype CoercionMapX a = CoercionMapX (TypeMapX a)
    
    107
    +-- CoercionMapX key point: two coercions are considered equal if
    
    108
    +-- their coercionTypes are the same; so we just defer to TypeMap
    
    109
    +
    
    101 110
     
    
    102 111
     -- TODO(22292): derive
    
    103 112
     instance Functor CoercionMapX where
    
    ... ... @@ -113,11 +122,6 @@ instance TrieMap CoercionMapX where
    113 122
       filterTM f (CoercionMapX core_tm) = CoercionMapX (filterTM f core_tm)
    
    114 123
       mapMaybeTM f (CoercionMapX core_tm) = CoercionMapX (mapMaybeTM f core_tm)
    
    115 124
     
    
    116
    -instance Eq (DeBruijn Coercion) where
    
    117
    -  D env1 co1 == D env2 co2
    
    118
    -    = D env1 (coercionType co1) ==
    
    119
    -      D env2 (coercionType co2)
    
    120
    -
    
    121 125
     lkC :: DeBruijn Coercion -> CoercionMapX a -> Maybe a
    
    122 126
     lkC (D env co) (CoercionMapX core_tm) = lkT (D env $ coercionType co)
    
    123 127
                                             core_tm
    
    ... ... @@ -126,6 +130,16 @@ xtC :: DeBruijn Coercion -> XT a -> CoercionMapX a -> CoercionMapX a
    126 130
     xtC (D env co) f (CoercionMapX m)
    
    127 131
       = CoercionMapX (xtT (D env $ coercionType co) f m)
    
    128 132
     
    
    133
    +-- This equality instance is needed for the equality test in leaf compression;
    
    134
    +-- see GenMap and Note [Compressed TrieMap] in GHC.Data.TrieMap
    
    135
    +instance Eq (DeBruijn Coercion) where
    
    136
    +  (==) = eqDeBruijnCoercion
    
    137
    +
    
    138
    +eqDeBruijnCoercion :: DeBruijn Coercion -> DeBruijn Coercion -> Bool
    
    139
    +eqDeBruijnCoercion (D env1 co1) (D env2 co2)
    
    140
    +  = eqDeBruijnType (D env1 (coercionType co1)) (D env2 (coercionType co2))
    
    141
    +
    
    142
    +
    
    129 143
     {-
    
    130 144
     ************************************************************************
    
    131 145
     *                                                                      *
    
    ... ... @@ -139,9 +153,7 @@ xtC (D env co) f (CoercionMapX m)
    139 153
     -- but it is strictly internal to this module.  If you are including a 'TypeMap'
    
    140 154
     -- inside another 'TrieMap', this is the type you want. Note that this
    
    141 155
     -- lookup does not do a kind-check. Thus, all keys in this map must have
    
    142
    --- the same kind. Also note that this map respects the distinction between
    
    143
    --- @Type@ and @Constraint@, despite the fact that they are equivalent type
    
    144
    --- synonyms in Core.
    
    156
    +-- the same kind.
    
    145 157
     type TypeMapG = GenMap TypeMapX
    
    146 158
     
    
    147 159
     -- | @TypeMapX a@ is the base map from @DeBruijn Type@ to @a@, but without the
    
    ... ... @@ -191,9 +203,6 @@ instance TrieMap TypeMapX where
    191 203
        filterTM = filterT
    
    192 204
        mapMaybeTM = mpT
    
    193 205
     
    
    194
    -instance Eq (DeBruijn Type) where
    
    195
    -  (==) = eqDeBruijnType
    
    196
    -
    
    197 206
     -- | An equality relation between two 'Type's (known below as @t1 :: k2@
    
    198 207
     -- and @t2 :: k2@)
    
    199 208
     data TypeEquality = TNEQ -- ^ @t1 /= t2@
    
    ... ... @@ -219,7 +228,7 @@ eqDeBruijnType env_t1@(D env1 t1) env_t2@(D env2 t2) =
    219 228
     
    
    220 229
         liftEquality :: Bool -> TypeEquality
    
    221 230
         liftEquality False = TNEQ
    
    222
    -    liftEquality _     = TEQ
    
    231
    +    liftEquality True  = TEQ
    
    223 232
     
    
    224 233
         hasCast :: TypeEquality -> TypeEquality
    
    225 234
         hasCast TEQ = TEQX
    
    ... ... @@ -272,7 +281,7 @@ eqDeBruijnType env_t1@(D env1 t1) env_t2@(D env2 t2) =
    272 281
                      go (D (extendCME env tv) ty) (D (extendCME env' tv') ty')
    
    273 282
               (CoercionTy {}, CoercionTy {})
    
    274 283
                   -> TEQ
    
    275
    -          _ -> TNEQ
    
    284
    +          _   -> TNEQ
    
    276 285
     
    
    277 286
         -- These bangs make 'gos' strict in the CMEnv, which in turn
    
    278 287
         -- keeps the CMEnv unboxed across the go/gos mutual recursion
    
    ... ... @@ -282,9 +291,6 @@ eqDeBruijnType env_t1@(D env1 t1) env_t2@(D env2 t2) =
    282 291
                                           gos e1 e2 tys1 tys2
    
    283 292
         gos _  _  _          _          = TNEQ
    
    284 293
     
    
    285
    -instance Eq (DeBruijn Var) where
    
    286
    -  (==) = eqDeBruijnVar
    
    287
    -
    
    288 294
     eqDeBruijnVar :: DeBruijn Var -> DeBruijn Var -> Bool
    
    289 295
     eqDeBruijnVar (D env1 v1) (D env2 v2) =
    
    290 296
         case (lookupCME env1 v1, lookupCME env2 v2) of
    
    ... ... @@ -292,6 +298,14 @@ eqDeBruijnVar (D env1 v1) (D env2 v2) =
    292 298
             (Nothing, Nothing) -> v1 == v2
    
    293 299
             _ -> False
    
    294 300
     
    
    301
    +-- This equality instance is needed for the equality test in leaf compression;
    
    302
    +-- see GenMap and Note [Compressed TrieMap] in GHC.Data.TrieMap
    
    303
    +instance Eq (DeBruijn Type) where
    
    304
    +  (==) = eqDeBruijnType
    
    305
    +
    
    306
    +instance Eq (DeBruijn Var) where
    
    307
    +  (==) = eqDeBruijnVar
    
    308
    +
    
    295 309
     instance {-# OVERLAPPING #-}
    
    296 310
              Outputable a => Outputable (TypeMapG a) where
    
    297 311
       ppr m = text "TypeMap elts" <+> ppr (foldTM (:) m [])
    
    ... ... @@ -488,6 +502,7 @@ instance TrieMap LooseTypeMap where
    488 502
       filterTM f (LooseTypeMap m) = LooseTypeMap (filterTM f m)
    
    489 503
       mapMaybeTM f (LooseTypeMap m) = LooseTypeMap (mapMaybeTM f m)
    
    490 504
     
    
    505
    +
    
    491 506
     {-
    
    492 507
     ************************************************************************
    
    493 508
     *                                                                      *
    

  • compiler/GHC/Core/Opt/CSE.hs
    ... ... @@ -450,7 +450,7 @@ cse_bind toplevel env_rhs env_body (in_id, in_rhs) out_id
    450 450
       | otherwise
    
    451 451
       = (env_body', (out_id'', out_rhs))
    
    452 452
       where
    
    453
    -    (env_body', out_id') = extendCSEnvWithBinding env_body  in_id out_id out_rhs cse_done
    
    453
    +    (env_body', out_id') = extendCSEnvWithBinding env_body in_id out_id out_rhs cse_done
    
    454 454
         (cse_done, out_rhs)  = try_for_cse env_rhs in_rhs
    
    455 455
         out_id'' | cse_done  = zapStableUnfolding $
    
    456 456
                                delayInlining toplevel out_id'
    

  • compiler/GHC/Core/Opt/Simplify/Env.hs
    ... ... @@ -422,11 +422,12 @@ data SimplFloats
    422 422
           }
    
    423 423
     
    
    424 424
     instance Outputable SimplFloats where
    
    425
    -  ppr (SimplFloats { sfLetFloats = lf, sfJoinFloats = jf, sfInScope = is })
    
    425
    +  ppr (SimplFloats { sfLetFloats = lf, sfJoinFloats = jf, sfInScope = _is })
    
    426 426
         = text "SimplFloats"
    
    427 427
           <+> braces (vcat [ text "lets: " <+> ppr lf
    
    428 428
                            , text "joins:" <+> ppr jf
    
    429
    -                       , text "in_scope:" <+> ppr is ])
    
    429
    +--                       , text "in_scope:" <+> ppr _is
    
    430
    +                       ])
    
    430 431
     
    
    431 432
     emptyFloats :: SimplEnv -> SimplFloats
    
    432 433
     emptyFloats env
    

  • compiler/GHC/Core/TyCo/Rep.hs
    ... ... @@ -2098,8 +2098,9 @@ coercionIsSmall :: Coercion -> Bool
    2098 2098
     -- This function is called inside `exprIsTrivial` so it needs to be
    
    2099 2099
     -- pretty efficient.  It should return False quickly on a big coercion;
    
    2100 2100
     -- it should /not/ traverse the big coercion!
    
    2101
    +-- The literal constant 40# is pretty arbitrary
    
    2101 2102
     coercionIsSmall co
    
    2102
    -  = not (isTrue# ((coercion_is_small co 100#) <# 0#))
    
    2103
    +  = not (isTrue# ((coercion_is_small co 40#) <# 0#))
    
    2103 2104
     
    
    2104 2105
     coercion_is_small :: Coercion -> Int# -> Int#
    
    2105 2106
     coercion_is_small co n = go co n
    

  • compiler/GHC/Data/TrieMap.hs
    ... ... @@ -359,7 +359,6 @@ mpList f (LM { lm_nil = mnil, lm_cons = mcons })
    359 359
     
    
    360 360
     Note [Compressed TrieMap]
    
    361 361
     ~~~~~~~~~~~~~~~~~~~~~~~~~
    
    362
    -
    
    363 362
     The GenMap constructor augments TrieMaps with leaf compression.  This helps
    
    364 363
     solve the performance problem detailed in #9960: suppose we have a handful
    
    365 364
     H of entries in a TrieMap, each with a very large key, size K. If you fold over
    

  • compiler/GHC/Iface/Make.hs
    ... ... @@ -199,7 +199,11 @@ updateDecl decls m_stg_infos m_cmm_infos
    199 199
                                     m_cmm_infos
    
    200 200
         tag_sigs = fromMaybe mempty m_stg_infos
    
    201 201
     
    
    202
    -    update_decl (IfaceId nm ty details infos)
    
    202
    +    update_decl decl@(IfaceId nm ty details infos)
    
    203
    +      | IfCoVarId <- details
    
    204
    +      = decl -- Coercions can appear at top level in interface files
    
    205
    +             -- but we generate no code for them and they have no LFInfo
    
    206
    +
    
    203 207
           | let not_caffy = elemNameSet nm non_cafs
    
    204 208
           , let mb_lf_info = lookupNameEnv lf_infos nm
    
    205 209
           , let sig = lookupNameEnv tag_sigs nm
    

  • compiler/GHC/IfaceToCore.hs
    ... ... @@ -1698,12 +1698,21 @@ tcIfaceExpr (IfaceCase scrut case_bndr alts) = do
    1698 1698
          return (Case scrut' case_bndr' (coreAltsType alts') alts')
    
    1699 1699
     
    
    1700 1700
     tcIfaceExpr (IfaceLet (IfaceNonRec (IfLetBndr fs ty info ji) rhs) body)
    
    1701
    +  | IfaceCo co <- rhs
    
    1702
    +  = -- For CoVars we ignore `info` and `ji`
    
    1703
    +    do  { name    <- newIfaceName (mkVarOccFS (ifLclNameFS fs))
    
    1704
    +        ; ty'     <- tcIfaceType ty
    
    1705
    +        ; let covar = mkLocalCoVar name ty'
    
    1706
    +        ; co'   <- tcIfaceCo co
    
    1707
    +        ; body' <- extendIfaceIdEnv [covar] (tcIfaceExpr body)
    
    1708
    +        ; return (Let (NonRec covar (Coercion co'))  body') }
    
    1709
    +  | otherwise
    
    1701 1710
       = do  { name    <- newIfaceName (mkVarOccFS (ifLclNameFS fs))
    
    1702 1711
             ; ty'     <- tcIfaceType ty
    
    1703 1712
             ; id_info <- tcIdInfo False {- Don't ignore prags; we are inside one! -}
    
    1704 1713
                                   NotTopLevel name ty' info
    
    1705 1714
             ; let id = mkLocalIdWithInfo name ManyTy ty' id_info
    
    1706
    -                     `asJoinId_maybe` ji
    
    1715
    +                   `asJoinId_maybe` ji
    
    1707 1716
             ; rhs' <- tcIfaceExpr rhs
    
    1708 1717
             ; body' <- extendIfaceIdEnv [id] (tcIfaceExpr body)
    
    1709 1718
             ; return (Let (NonRec id rhs') body') }
    

  • compiler/GHC/Types/Id.hs
    ... ... @@ -329,8 +329,8 @@ mkLocalIdOrCoVar name w ty
    329 329
       | isCoVarType ty = mkLocalCoVar name   ty
    
    330 330
       | otherwise      = mkLocalId    name w ty
    
    331 331
     
    
    332
    -    -- proper ids only; no covars!
    
    333 332
     mkLocalIdWithInfo :: HasDebugCallStack => Name -> Mult -> Type -> IdInfo -> Id
    
    333
    +-- Used for proper ids only; no covars!
    
    334 334
     mkLocalIdWithInfo name w ty info =
    
    335 335
       Var.mkLocalVar VanillaId name w (assert (not (isCoVarType ty)) ty) info
    
    336 336
             -- Note [Free type variables]