Adam Gundry pushed to branch wip/amg/castz at Glasgow Haskell Compiler / GHC
Commits:
-
6ef18f2a
by Adam Gundry at 2025-11-27T08:59:21+00:00
-
7bee0604
by Adam Gundry at 2025-11-27T09:00:27+00:00
-
dd8c18da
by Adam Gundry at 2025-11-27T09:14:19+00:00
-
cd9d5fb7
by Adam Gundry at 2025-11-27T09:23:59+00:00
6 changed files:
- compiler/GHC/Core.hs
- compiler/GHC/Core/Coercion.hs
- compiler/GHC/Core/Opt/Arity.hs
- compiler/GHC/Core/Opt/Simplify/Iteration.hs
- compiler/GHC/Core/SimpleOpt.hs
- compiler/GHC/HsToCore/Binds.hs
Changes:
| ... | ... | @@ -18,8 +18,7 @@ module GHC.Core ( |
| 18 | 18 | InCastCoercion,
|
| 19 | 19 | OutId, OutBind, OutExpr, OutAlt, OutArg, OutType, OutKind,
|
| 20 | 20 | OutBndr, OutVar, OutCoercion, OutCoercionR, OutTyVar, OutCoVar,
|
| 21 | - OutTyCoVar, MOutCoercion,
|
|
| 22 | - OutCastCoercion,
|
|
| 21 | + OutTyCoVar, OutCastCoercion,
|
|
| 23 | 22 | |
| 24 | 23 | -- ** 'Expr' construction
|
| 25 | 24 | mkLet, mkLets, mkLetNonRec, mkLetRec, mkLams,
|
| ... | ... | @@ -1133,7 +1132,6 @@ type OutBind = CoreBind |
| 1133 | 1132 | type OutExpr = CoreExpr
|
| 1134 | 1133 | type OutAlt = CoreAlt
|
| 1135 | 1134 | type OutArg = CoreArg
|
| 1136 | -type MOutCoercion = MCoercion
|
|
| 1137 | 1135 | type OutCastCoercion = CastCoercion
|
| 1138 | 1136 | |
| 1139 | 1137 |
| ... | ... | @@ -65,6 +65,7 @@ module GHC.Core.Coercion ( |
| 65 | 65 | mkFunResCastCo,
|
| 66 | 66 | mkFunCastCoNoFTF,
|
| 67 | 67 | applyForAllTy,
|
| 68 | + decomposeFunCastCo,
|
|
| 68 | 69 | |
| 69 | 70 | -- ** Decomposition
|
| 70 | 71 | instNewTyCon_maybe,
|
| ... | ... | @@ -459,6 +460,14 @@ decomposeFunCo co |
| 459 | 460 | Pair s1t1 s2t2 = coercionKind co
|
| 460 | 461 | all_ok = isFunTy s1t1 && isFunTy s2t2
|
| 461 | 462 | |
| 463 | + |
|
| 464 | +decomposeFunCastCo :: HasDebugCallStack => CastCoercion -> (CastCoercion, CastCoercion)
|
|
| 465 | +decomposeFunCastCo (CCoercion co) = let (_, arg_co, res_co) = decomposeFunCo co
|
|
| 466 | + in (CCoercion arg_co, CCoercion res_co)
|
|
| 467 | +decomposeFunCastCo ReflCastCo = (ReflCastCo, ReflCastCo)
|
|
| 468 | +decomposeFunCastCo (ZCoercion tyR cos) = (ZCoercion (funArgTy tyR) cos, ZCoercion (funResultTy tyR) cos)
|
|
| 469 | + |
|
| 470 | + |
|
| 462 | 471 | {- Note [Pushing a coercion into a pi-type]
|
| 463 | 472 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 464 | 473 | Suppose we have this:
|
| ... | ... | @@ -3010,18 +3010,18 @@ pushCoValArg co |
| 3010 | 3010 | Pair tyL tyR = coercionKind co
|
| 3011 | 3011 | |
| 3012 | 3012 | pushCoercionIntoLambda
|
| 3013 | - :: HasDebugCallStack => Subst -> InVar -> InExpr -> OutCastCoercion -> Maybe (OutVar, OutExpr)
|
|
| 3013 | + :: HasDebugCallStack => Subst -> InVar -> InExpr -> Type -> OutCastCoercion -> Maybe (OutVar, OutExpr)
|
|
| 3014 | 3014 | -- This implements the Push rule from the paper on coercions
|
| 3015 | 3015 | -- (\x. e) |> co
|
| 3016 | 3016 | -- ===>
|
| 3017 | 3017 | -- (\x'. e |> co')
|
| 3018 | -pushCoercionIntoLambda subst x e cco
|
|
| 3018 | +pushCoercionIntoLambda subst x e ty co
|
|
| 3019 | 3019 | | assert (not (isTyVar x) && not (isCoVar x)) True
|
| 3020 | - , CCoercion co <- cco -- AMG TODO: support for other CastCoercions
|
|
| 3021 | - , Pair s1s2 t1t2 <- coercionKind co
|
|
| 3022 | - , Just {} <- splitFunTy_maybe s1s2
|
|
| 3020 | + , let s1s2 = castCoercionLKind ty co
|
|
| 3021 | + , let t1t2 = castCoercionRKind ty co
|
|
| 3022 | + , Just (_, _, s1, _) <- splitFunTy_maybe s1s2
|
|
| 3023 | 3023 | , Just (_, w1, t1,_t2) <- splitFunTy_maybe t1t2
|
| 3024 | - , (_, co1, co2) <- decomposeFunCo co
|
|
| 3024 | + , (co1, co2) <- decomposeFunCastCo co
|
|
| 3025 | 3025 | , typeHasFixedRuntimeRep t1
|
| 3026 | 3026 | -- We can't push the coercion into the lambda if it would create
|
| 3027 | 3027 | -- a representation-polymorphic binder.
|
| ... | ... | @@ -3033,12 +3033,12 @@ pushCoercionIntoLambda subst x e cco |
| 3033 | 3033 | subst' =
|
| 3034 | 3034 | extendIdSubst (setInScope subst in_scope')
|
| 3035 | 3035 | x
|
| 3036 | - (mkCast (Var x') (mkSymCo co1))
|
|
| 3036 | + (mkCastCo (Var x') (mkSymCastCo s1 co1))
|
|
| 3037 | 3037 | -- We substitute x' for x, except we need to preserve types.
|
| 3038 | 3038 | -- The types are as follows:
|
| 3039 | 3039 | -- x :: s1, x' :: t1, co1 :: s1 ~# t1,
|
| 3040 | 3040 | -- so we extend the substitution with x |-> (x' |> sym co1).
|
| 3041 | - in Just (x', substExpr subst' e `mkCast` co2)
|
|
| 3041 | + in Just (x', substExpr subst' e `mkCastCo` co2)
|
|
| 3042 | 3042 | | otherwise
|
| 3043 | 3043 | = Nothing
|
| 3044 | 3044 |
| ... | ... | @@ -1691,20 +1691,18 @@ simplCast :: SimplEnv -> InExpr -> InCastCoercion -> SimplCont |
| 1691 | 1691 | simplCast env body co0 cont0
|
| 1692 | 1692 | = do { (tyL, co1) <- {-#SCC "simplCast-simplCoercion" #-} simplCastCoercion env (exprType body) co0
|
| 1693 | 1693 | ; cont1 <- {-#SCC "simplCast-addCoerce" #-}
|
| 1694 | - if isReflCastCo co1
|
|
| 1695 | - then return cont0 -- See Note [Optimising reflexivity]
|
|
| 1696 | - else addCoerce tyL co1 True cont0
|
|
| 1694 | + addCoerceMaybeRefl tyL co1 True cont0
|
|
| 1697 | 1695 | -- True <=> co1 is optimised
|
| 1698 | 1696 | ; {-#SCC "simplCast-simplExprF" #-} simplExprF env body cont1 }
|
| 1699 | 1697 | where
|
| 1700 | - |
|
| 1701 | - -- If the first parameter is MRefl, then simplifying revealed a
|
|
| 1702 | - -- reflexive coercion. Omit.
|
|
| 1703 | - -- TODO: probably can simplify this further now?
|
|
| 1704 | - addCoerceM :: OutType -> OutCastCoercion -> Bool -> SimplCont -> SimplM SimplCont
|
|
| 1705 | - addCoerceM _ ReflCastCo _ cont = return cont
|
|
| 1706 | - addCoerceM tyL co opt cont = addCoerce tyL co opt cont
|
|
| 1707 | - |
|
| 1698 | + -- If simplifying revealed an obviously reflexive coercion, omit it.
|
|
| 1699 | + -- See Note [Optimising reflexivity].
|
|
| 1700 | + addCoerceMaybeRefl :: OutType -> OutCastCoercion -> Bool -> SimplCont -> SimplM SimplCont
|
|
| 1701 | + addCoerceMaybeRefl tyL co opt cont
|
|
| 1702 | + | isReflCastCo co = return cont
|
|
| 1703 | + | otherwise = addCoerce tyL co opt cont
|
|
| 1704 | + |
|
| 1705 | + -- Here the coercion is known not to satisfy isReflCastCo.
|
|
| 1708 | 1706 | -- Type tyL is the coercionLKind of the coercion
|
| 1709 | 1707 | addCoerce :: OutType -> OutCastCoercion -> Bool -> SimplCont -> SimplM SimplCont
|
| 1710 | 1708 | addCoerce tyL co1 _ (CastIt { sc_co = co2, sc_cont = cont }) -- See Note [Optimising reflexivity]
|
| ... | ... | @@ -1715,7 +1713,7 @@ simplCast env body co0 cont0 |
| 1715 | 1713 | addCoerce tyL co co_is_opt (ApplyToTy { sc_arg_ty = arg_ty, sc_cont = tail })
|
| 1716 | 1714 | | Just (arg_ty', res_ty, m_co') <- pushCastCoTyArg tyL co arg_ty
|
| 1717 | 1715 | = {-#SCC "addCoerce-pushCoTyArg" #-}
|
| 1718 | - do { tail' <- addCoerceM res_ty m_co' co_is_opt tail
|
|
| 1716 | + do { tail' <- addCoerceMaybeRefl res_ty m_co' co_is_opt tail
|
|
| 1719 | 1717 | ; return (ApplyToTy { sc_arg_ty = arg_ty'
|
| 1720 | 1718 | , sc_cont = tail'
|
| 1721 | 1719 | , sc_hole_ty = tyL }) }
|
| ... | ... | @@ -1729,11 +1727,11 @@ simplCast env body co0 cont0 |
| 1729 | 1727 | , sc_dup = dup, sc_cont = tail
|
| 1730 | 1728 | , sc_hole_ty = fun_ty })
|
| 1731 | 1729 | | not co_is_opt -- pushCoValArg duplicates the coercion, so optimise first
|
| 1732 | - = addCoerce tyL (optOutCoercion (zapSubstEnv env) tyL co co_is_opt) True cont
|
|
| 1730 | + = addCoerceMaybeRefl tyL (optOutCoercion (zapSubstEnv env) tyL co co_is_opt) True cont
|
|
| 1733 | 1731 | |
| 1734 | 1732 | | Just (_, m_co1, res_ty, m_co2) <- pushCastCoValArg tyL co
|
| 1735 | 1733 | = {-#SCC "addCoerce-pushCoValArg" #-}
|
| 1736 | - do { tail' <- addCoerceM res_ty m_co2 co_is_opt tail
|
|
| 1734 | + do { tail' <- addCoerceMaybeRefl res_ty m_co2 co_is_opt tail
|
|
| 1737 | 1735 | ; if isReflCastCo m_co1
|
| 1738 | 1736 | then return (cont { sc_cont = tail'
|
| 1739 | 1737 | , sc_hole_ty = tyL }) ;
|
| ... | ... | @@ -1753,10 +1751,7 @@ simplCast env body co0 cont0 |
| 1753 | 1751 | , sc_hole_ty = tyL }) } }
|
| 1754 | 1752 | |
| 1755 | 1753 | addCoerce tyL co co_is_opt cont
|
| 1756 | - | isReflCastCo co = return cont -- Having this at the end makes a huge
|
|
| 1757 | - -- difference in T12227, for some reason
|
|
| 1758 | - -- See Note [Optimising reflexivity]
|
|
| 1759 | - | otherwise = return (CastIt { sc_co = co, sc_hole_ty = tyL, sc_opt = co_is_opt, sc_cont = cont })
|
|
| 1754 | + = return (CastIt { sc_co = co, sc_hole_ty = tyL, sc_opt = co_is_opt, sc_cont = cont })
|
|
| 1760 | 1755 | |
| 1761 | 1756 | simplLazyArg :: SimplEnvIS -- ^ Used only for its InScopeSet
|
| 1762 | 1757 | -> DupFlag
|
| ... | ... | @@ -213,11 +213,11 @@ simpleOptPgm opts this_mod binds rules = |
| 213 | 213 | ----------------------
|
| 214 | 214 | type SimpleClo = (SimpleOptEnv, InExpr)
|
| 215 | 215 | |
| 216 | -data SimpleContItem = ApplyToArg SimpleClo | CastIt OutCastCoercion
|
|
| 216 | +data SimpleContItem = ApplyToArg SimpleClo | CastIt OutType OutCastCoercion
|
|
| 217 | 217 | |
| 218 | 218 | instance Outputable SimpleContItem where
|
| 219 | 219 | ppr (ApplyToArg (_, arg)) = text "ARG" <+> ppr arg
|
| 220 | - ppr (CastIt co) = text "CAST" <+> ppr co
|
|
| 220 | + ppr (CastIt _ co) = text "CAST" <+> ppr co
|
|
| 221 | 221 | |
| 222 | 222 | data SimpleOptEnv
|
| 223 | 223 | = SOE { soe_opts :: {-# UNPACK #-} !SimpleOpts
|
| ... | ... | @@ -392,10 +392,10 @@ simple_app env e0@(Lam {}) as0@(_:_) |
| 392 | 392 | = wrapLet mb_pr $ do_beta env'' body as
|
| 393 | 393 | where (env', b') = subst_opt_bndr env b
|
| 394 | 394 | |
| 395 | - do_beta env e@(Lam b body) as@(CastIt co:rest)
|
|
| 395 | + do_beta env e@(Lam b body) as@(CastIt ty co:rest)
|
|
| 396 | 396 | -- See Note [Desugaring unlifted newtypes]
|
| 397 | 397 | | isNonCoVarId b
|
| 398 | - , Just (b', body') <- pushCoercionIntoLambda (soe_subst env) b body co
|
|
| 398 | + , Just (b', body') <- pushCoercionIntoLambda (soe_subst env) b body ty co
|
|
| 399 | 399 | = do_beta (soeZapSubst env) (Lam b' body') rest
|
| 400 | 400 | -- soeZapSubst: pushCoercionIntoLambda applies the substitution
|
| 401 | 401 | | otherwise
|
| ... | ... | @@ -461,10 +461,10 @@ add_cast env tyL co1 as |
| 461 | 461 | = as
|
| 462 | 462 | | otherwise
|
| 463 | 463 | = case as of
|
| 464 | - CastIt co2:rest -> CastIt (co1' `mkTransCastCo` co2):rest
|
|
| 465 | - _ -> CastIt co1':as
|
|
| 464 | + CastIt _ co2:rest -> CastIt ty (co1' `mkTransCastCo` co2):rest
|
|
| 465 | + _ -> CastIt ty co1':as
|
|
| 466 | 466 | where
|
| 467 | - (_, co1') = optCastCoercion (so_co_opts (soe_opts env)) (soe_subst env) tyL co1
|
|
| 467 | + (ty, co1') = optCastCoercion (so_co_opts (soe_opts env)) (soe_subst env) tyL co1
|
|
| 468 | 468 | |
| 469 | 469 | rebuild_app :: HasDebugCallStack
|
| 470 | 470 | => SimpleOptEnv -> OutExpr -> [SimpleContItem] -> OutExpr
|
| ... | ... | @@ -473,7 +473,7 @@ rebuild_app env fun args = foldl mk_app fun args |
| 473 | 473 | in_scope = soeInScope env
|
| 474 | 474 | mk_app out_fun = \case
|
| 475 | 475 | ApplyToArg arg -> App out_fun (simple_opt_clo in_scope arg)
|
| 476 | - CastIt co -> mk_cast out_fun co
|
|
| 476 | + CastIt _ co -> mk_cast out_fun co
|
|
| 477 | 477 | |
| 478 | 478 | {- Note [Desugaring unlifted newtypes]
|
| 479 | 479 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -1675,7 +1675,7 @@ exprIsLambda_maybe ise@(ISE in_scope_set _) (Cast casted_e co) |
| 1675 | 1675 | -- this implies that x is not in scope in gamma (makes this code simpler)
|
| 1676 | 1676 | , not (isTyVar x) && not (isCoVar x)
|
| 1677 | 1677 | , assert (not $ x `elemVarSet` tyCoVarsOfCastCo co) True
|
| 1678 | - , Just (x',e') <- pushCoercionIntoLambda (mkEmptySubst in_scope_set) x e co
|
|
| 1678 | + , Just (x',e') <- pushCoercionIntoLambda (mkEmptySubst in_scope_set) x e (exprType casted_e) co
|
|
| 1679 | 1679 | , let res = Just (x',e',ts)
|
| 1680 | 1680 | = --pprTrace "exprIsLambda_maybe:Cast" (vcat [ppr casted_e,ppr co,ppr res)])
|
| 1681 | 1681 | res
|
| ... | ... | @@ -1166,9 +1166,9 @@ getRenamings orig_bndrs binds rule_bndrs |
| 1166 | 1166 | go [] = init_renamings
|
| 1167 | 1167 | go (bind : binds)
|
| 1168 | 1168 | | NonRec b rhs <- bind
|
| 1169 | - , Just (v, mco) <- getCastedVar rhs
|
|
| 1169 | + , Just (v, co) <- getCastedVar rhs
|
|
| 1170 | 1170 | , Just e <- lookupVarEnv renamings b
|
| 1171 | - = extendVarEnv renamings v (mkCastMCo e (mkSymMCo mco))
|
|
| 1171 | + = extendVarEnv renamings v (mkCastCo e co)
|
|
| 1172 | 1172 | | otherwise
|
| 1173 | 1173 | = renamings
|
| 1174 | 1174 | where
|
| ... | ... | @@ -1186,9 +1186,9 @@ pickSpecBinds is_local known_bndrs (bind:binds) |
| 1186 | 1186 | keep_me rhs = isEmptyVarSet (exprSomeFreeVars bad_var rhs)
|
| 1187 | 1187 | bad_var v = is_local v && not (v `elemVarSet` known_bndrs)
|
| 1188 | 1188 | |
| 1189 | -getCastedVar :: CoreExpr -> Maybe (Var, MCoercionR)
|
|
| 1190 | -getCastedVar (Var v) = Just (v, MRefl)
|
|
| 1191 | -getCastedVar (Cast (Var v) (CCoercion co)) = Just (v, MCo co) -- TODO what about ZCoercion case?
|
|
| 1189 | +getCastedVar :: CoreExpr -> Maybe (Var, CastCoercion)
|
|
| 1190 | +getCastedVar (Var v) = Just (v, ReflCastCo)
|
|
| 1191 | +getCastedVar (Cast (Var v) co) = Just (v, mkSymCastCo (varType v) co)
|
|
| 1192 | 1192 | getCastedVar _ = Nothing
|
| 1193 | 1193 | |
| 1194 | 1194 | specFunInlinePrag :: Id -> InlinePragma
|