David Eichmann pushed to branch wip/davide/hadrian-windows-symlink at Glasgow Haskell Compiler / GHC
Commits:
-
f9bcfac2
by sheaf at 2026-06-03T14:47:19-04:00
-
cf1fd661
by Artem Pelenitsyn at 2026-06-03T14:48:09-04:00
-
7a23957d
by David Eichmann at 2026-06-04T12:24:02+01:00
7 changed files:
- + changelog.d/T27182.md
- compiler/GHC/Builtin/primops.txt.pp
- compiler/GHC/Core/Utils.hs
- compiler/GHC/CoreToStg/Prep.hs
- hadrian/src/Rules/BinaryDist.hs
- + testsuite/tests/profiling/should_compile/T27182.hs
- testsuite/tests/profiling/should_compile/all.T
Changes:
| 1 | +section: compiler
|
|
| 2 | +issues: #27182
|
|
| 3 | +mrs: !16003
|
|
| 4 | +synopsis:
|
|
| 5 | + Fix `getStgArgFromTrivialArg` panic in CoreToStg
|
|
| 6 | +description:
|
|
| 7 | + Avoid a `getStgArgFromTrivialArg` panic in CoreToStg due to a call to `mkTick`
|
|
| 8 | + in Core Prep which invalidated ANF. |
| ... | ... | @@ -2149,7 +2149,7 @@ primop SizeofMutableByteArrayOp "sizeofMutableByteArray#" GenPrimOp |
| 2149 | 2149 | |
| 2150 | 2150 | primop GetSizeofMutableByteArrayOp "getSizeofMutableByteArray#" GenPrimOp
|
| 2151 | 2151 | MutableByteArray# s -> State# s -> (# State# s, Int# #)
|
| 2152 | - {Return the number of elements in the array, correctly accounting for
|
|
| 2152 | + {Return the number of bytes in the array, correctly accounting for
|
|
| 2153 | 2153 | the effect of 'shrinkMutableByteArray#' and 'resizeMutableByteArray#'.
|
| 2154 | 2154 | |
| 2155 | 2155 | @since 0.5.0.0}
|
| ... | ... | @@ -11,6 +11,7 @@ module GHC.Core.Utils ( |
| 11 | 11 | -- * Constructing expressions
|
| 12 | 12 | mkCast, mkCastMCo, mkPiMCo,
|
| 13 | 13 | mkTick, mkTicks, mkTickNoHNF, tickHNFArgs,
|
| 14 | + mkTickCpe,
|
|
| 14 | 15 | bindNonRec, needsCaseBinding, needsCaseBindingL,
|
| 15 | 16 | mkAltExpr, mkDefaultCase, mkSingleAltCase,
|
| 16 | 17 | |
| ... | ... | @@ -319,7 +320,18 @@ mkCast expr co |
| 319 | 320 | -- * Split profiling ticks into counting/scoping parts so that the two parts
|
| 320 | 321 | -- can be placed independently into the AST.
|
| 321 | 322 | mkTick :: CoreTickish -> CoreExpr -> CoreExpr
|
| 322 | -mkTick t orig_expr = mkTick' orig_expr
|
|
| 323 | +mkTick = mk_tick False
|
|
| 324 | + |
|
| 325 | +-- | A version of 'mkTick' that preserves ANF, for use in Core Prep.
|
|
| 326 | +--
|
|
| 327 | +-- See Note [mkTick breaks ANF] in GHC.CoreToStg.Prep.
|
|
| 328 | +mkTickCpe :: CoreTickish -> CoreExpr -> CoreExpr
|
|
| 329 | +mkTickCpe = mk_tick True
|
|
| 330 | + |
|
| 331 | +-- | Internal function used to define both 'mkTick' and 'mkTickCpe'
|
|
| 332 | +-- without duplication.
|
|
| 333 | +mk_tick :: Bool -> CoreTickish -> CoreExpr -> CoreExpr
|
|
| 334 | +mk_tick preserve_anf t orig_expr = mkTick' orig_expr
|
|
| 323 | 335 | where
|
| 324 | 336 | -- Some ticks (cost-centres) can be split in two, with the
|
| 325 | 337 | -- non-counting part having laxer placement properties.
|
| ... | ... | @@ -343,7 +355,7 @@ mkTick t orig_expr = mkTick' orig_expr |
| 343 | 355 | -- Push SCCs into lambdas.
|
| 344 | 356 | -- See (PSCC2) in Note [Pushing SCCs inwards].
|
| 345 | 357 | | can_split
|
| 346 | - -> Tick (mkNoScope t) $ Lam x $ mkTick (mkNoCount t) e
|
|
| 358 | + -> Tick (mkNoScope t) $ Lam x $ mk_tick preserve_anf (mkNoCount t) e
|
|
| 347 | 359 | |
| 348 | 360 | App f arg
|
| 349 | 361 | -- All ticks float inwards through non-runtime arguments, as per
|
| ... | ... | @@ -353,7 +365,9 @@ mkTick t orig_expr = mkTick' orig_expr |
| 353 | 365 | |
| 354 | 366 | -- Push SCCs into saturated constructor applications.
|
| 355 | 367 | -- See (PSCC3) in Note [Pushing SCCs inwards].
|
| 356 | - | isSaturatedConApp expr
|
|
| 368 | + | not preserve_anf -- this optimisation breaks ANF;
|
|
| 369 | + -- see Note [mkTick breaks ANF] in GHC.CoreToStg.Prep
|
|
| 370 | + , isSaturatedConApp expr
|
|
| 357 | 371 | , tickishPlace t == PlaceCostCentre || can_split
|
| 358 | 372 | -> if tickishPlace t == PlaceCostCentre
|
| 359 | 373 | then tickHNFArgs t expr
|
| ... | ... | @@ -801,7 +801,9 @@ cpeBodyF env (Tick tickish expr) |
| 801 | 801 | ; return (FloatTick tickish `consFloat` floats, body) }
|
| 802 | 802 | | otherwise
|
| 803 | 803 | = do { body <- cpeBody env expr
|
| 804 | - ; return (emptyFloats, mkTick tickish' body) }
|
|
| 804 | + ; return (emptyFloats, mkTickCpe tickish' body) }
|
|
| 805 | + -- Use mkTickCpe and not mkTick, as the latter may break ANF (#27182).
|
|
| 806 | + -- See (TickANF2) in Note [mkTick breaks ANF].
|
|
| 805 | 807 | where
|
| 806 | 808 | tickish' | Breakpoint ext bid fvs <- tickish
|
| 807 | 809 | -- See also 'substTickish'
|
| ... | ... | @@ -905,6 +907,28 @@ cpeBodyF env (Case scrut bndr ty alts) |
| 905 | 907 | ; rhs' <- cpeBody env2 rhs
|
| 906 | 908 | ; return (Alt con bs' rhs') }
|
| 907 | 909 | |
| 910 | +{- Note [mkTick breaks ANF]
|
|
| 911 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 912 | +mkTick does not preserve the ANF property as required by Core Prep (see
|
|
| 913 | +Note [CorePrep invariants]), as seen in #27182. Given:
|
|
| 914 | + |
|
| 915 | + mkTick scc<foo> (\ (eta :: Char -> Bool) -> BindP (p :: Int) eta)
|
|
| 916 | + |
|
| 917 | +mkTick will push the SCC into the constructor application, resulting in:
|
|
| 918 | + |
|
| 919 | + \ (eta :: Char -> Bool) -> BindP (p :: Int) (scc<oneM> eta)
|
|
| 920 | + |
|
| 921 | +To avoid this problem (at least until 'mkTick' is more thoroughly reworked to
|
|
| 922 | +avoid this infelicity, see #27141), we define a variant of 'mkTick', called
|
|
| 923 | +'mkTickCpe', which does not push ticks into constructor applications (this is
|
|
| 924 | +the only optimisation done by 'mkTick' that can break ANF).
|
|
| 925 | + |
|
| 926 | +We prefer using a small variant of 'mkTick' rather than using the 'Tick'
|
|
| 927 | +constructor, as the latter can slightly degrade profiling reports by failing to
|
|
| 928 | +combine ticks (can result in spurious cost centres with 0 entries appearing in
|
|
| 929 | +profiling reports).
|
|
| 930 | +-}
|
|
| 931 | + |
|
| 908 | 932 | -- ---------------------------------------------------------------------------
|
| 909 | 933 | -- CpeBody: produces a result satisfying CpeBody
|
| 910 | 934 | -- ---------------------------------------------------------------------------
|
| ... | ... | @@ -1207,7 +1231,7 @@ cpeApp top_env expr |
| 1207 | 1231 | rebuild_app' env (a : as) fun' floats ss rt_ticks req_depth = case a of
|
| 1208 | 1232 | -- See Note [Ticks and mandatory eta expansion]
|
| 1209 | 1233 | _ | not (null rt_ticks), req_depth <= 0
|
| 1210 | - -> let tick_fun = foldr mkTick fun' rt_ticks
|
|
| 1234 | + -> let tick_fun = foldr mkTickCpe fun' rt_ticks
|
|
| 1211 | 1235 | in rebuild_app' env (a : as) tick_fun floats ss rt_ticks req_depth
|
| 1212 | 1236 | |
| 1213 | 1237 | AIApp (Type arg_ty)
|
| ... | ... | @@ -2307,7 +2331,7 @@ wrapBinds floats body |
| 2307 | 2331 | mk_bind (UnsafeEqualityCase scrut b con bs) body
|
| 2308 | 2332 | = mkSingleAltCase scrut b con bs body
|
| 2309 | 2333 | mk_bind (FloatTick tickish) body
|
| 2310 | - = mkTick tickish body
|
|
| 2334 | + = mkTickCpe tickish body
|
|
| 2311 | 2335 | |
| 2312 | 2336 | -- | Put floats at top-level
|
| 2313 | 2337 | deFloatTop :: Floats -> [CoreBind]
|
| ... | ... | @@ -2735,7 +2759,7 @@ newVar env ty |
| 2735 | 2759 | wrapTicks :: Floats -> CoreExpr -> (Floats, CoreExpr)
|
| 2736 | 2760 | wrapTicks floats expr
|
| 2737 | 2761 | | (floats1, ticks1) <- fold_fun go floats
|
| 2738 | - = (floats1, foldrOL mkTick expr ticks1)
|
|
| 2762 | + = (floats1, foldrOL mkTickCpe expr ticks1)
|
|
| 2739 | 2763 | where fold_fun f floats =
|
| 2740 | 2764 | let (binds, ticks) = foldlOL f (nilOL,nilOL) (fs_binds floats)
|
| 2741 | 2765 | in (floats { fs_binds = binds }, ticks)
|
| ... | ... | @@ -2755,8 +2779,8 @@ wrapTicks floats expr |
| 2755 | 2779 | |
| 2756 | 2780 | wrap t (Float bind bound info) = Float (wrapBind t bind) bound info
|
| 2757 | 2781 | wrap _ f = pprPanic "Unexpected FloatingBind" (ppr f)
|
| 2758 | - wrapBind t (NonRec binder rhs) = NonRec binder (mkTick t rhs)
|
|
| 2759 | - wrapBind t (Rec pairs) = Rec (mapSnd (mkTick t) pairs)
|
|
| 2782 | + wrapBind t (NonRec binder rhs) = NonRec binder (mkTickCpe t rhs)
|
|
| 2783 | + wrapBind t (Rec pairs) = Rec (mapSnd (mkTickCpe t) pairs)
|
|
| 2760 | 2784 | |
| 2761 | 2785 | ------------------------------------------------------------------------------
|
| 2762 | 2786 | -- Numeric literals
|
| ... | ... | @@ -289,23 +289,25 @@ bindistRules = do |
| 289 | 289 | copyFile ("hadrian" -/- "cfg" -/- "default.target.in") (bindistFilesDir -/- "default.target.in")
|
| 290 | 290 | copyFile ("hadrian" -/- "cfg" -/- "default.host.target.in") (bindistFilesDir -/- "default.host.target.in")
|
| 291 | 291 | |
| 292 | - -- todo: do we need these wrappers on windows
|
|
| 293 | - forM_ bin_targets $ \(pkg, _) -> do
|
|
| 294 | - needed_wrappers <- pkgToWrappers pkg
|
|
| 295 | - forM_ needed_wrappers $ \wrapper_name -> do
|
|
| 296 | - let suffix = if useGhcPrefix pkg
|
|
| 297 | - then "ghc-" ++ version
|
|
| 298 | - else version
|
|
| 299 | - wrapper_content <- wrapper wrapper_name
|
|
| 300 | - let unversioned_wrapper_path = bindistFilesDir -/- "wrappers" -/- wrapper_name
|
|
| 301 | - versioned_wrapper = wrapper_name ++ "-" ++ suffix
|
|
| 302 | - versioned_wrapper_path = bindistFilesDir -/- "wrappers" -/- versioned_wrapper
|
|
| 303 | - -- Write the wrapper to the versioned path
|
|
| 304 | - writeFile' versioned_wrapper_path wrapper_content
|
|
| 305 | - -- Create a symlink from the non-versioned to the versioned.
|
|
| 306 | - liftIO $ do
|
|
| 307 | - IO.removeFile unversioned_wrapper_path <|> return ()
|
|
| 308 | - IO.createFileLink versioned_wrapper unversioned_wrapper_path
|
|
| 292 | + -- These wrapper scripts are only necessary in the configure/install
|
|
| 293 | + -- workflow which is not supported on windows.
|
|
| 294 | + unless windowsHost $ do
|
|
| 295 | + forM_ bin_targets $ \(pkg, _) -> do
|
|
| 296 | + needed_wrappers <- pkgToWrappers pkg
|
|
| 297 | + forM_ needed_wrappers $ \wrapper_name -> do
|
|
| 298 | + let suffix = if useGhcPrefix pkg
|
|
| 299 | + then "ghc-" ++ version
|
|
| 300 | + else version
|
|
| 301 | + wrapper_content <- wrapper wrapper_name
|
|
| 302 | + let unversioned_wrapper_path = bindistFilesDir -/- "wrappers" -/- wrapper_name
|
|
| 303 | + versioned_wrapper = wrapper_name ++ "-" ++ suffix
|
|
| 304 | + versioned_wrapper_path = bindistFilesDir -/- "wrappers" -/- versioned_wrapper
|
|
| 305 | + -- Write the wrapper to the versioned path
|
|
| 306 | + writeFile' versioned_wrapper_path wrapper_content
|
|
| 307 | + -- Create a symlink from the non-versioned to the versioned.
|
|
| 308 | + liftIO $ do
|
|
| 309 | + IO.removeFile unversioned_wrapper_path <|> return ()
|
|
| 310 | + IO.createFileLink versioned_wrapper unversioned_wrapper_path
|
|
| 309 | 311 | |
| 310 | 312 | let buildBinDist compressor = do
|
| 311 | 313 | win_target <- isWinTarget
|
| 1 | +module T27182 ( oneM ) where
|
|
| 2 | + |
|
| 3 | +data Parser = BindP Int ( Char -> Bool )
|
|
| 4 | + |
|
| 5 | +oneM :: Int -> ( Char -> Bool ) -> Parser
|
|
| 6 | +oneM p = BindP p |
| ... | ... | @@ -22,3 +22,4 @@ test('T19894', [test_opts, extra_files(['T19894'])], multimod_compile, ['Main', |
| 22 | 22 | test('T20938', [test_opts], compile, ['-O -prof'])
|
| 23 | 23 | test('T26056', [test_opts], compile, ['-O -prof'])
|
| 24 | 24 | test('T27121', [test_opts, extra_files(['T27121_aux.hs'])], multimod_compile, ['T27121', '-v0 -O -prof -fprof-auto'])
|
| 25 | +test('T27182', [test_opts], compile, ['-O -prof -fprof-late']) |