[Git][ghc/ghc][wip/marge_bot_batch_merge_job] 5 commits: hadrian: Deprecate quickest flavour.
Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC Commits: b3ddee95 by Andreas Klebinger at 2026-08-28T13:57:46-04:00 hadrian: Deprecate quickest flavour. It was more of a trap for new users than actually beneficial so we deprecate it and suggest quick+no_dynamic_libs to users instead. - - - - - a1d81390 by Andreas Klebinger at 2026-08-28T13:58:37-04:00 cmm: Always favour entry block during block deduplication. We now always keep the first block in the CmmGraph. This way we avoid the need to update the entry info table. Failing to do so caused #27722. Fixes #27722. - - - - - 5bd65f00 by Andreas Klebinger at 2026-08-28T13:59:16-04:00 test: FamAppCachePerf - Only collect bytes allocated. Fixes 27747 - - - - - e3760dba by mangoiv at 2026-08-29T03:15:03-04:00 nightlies: output yaml to file only Previously we would just output the metadata to stdout which risks that it's clobbered by incidental debugt output. We now output to file only. Fixes #27511 - - - - - 0a5cb788 by Andreas Klebinger at 2026-08-29T03:15:03-04:00 Specialise: Stop looping on recursive dictionaries in interestingDict interestingDict now doesn't look through loopbreaker unfoldings. Doing so would cause infinite loops on certain dictionaries. Fixes #27705. - - - - - 22 changed files: - .gitlab-ci.yml - .gitlab/rel_eng/mk-ghcup-metadata/mk_ghcup_metadata.py - + changelog.d/T27705 - + changelog.d/T27722-cbe-entry-block.md - compiler/GHC/Cmm/CommonBlockElim.hs - compiler/GHC/Core/Opt/Specialise.hs - hadrian/README.md - hadrian/doc/cross-compile.md - hadrian/doc/flavours.md - hadrian/doc/make.md - hadrian/doc/windows.md - hadrian/hadrian.cabal - hadrian/src/CommandLine.hs - hadrian/src/Flavour.hs - hadrian/src/Settings.hs - − hadrian/src/Settings/Flavours/Quickest.hs - testsuite/tests/perf/compiler/all.T - + testsuite/tests/simplCore/should_run/T27705.hs - + testsuite/tests/simplCore/should_run/T27705.stdout - + testsuite/tests/simplCore/should_run/T27705_Inst.hs - testsuite/tests/simplCore/should_run/all.T - utils/ghc-toolchain/src/GHC/Toolchain/Target.hs Changes: ===================================== .gitlab-ci.yml ===================================== @@ -1300,7 +1300,7 @@ ghcup-metadata-nightly: artifacts: false - job: project-version script: - - nix shell -f .gitlab/rel_eng -c ghcup-metadata --metadata ghcup-0.0.7.yaml --date="$(date -d $CI_PIPELINE_CREATED_AT +%Y-%m-%d)" --pipeline-id="$CI_PIPELINE_ID" --version="$ProjectVersion" > "metadata_test.yaml" + - nix shell -f .gitlab/rel_eng -c ghcup-metadata --metadata ghcup-0.0.7.yaml --date="$(date -d $CI_PIPELINE_CREATED_AT +%Y-%m-%d)" --pipeline-id="$CI_PIPELINE_ID" --version="$ProjectVersion" metadata_test.yaml rules: - if: $NIGHTLY ===================================== .gitlab/rel_eng/mk-ghcup-metadata/mk_ghcup_metadata.py ===================================== @@ -324,6 +324,7 @@ def main() -> None: # TODO: We could work out the --version from the project-version CI job. parser.add_argument('--version', required=True, type=str, help='Version of the GHC compiler') parser.add_argument('--date', required=True, type=str, help='Date of the compiler release') + parser.add_argument('output_path', nargs='?', type=Path, help='Path to write the output to, if not set, dump to stdout') args = parser.parse_args() project = gl.projects.get(1, lazy=True) @@ -352,13 +353,14 @@ def main() -> None: with open(args.metadata, 'r') as file: ghcup_metadata = yaml.safe_load(file) if args.version in ghcup_metadata['ghcupDownloads']['GHC']: - # if there are days without a commit, then the nightly metadata - # is up to date by default, no need to fail, no need to upload anything - print("Refusing to override existing version in metadata, exiting") - sys.exit() + eprint("GHCUp nightly run produced the same metadata as last night") setNightlyTags(ghcup_metadata) ghcup_metadata['ghcupDownloads']['GHC'][args.version] = new_yaml - print(yaml.dump(ghcup_metadata)) + if args.output_path: + with open(args.output_path, 'w') as ofile: + yaml.dump(ghcup_metadata, ofile) + else: + print(yaml.dump(ghcup_metadata)) ===================================== changelog.d/T27705 ===================================== @@ -0,0 +1,5 @@ +section: compiler +synopsis: Fixed an issue that caused the specializer to sometimes loop on recursive dictionary superclasses. +issues: #27705 +mrs: !16559 + ===================================== changelog.d/T27722-cbe-entry-block.md ===================================== @@ -0,0 +1,5 @@ +section: cmm +issues: #27722 +mrs: !16592 +synopsis: + Fix common block elimination dropping entry block info table in hand written cmm. ===================================== compiler/GHC/Cmm/CommonBlockElim.hs ===================================== @@ -26,6 +26,7 @@ import GHC.Types.Literal.Floating import GHC.Types.Unique.FM import GHC.Types.Unique import GHC.Utils.Word64 (truncateWord64ToWord32) +import GHC.Utils.Panic.Plain (assert) import Control.Arrow (first, second) import Data.List.NonEmpty (NonEmpty (..)) import qualified Data.List.NonEmpty as NE @@ -60,16 +61,31 @@ import qualified Data.List.NonEmpty as NE -- TODO: Use optimization fuel elimCommonBlocks :: CmmGraph -> CmmGraph -elimCommonBlocks g = replaceLabels env $ copyTicks env g +elimCommonBlocks g = + assert (g_entry g == g_entry g') g' where + g' = replaceLabels env $ copyTicks env g env = iterate mapEmpty blocks_with_key -- The order of blocks doesn't matter here. While we could use -- revPostorder which drops unreachable blocks this is done in -- ContFlowOpt already which runs before this pass. So we use -- toBlockList since it is faster. - groups = groupByInt hash_block (toBlockList g) :: [[CmmBlock]] + -- One exception: The entry block most come first or we risk eliminating it + -- in favour of another block. See Note [Retain entry block during common block elimination.] + groups = groupByInt hash_block (toBlockListEntryFirst g) :: [[CmmBlock]] blocks_with_key = [ [ (successors b, [b]) | b <- bs] | bs <- groups] +-- Note [Retain entry block during common block elimination.] +-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-- At the stage we run common block elimination (CBE) we only have one info +-- table for the entry label. Which means we can get away without applying the +-- block label substitution to the info table *as long as we keep the first block*. +-- When combining blocks the first block in the list of blocks is kept, and the later +-- one eliminated, so we can achieve this by simply using toBlockListEntryFirst. +-- +-- If we don't we end up with #27722 where the entry block was eliminated in favour +-- of another block. + -- Invariant: The blocks in the list are pairwise distinct -- (so avoid comparing them again) type DistinctBlocks = [CmmBlock] ===================================== compiler/GHC/Core/Opt/Specialise.hs ===================================== @@ -3120,8 +3120,8 @@ interestingDict :: SpecEnv -> CoreExpr -> Bool -- This is a subtle and important function -- See Note [Interesting dictionary arguments] interestingDict env (Var v) -- See (ID3) and (ID5) + -- (ID6.a) Might fail for loop breaker dicts but that seems fine. | Just rhs <- maybeUnfoldingTemplate (idUnfolding v) - -- Might fail for loop breaker dicts but that seems fine. = interestingDict env rhs interestingDict env arg -- Main Plan: use exprIsConApp_maybe @@ -3136,9 +3136,9 @@ interestingDict env arg -- Main Plan: use exprIsConApp_maybe , isIPClass cls -- See (ID5) -> False - -- Otherwise we are unwrapping a unary type class + -- Shouldn't happen. | otherwise - -> exprIsHNF arg -- See (ID7) + -> pprTraceDebug "shouldn't happen anymore" (ppr arg) $ exprIsHNF arg -- See (ID7) | Just (_, _, data_con, _tys, args) <- exprIsConApp_maybe in_scope_env arg , Just cls <- tyConClass_maybe (dataConTyCon data_con) @@ -3152,7 +3152,8 @@ interestingDict env arg -- Main Plan: use exprIsConApp_maybe where arg_ty = exprType arg definitely_not_ip_like = not (couldBeIPLike arg_ty) - in_scope_env = ISE (substInScopeSet $ se_subst env) realIdUnfolding + -- idUnfolding rather than realIdUnfolding: See (ID6.a) + in_scope_env = ISE (substInScopeSet $ se_subst env) idUnfolding {- Note [Ticks on applications] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -3268,11 +3269,27 @@ case we can clearly specialise. But there are wrinkles: (Remember: a constraint tuple is just a class with N superclasses and no methods.) See discussion on #26831. -(ID7) A unary (single-method) class is currently represented by (meth |> co). We - will unwrap the cast (see (ID5)) and then want to reply "yes" if the method - has any struture. We rather arbitrarily use `exprIsHNF` for this. (We plan a - new story for unary classes, see #23109, and this special case will become - irrelevant.) +(ID6.a) If we deal with a recursive dictionary as in #27705 we want to avoid + infinite recursion while recursing into superclasses. + + For example we might have: + + class D1 a => D2 a + class D2 a => D1 a + + The primary concern is that we want to avoid looping on recursive instances. + We can achieve this by simply not looking through loop breakers by using idUnfolding + rather than realIdUnfolding. + + It's possible that this prevents specialization of edge cases that have loop breakers + in their recursive loop. But even if we can find a dictionary like this the simplifier + won't look through loopbreaker dictionaries either killing any potential benefit. + So while we could handle this case via a already-seen set or fuel we simply don't bother + for now. + +(ID7) A unary (single-method) class is currently handled by the same path as regular dicts + since they are represented by faking a regular Dictionary. + See Note [Unary class magic] for the details. (ID8) Sadly, if `exprIsConApp_maybe` says Nothing, we still want to treat a non-trivial argument as interesting. In T19695 we have this: ===================================== hadrian/README.md ===================================== @@ -55,10 +55,9 @@ changes. Build results are placed into `_build` by default. There are many different ways to build a compiler, each way is called a flavour. * `--flavour=FLAVOUR`: choose a build flavour. The following settings are -currently supported: `default`, `quick`, `quickest`, `perf`, `prof`, `devel1` -and `devel2`. As an example, the `quickest` flavour adds `-O0` flag to all GHC -invocations and builds libraries only in the `vanilla` way, which speeds up -builds by 3-4x. +currently supported: `default`, `quick`, `perf`, `prof`, `devel1` +and `devel2`. As an example, the `quick` flavour builds the GHC binary with `-O0` +which speeds up builds and rebuilds significantly. In addition to the overall build flavour there are also "flavour transformers" which can slightly modify the build settings for a flavour. Some common flavour ===================================== hadrian/doc/cross-compile.md ===================================== @@ -16,7 +16,7 @@ After all the dependencies are in place: - `git submodule update --init` - `./configure --target=arm-linux-gnueabihf` - `cd hadrian` -- Build the compiler by e.g. `./build.sh --flavour=quickest --integer-simple -V -j` +- Build the compiler by e.g. `./build.sh --flavour=quick --integer-simple -V -j` After that, you should have built `inplace/bin/ghc-stage1` cross compiler. We will go to the next section to validate this. ===================================== hadrian/doc/flavours.md ===================================== @@ -82,18 +82,6 @@ when compiling the `compiler` library, and `hsGhc` when compiling/linking the GH <td>-O</td> <td>-debug (link)</td> </tr> - <tr> - <th>quickest</td> - <td></td> - <td>-O0<br>+RTS<br>-O64M<br>-RTS</td> - <td>-O0<br>+RTS<br>-O64M<br>-RTS</td> - <td></td> - <td></td> - <td>-O</td> - <td></td> - <td>-O</td> - <td></td> - </tr> <tr> <th>perf</td> <td> Yes (on supported platforms) </td> @@ -367,11 +355,4 @@ information. The following table lists ways that are built in different flavours <td>debug<br>threaded<br>threadedDebug<br>debugDynamic<br>threadedDynamic<br>threadedDebugDynamic</td> <td>debug<br>threaded<br>threadedDebug<br>debugDynamic<br>threadedDynamic<br>threadedDebugDynamic</td> </tr> -<tr> - <th>quickest</th> - <td>vanilla</td> - <td>vanilla</td> - <td>vanilla<br>threaded</td> - <td>vanilla<br>threaded</td> -</tr> </table> ===================================== hadrian/doc/make.md ===================================== @@ -80,15 +80,15 @@ time you fire up a build. This is not possible with the Make build system. build _build/stage1/lib/package.conf.d/text-1.2.3.0.conf # OR actual path ``` -- Building with a particular flavour (e.g `quickest`) +- Building with a particular flavour (e.g `quick`) ``` sh # Make - echo "BuildFlavour=quickest" >> mk/build.mk + echo "BuildFlavour=quick" >> mk/build.mk make # Hadrian - build --flavour=quickest + build --flavour=quick ``` See [flavours documentation](https://gitlab.haskell.org/ghc/ghc/blob/master/hadrian/doc/flavours.md) for info on flavours. ===================================== hadrian/doc/windows.md ===================================== @@ -20,7 +20,7 @@ stack exec -- pacman -S autoconf automake-wrapper make patch python tar --noconf stack build # Build GHC -stack exec hadrian -- --directory ".." -j --flavour=quickest +stack exec hadrian -- --directory ".." -j --flavour=quick # Test GHC cd .. @@ -28,7 +28,7 @@ _build\stage1\bin\ghc -e 1+2 ``` The entire process should take about 20 minutes. Note, this will build GHC -without optimisations. If you need an optimised GHC, drop the `--flavour=quickest` +without optimisations. If you need an optimised GHC, drop the `--flavour=quick` flag from the build command line (this will slow down the build to about an hour). These are currently not the @@ -37,7 +37,7 @@ but are much simpler and may also be more robust. The `stack build` and `stack exec hadrian` commands can be replaced by an invocation of Hadrian's Stack-based build script: -`build-stack.bat -j --flavour=quickest`. Use this script if you plan to work on +`build-stack.bat -j --flavour=quick`. Use this script if you plan to work on Hadrian and/or rebuild GHC often. ## Prerequisites ===================================== hadrian/hadrian.cabal ===================================== @@ -125,7 +125,6 @@ executable hadrian , Settings.Flavours.Performance , Settings.Flavours.Quick , Settings.Flavours.QuickCross - , Settings.Flavours.Quickest , Settings.Flavours.Validate , Settings.Flavours.Release , Settings.Packages ===================================== hadrian/src/CommandLine.hs ===================================== @@ -281,7 +281,7 @@ optDescrs = , Option ['o'] ["build-root"] (ReqArg readBuildRoot "BUILD_ROOT") "Where to store build artifacts. (Default _build)." , Option [] ["flavour"] (OptArg readFlavour "FLAVOUR") - "Build flavour (Default, Devel1, Devel2, Perf, Prof, Quick or Quickest)." + "Build flavour (Default, Devel1, Devel2, Perf, Prof or Quick)." , Option [] ["freeze1"] (NoArg readFreeze1) "Freeze Stage1 GHC." , Option [] ["freeze2"] (NoArg readFreeze2) ===================================== hadrian/src/Flavour.hs ===================================== @@ -531,7 +531,7 @@ It now also offers a more "old-school" interface, in the form of @foo.bar.baz = v@ or @foo.bar.baz += v@ expressions, that one can pass on the command line that invokes hadrian: -> $ hadrian/build --flavour=quickest -j "stage1.ghc-bin.ghc.link.opts += -v3" +> $ hadrian/build --flavour=quick -j "stage1.ghc-bin.ghc.link.opts += -v3" or in a file at <build root>/hadrian.settings, where <build root> is the build root to be used for the build, which is _build by default. ===================================== hadrian/src/Settings.hs ===================================== @@ -19,7 +19,6 @@ import Settings.Flavours.Development import Settings.Flavours.GhcInGhci import Settings.Flavours.Performance import Settings.Flavours.Quick -import Settings.Flavours.Quickest import Settings.Flavours.QuickCross import Settings.Flavours.Validate import Settings.Flavours.Release @@ -55,7 +54,6 @@ hadrianFlavours = , developmentFlavour Stage2, performanceFlavour , releaseFlavour , quickFlavour, quickValidateFlavour, quickDebugFlavour - , quickestFlavour , quickCrossFlavour , ghcInGhciFlavour, validateFlavour, slowValidateFlavour ] @@ -69,6 +67,10 @@ hadrianFlavours = flavour :: Action Flavour flavour = do flavourName <- fromMaybe userDefaultFlavour <$> cmdFlavour + when ("quickest" `isPrefixOf` flavourName) $ + fail $ "The `quickest` flavour has been deprecated. Use `quick` instead.\n" + ++ "Skip building dynamic libraries with `quick+no_dynamic_libs`\n" + ++ "to get closer to the old quickest behaviour." kvs <- userSetting ([] :: [KeyVal]) let flavours = hadrianFlavours ++ userFlavours (settingErrs, tweak) = applySettings kvs ===================================== hadrian/src/Settings/Flavours/Quickest.hs deleted ===================================== @@ -1,21 +0,0 @@ -module Settings.Flavours.Quickest (quickestFlavour) where - -import Expression -import Flavour -import {-# SOURCE #-} Settings.Default - --- Please update doc/flavours.md when changing this file. -quickestFlavour :: Flavour -quickestFlavour = disableDynamicLibs $ disableProfiledLibs $ defaultFlavour - { name = "quickest" - , extraArgs = quickestArgs - } - -quickestArgs :: Args -quickestArgs = sourceArgs SourceArgs - { hsDefault = mconcat $ - [ pure ["-O0", "+RTS", "-O64M", "-RTS"] - ] - , hsLibrary = mempty - , hsCompiler = stage0 ? arg "-O" - , hsGhc = stage0 ? arg "-O" } ===================================== testsuite/tests/perf/compiler/all.T ===================================== @@ -192,7 +192,6 @@ test ('T13386', # Performance test for lookups in the family application cache test('FamAppCachePerf', [ only_ways(['normal']) - , collect_compiler_residency(20) , collect_compiler_stats('bytes allocated',2) ], compile, ===================================== testsuite/tests/simplCore/should_run/T27705.hs ===================================== @@ -0,0 +1,9 @@ +module Main where + +import T27705_Inst + +-- The dictionaries (D1/D2) are mutually recursive. We have to watch +-- out for the specializer looping on them. This was first detected in #22802 +-- but no test was added, which caused it to break again #27705 :( +main :: IO () +main = print (b (3 :: Int)) ===================================== testsuite/tests/simplCore/should_run/T27705.stdout ===================================== @@ -0,0 +1 @@ +42 ===================================== testsuite/tests/simplCore/should_run/T27705_Inst.hs ===================================== @@ -0,0 +1,13 @@ +{-# LANGUAGE UndecidableInstances, UndecidableSuperClasses, FlexibleInstances #-} +module T27705_Inst where + +-- The two dictionaries are mutually recursive, and we have to ensure the specialiser +-- doesn't loop when it's peaking through their unfoldings. +class D2 a => D1 a +class D1 a => D2 a +instance D2 Int => D1 Int +instance D1 Int => D2 Int + +{-# NOINLINE b #-} +b :: D1 a => a -> Int +b _ = 42 ===================================== testsuite/tests/simplCore/should_run/all.T ===================================== @@ -123,3 +123,5 @@ test('T24359b', normal, compile_and_run, ['-O']) test('T23429', normal, compile_and_run, ['-O']) test('T27071', normal, compile_and_run, ['-O -fworker-wrapper-cbv']) test('T27005', [], multimod_compile_and_run, ['T27005', '-O']) +test('T27705', [extra_hc_opts('+RTS -M500M -RTS')], multimod_compile_and_run, + ['T27705', '-O2 -fexpose-all-unfoldings']) ===================================== utils/ghc-toolchain/src/GHC/Toolchain/Target.hs ===================================== @@ -199,7 +199,7 @@ tgtSupportsSMP Target{..} = do -- 5. The testsuite driver will use dyn way for TH/ghci tests even -- when host GHC is static. -- 6. TH/ghci doesn't work if stage1 is built without shared libraries --- (e.g. quickest/fully_static). +-- (e.g. no_dynamic_libs/fully_static). tgtRTSLinkerOnlySupportsSharedLibs :: Target -> Bool tgtRTSLinkerOnlySupportsSharedLibs Target{tgtArchOs} = archOS_arch tgtArchOs `elem` View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/1eab24e6d5ab03bc9dd40d6f549113e... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/1eab24e6d5ab03bc9dd40d6f549113e... You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
participants (1)
-
Marge Bot (@marge-bot)