Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
-
d216412b
by Ian-Woo Kim at 2026-06-16T20:25:57-04:00
-
8e1cc105
by Wolfgang Jeltsch at 2026-06-16T20:25:57-04:00
5 changed files:
- + changelog.d/deterministic-usage-order
- changelog.d/module-graph-reuse-in-downsweep
- changelog.d/more-efficient-home-unit-imports-finding
- compiler/GHC/HsToCore/Usage.hs
- compiler/GHC/Unit/Module/Deps.hs
Changes:
| 1 | +section: compiler
|
|
| 2 | +synopsis: Make the order of usages deterministic
|
|
| 3 | +issues: #26877
|
|
| 4 | +mrs: !15484
|
|
| 5 | +description: {
|
|
| 6 | + The order in which usages appear in interface files is now
|
|
| 7 | + deterministic.
|
|
| 8 | +} |
| ... | ... | @@ -3,7 +3,7 @@ synopsis: Allow `downsweep` to use nodes of an existing module graph |
| 3 | 3 | issues: #27054
|
| 4 | 4 | mrs: !16028
|
| 5 | 5 | description: {
|
| 6 | - This contribution enables `downsweep` to use the nodes of a module
|
|
| 7 | - graph obtained from a previous downsweeping round, which allows GHC
|
|
| 8 | - API applications to build module graphs somewhat incrementally.
|
|
| 6 | + The `downsweep` operation can now use the nodes of a module graph
|
|
| 7 | + obtained from a previous downsweeping round, which allows GHC API
|
|
| 8 | + applications to build module graphs somewhat incrementally.
|
|
| 9 | 9 | } |
| ... | ... | @@ -3,13 +3,10 @@ synopsis: Introduce a cache of home module name providers |
| 3 | 3 | issues: #27055
|
| 4 | 4 | mrs: !15888
|
| 5 | 5 | description: {
|
| 6 | - This contribution optimizes the algorithm for finding out which home
|
|
| 7 | - unit provides the module that a certain import declaration refers
|
|
| 8 | - to. The previous approach has been to simply search all home units
|
|
| 9 | - in no particular order. This change introduces a cache that allows
|
|
| 10 | - for efficiently determining those complete home units that provide a
|
|
| 11 | - certain module name and changes the module-finding algorithm such
|
|
| 12 | - that it searches these units before the other home units. This leads
|
|
| 13 | - to significant performance improvements in situations where there
|
|
| 14 | - are lots of home units.
|
|
| 6 | + For finding out which home unit provides the module that a certain
|
|
| 7 | + import declaration refers to, we now use a better algorithm. The
|
|
| 8 | + previous approach was to simply search all home units in no
|
|
| 9 | + particular order. The new algorithm first searches those complete
|
|
| 10 | + home units that provide a certain module name, before searching the
|
|
| 11 | + other home units.
|
|
| 15 | 12 | } |
| ... | ... | @@ -70,6 +70,8 @@ data UsageConfig = UsageConfig |
| 70 | 70 | { uc_safe_implicit_imps_req :: !Bool -- ^ Are all implicit imports required to be safe for this Safe Haskell mode?
|
| 71 | 71 | }
|
| 72 | 72 | |
| 73 | +-- | Build the list of 'Usage's that drive recompilation checking.
|
|
| 74 | +-- The resulting list is deterministically sorted.
|
|
| 73 | 75 | mkUsageInfo :: UsageConfig -> Plugins -> FinderCache -> UnitEnv
|
| 74 | 76 | -> Module -> ImportedMods -> [ImportUserSpec] -> NameSet
|
| 75 | 77 | -> [FilePath] -> [FilePath] -> [(Module, Fingerprint)] -> [LinkableUsage] -> PkgsLoaded
|
| ... | ... | @@ -100,10 +102,10 @@ mkUsageInfo uc plugins fc unit_env |
| 100 | 102 | }
|
| 101 | 103 | | (mod, hash) <- merged ]
|
| 102 | 104 | ++ object_usages
|
| 103 | - usages `seqList` return usages
|
|
| 104 | - -- seq the list of Usages returned: occasionally these
|
|
| 105 | - -- don't get evaluated for a while and we can end up hanging on to
|
|
| 106 | - -- the entire collection of Ifaces.
|
|
| 105 | + usages `seqList` return (sortBy stableUsageCmp usages)
|
|
| 106 | + -- The use of 'seqList' is important because occasionally the returned list
|
|
| 107 | + -- is not evaluated for a while, so that with too much laziness here we
|
|
| 108 | + -- could end up hanging on to the entire collection of 'Iface's.
|
|
| 107 | 109 | |
| 108 | 110 | {- Note [Plugin dependencies]
|
| 109 | 111 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 1 | 1 | {-# LANGUAGE PatternSynonyms #-}
|
| 2 | 2 | {-# LANGUAGE DerivingVia #-}
|
| 3 | + |
|
| 4 | +{-# OPTIONS_GHC -Wwarn=incomplete-record-selectors #-}
|
|
| 5 | + |
|
| 3 | 6 | -- | Dependencies and Usage of a module
|
| 4 | 7 | module GHC.Unit.Module.Deps
|
| 5 | 8 | ( Dependencies(dep_direct_mods
|
| ... | ... | @@ -17,6 +20,7 @@ module GHC.Unit.Module.Deps |
| 17 | 20 | , noDependencies
|
| 18 | 21 | , pprDeps
|
| 19 | 22 | , Usage (..)
|
| 23 | + , stableUsageCmp
|
|
| 20 | 24 | , HomeModImport (..)
|
| 21 | 25 | , HomeModImportedAvails (..)
|
| 22 | 26 | , ImportAvails (..)
|
| ... | ... | @@ -52,6 +56,7 @@ import GHC.Utils.Outputable |
| 52 | 56 | import Control.DeepSeq
|
| 53 | 57 | import Data.Bifunctor
|
| 54 | 58 | import qualified Data.Foldable as Foldable
|
| 59 | +import Data.Function (on)
|
|
| 55 | 60 | import Data.List (sortBy, sort, partition)
|
| 56 | 61 | import Data.Set (Set)
|
| 57 | 62 | import qualified Data.Set as Set
|
| ... | ... | @@ -497,6 +502,47 @@ instance Binary Usage where |
| 497 | 502 | |
| 498 | 503 | i -> error ("Binary.get(Usage): " ++ show i)
|
| 499 | 504 | |
| 505 | +-- | Compares 'Usage's by constructor and, if the constructors are the same, by
|
|
| 506 | +-- identifying strings, to achieve a predictable ordering.
|
|
| 507 | +stableUsageCmp :: Usage -> Usage -> Ordering
|
|
| 508 | +stableUsageCmp
|
|
| 509 | + usage1@UsagePackageModule {}
|
|
| 510 | + usage2@UsagePackageModule {}
|
|
| 511 | + = (compare `on` usg_mod) usage1 usage2
|
|
| 512 | +stableUsageCmp
|
|
| 513 | + usage1@UsageHomeModule {}
|
|
| 514 | + usage2@UsageHomeModule {}
|
|
| 515 | + = (compare `on` Module <$> usg_unit_id <*> usg_mod_name) usage1 usage2
|
|
| 516 | +stableUsageCmp
|
|
| 517 | + usage1@UsageFile {}
|
|
| 518 | + usage2@UsageFile {}
|
|
| 519 | + = (lexicalCompareFS `on` usg_file_path) usage1 usage2
|
|
| 520 | +stableUsageCmp
|
|
| 521 | + usage1@UsageDirectory {}
|
|
| 522 | + usage2@UsageDirectory {}
|
|
| 523 | + = (lexicalCompareFS `on` usg_dir_path) usage1 usage2
|
|
| 524 | +stableUsageCmp
|
|
| 525 | + usage1@UsageHomeModuleBytecode {}
|
|
| 526 | + usage2@UsageHomeModuleBytecode {}
|
|
| 527 | + = (compare `on` Module <$> usg_unit_id <*> usg_mod_name) usage1 usage2
|
|
| 528 | +stableUsageCmp
|
|
| 529 | + usage1@UsageMergedRequirement {}
|
|
| 530 | + usage2@UsageMergedRequirement {}
|
|
| 531 | + = (compare `on` usg_mod) usage1 usage2
|
|
| 532 | +stableUsageCmp
|
|
| 533 | + usage1
|
|
| 534 | + usage2
|
|
| 535 | + = (compare `on` constructorIndex) usage1 usage2
|
|
| 536 | + where
|
|
| 537 | + |
|
| 538 | + constructorIndex :: Usage -> Int
|
|
| 539 | + constructorIndex UsagePackageModule {} = 0
|
|
| 540 | + constructorIndex UsageHomeModule {} = 1
|
|
| 541 | + constructorIndex UsageFile {} = 2
|
|
| 542 | + constructorIndex UsageDirectory {} = 3
|
|
| 543 | + constructorIndex UsageHomeModuleBytecode {} = 4
|
|
| 544 | + constructorIndex UsageMergedRequirement {} = 5
|
|
| 545 | + |
|
| 500 | 546 | -- | Records the imports that we depend on from a home module,
|
| 501 | 547 | -- for recompilation checking.
|
| 502 | 548 | --
|