diff options
| author | David Feuer <david.feuer@gmail.com> | 2017-12-11 13:03:52 -0500 |
|---|---|---|
| committer | Ben Gamari <ben@smart-cactus.org> | 2017-12-11 13:03:53 -0500 |
| commit | 708ed9ca4dbf372817fe84a2fe486940123bddfb (patch) | |
| tree | 30d67b789552b9f017674d4e9f2b6341cc75eede /compiler/iface | |
| parent | cafe98345cb5d4b11f2059d60d2f20e976ef4f2a (diff) | |
| download | haskell-708ed9ca4dbf372817fe84a2fe486940123bddfb.tar.gz | |
Allow users to ignore optimization changes
* Add a new flag, `-fignore-optim-changes`, allowing them to avoid
recompilation if the only changes are to the `-O` level or to
flags controlling optimizations.
* When `-fignore-optim-changes` is *off*, recompile when optimization
flags (e.g., `-fno-full-laziness`) change. Previously, we ignored
these unconditionally when deciding whether to recompile a module.
Reviewers: austin, bgamari, simonmar
Reviewed By: simonmar
Subscribers: duog, carter, simonmar, rwbarton, thomie
GHC Trac Issues: #13604
Differential Revision: https://phabricator.haskell.org/D4123
Diffstat (limited to 'compiler/iface')
| -rw-r--r-- | compiler/iface/FlagChecker.hs | 67 | ||||
| -rw-r--r-- | compiler/iface/LoadIface.hs | 2 | ||||
| -rw-r--r-- | compiler/iface/MkIface.hs | 45 |
3 files changed, 100 insertions, 14 deletions
diff --git a/compiler/iface/FlagChecker.hs b/compiler/iface/FlagChecker.hs index eb99c743e6..f81b2652e8 100644 --- a/compiler/iface/FlagChecker.hs +++ b/compiler/iface/FlagChecker.hs @@ -4,6 +4,8 @@ -- interface file as part of the recompilation checking infrastructure. module FlagChecker ( fingerprintDynFlags + , fingerprintOptFlags + , fingerprintHpcFlags ) where import GhcPrelude @@ -53,25 +55,45 @@ fingerprintDynFlags dflags@DynFlags{..} this_mod nameio = -- -fprof-auto etc. prof = if gopt Opt_SccProfilingOn dflags then fromEnum profAuto else 0 - -- -O, see https://ghc.haskell.org/trac/ghc/ticket/10923 - opt = if hscTarget == HscInterpreted || - hscTarget == HscNothing - then 0 - else optLevel + flags = (mainis, safeHs, lang, cpp, paths, prof) + in -- pprTrace "flags" (ppr flags) $ + computeFingerprint nameio flags + +-- Fingerprint the optimisation info. We keep this separate from the rest of +-- the flags because GHCi users (especially) may wish to ignore changes in +-- optimisation level or optimisation flags so as to use as many pre-existing +-- object files as they can. +-- See Note [Ignoring some flag changes] +fingerprintOptFlags :: DynFlags + -> (BinHandle -> Name -> IO ()) + -> IO Fingerprint +fingerprintOptFlags DynFlags{..} nameio = + let + -- See https://ghc.haskell.org/trac/ghc/ticket/10923 + -- We used to fingerprint the optimisation level, but as Joachim + -- Breitner pointed out in comment 9 on that ticket, it's better + -- to ignore that and just look at the individual optimisation flags. + opt_flags = map fromEnum $ filter (`EnumSet.member` optimisationFlags) + (EnumSet.toList generalFlags) + + in computeFingerprint nameio opt_flags + +-- Fingerprint the HPC info. We keep this separate from the rest of +-- the flags because GHCi users (especially) may wish to use an object +-- file compiled for HPC when not actually using HPC. +-- See Note [Ignoring some flag changes] +fingerprintHpcFlags :: DynFlags + -> (BinHandle -> Name -> IO ()) + -> IO Fingerprint +fingerprintHpcFlags dflags@DynFlags{..} nameio = + let -- -fhpc, see https://ghc.haskell.org/trac/ghc/ticket/11798 -- hpcDir is output-only, so we should recompile if it changes hpc = if gopt Opt_Hpc dflags then Just hpcDir else Nothing - -- -fignore-asserts, which affects how `Control.Exception.assert` works - ignore_asserts = gopt Opt_IgnoreAsserts dflags - - -- Nesting just to avoid ever more Binary tuple instances - flags = (mainis, safeHs, lang, cpp, paths, - (prof, opt, hpc, ignore_asserts)) + in computeFingerprint nameio hpc - in -- pprTrace "flags" (ppr flags) $ - computeFingerprint nameio flags {- Note [path flags and recompilation] @@ -102,3 +124,22 @@ recompilation check; here we explain why. The only path-related flag left is -hcsuf. -} + +{- Note [Ignoring some flag changes] + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Normally, --make tries to reuse only compilation products that are +the same as those that would have been produced compiling from +scratch. Sometimes, however, users would like to be more aggressive +about recompilation avoidance. This is particularly likely when +developing using GHCi (see #13604). Currently, we allow users to +ignore optimisation changes using -fignore-optim-changes, and to +ignore HPC option changes using -fignore-hpc-changes. If there's a +demand for it, we could also allow changes to -fprof-auto-* flags +(although we can't allow -prof flags to differ). The key thing about +these options is that we can still successfully link a library or +executable when some of its components differ in these ways. + +The way we accomplish this is to leave the optimization and HPC +options out of the flag hash, hashing them separately. +-} diff --git a/compiler/iface/LoadIface.hs b/compiler/iface/LoadIface.hs index b91d984b9a..b9a77598da 100644 --- a/compiler/iface/LoadIface.hs +++ b/compiler/iface/LoadIface.hs @@ -1020,6 +1020,8 @@ pprModIface iface , nest 2 (text "export-list hash:" <+> ppr (mi_exp_hash iface)) , nest 2 (text "orphan hash:" <+> ppr (mi_orphan_hash iface)) , nest 2 (text "flag hash:" <+> ppr (mi_flag_hash iface)) + , nest 2 (text "opt_hash:" <+> ppr (mi_opt_hash iface)) + , nest 2 (text "hpc_hash:" <+> ppr (mi_hpc_hash iface)) , nest 2 (text "sig of:" <+> ppr (mi_sig_of iface)) , nest 2 (text "used TH splices:" <+> ppr (mi_used_th iface)) , nest 2 (text "where") diff --git a/compiler/iface/MkIface.hs b/compiler/iface/MkIface.hs index a12cff2226..6d696d991c 100644 --- a/compiler/iface/MkIface.hs +++ b/compiler/iface/MkIface.hs @@ -4,6 +4,7 @@ -} {-# LANGUAGE CPP, NondecreasingIndentation #-} +{-# LANGUAGE MultiWayIf #-} -- | Module for constructing @ModIface@ values (interface files), -- writing them to disk and comparing two versions to see if @@ -279,6 +280,8 @@ mkIface_ hsc_env maybe_old_fingerprint mi_iface_hash = fingerprint0, mi_mod_hash = fingerprint0, mi_flag_hash = fingerprint0, + mi_opt_hash = fingerprint0, + mi_hpc_hash = fingerprint0, mi_exp_hash = fingerprint0, mi_used_th = used_th, mi_orphan_hash = fingerprint0, @@ -660,6 +663,10 @@ addFingerprints hsc_env mb_old_fingerprint iface0 new_decls -- the abi hash and one that should flag_hash <- fingerprintDynFlags dflags this_mod putNameLiterally + opt_hash <- fingerprintOptFlags dflags putNameLiterally + + hpc_hash <- fingerprintHpcFlags dflags putNameLiterally + -- the ABI hash depends on: -- - decls -- - export list @@ -695,6 +702,8 @@ addFingerprints hsc_env mb_old_fingerprint iface0 new_decls mi_exp_hash = export_hash, mi_orphan_hash = orphan_hash, mi_flag_hash = flag_hash, + mi_opt_hash = opt_hash, + mi_hpc_hash = hpc_hash, mi_orphan = not ( all ifRuleAuto orph_rules -- See Note [Orphans and auto-generated rules] && null orph_insts @@ -1200,6 +1209,10 @@ checkVersions hsc_env mod_summary iface then return (RecompBecause "-this-unit-id changed", Nothing) else do { ; recomp <- checkFlagHash hsc_env iface ; if recompileRequired recomp then return (recomp, Nothing) else do { + ; recomp <- checkOptimHash hsc_env iface + ; if recompileRequired recomp then return (recomp, Nothing) else do { + ; recomp <- checkHpcHash hsc_env iface + ; if recompileRequired recomp then return (recomp, Nothing) else do { ; recomp <- checkMergedSignatures mod_summary iface ; if recompileRequired recomp then return (recomp, Nothing) else do { ; recomp <- checkHsig mod_summary iface @@ -1223,7 +1236,7 @@ checkVersions hsc_env mod_summary iface ; updateEps_ $ \eps -> eps { eps_is_boot = mod_deps } ; recomp <- checkList [checkModUsage this_pkg u | u <- mi_usages iface] ; return (recomp, Just iface) - }}}}}} + }}}}}}}} where this_pkg = thisPackage (hsc_dflags hsc_env) -- This is a bit of a hack really @@ -1255,6 +1268,36 @@ checkFlagHash hsc_env iface = do (text " Module flags have changed") old_hash new_hash +-- | Check the optimisation flags haven't changed +checkOptimHash :: HscEnv -> ModIface -> IfG RecompileRequired +checkOptimHash hsc_env iface = do + let old_hash = mi_opt_hash iface + new_hash <- liftIO $ fingerprintOptFlags (hsc_dflags hsc_env) + putNameLiterally + if | old_hash == new_hash + -> up_to_date (text "Optimisation flags unchanged") + | gopt Opt_IgnoreOptimChanges (hsc_dflags hsc_env) + -> up_to_date (text "Optimisation flags changed; ignoring") + | otherwise + -> out_of_date_hash "Optimisation flags changed" + (text " Optimisation flags have changed") + old_hash new_hash + +-- | Check the HPC flags haven't changed +checkHpcHash :: HscEnv -> ModIface -> IfG RecompileRequired +checkHpcHash hsc_env iface = do + let old_hash = mi_hpc_hash iface + new_hash <- liftIO $ fingerprintHpcFlags (hsc_dflags hsc_env) + putNameLiterally + if | old_hash == new_hash + -> up_to_date (text "HPC flags unchanged") + | gopt Opt_IgnoreHpcChanges (hsc_dflags hsc_env) + -> up_to_date (text "HPC flags changed; ignoring") + | otherwise + -> out_of_date_hash "HPC flags changed" + (text " HPC flags have changed") + old_hash new_hash + -- Check that the set of signatures we are merging in match. -- If the -unit-id flags change, this can change too. checkMergedSignatures :: ModSummary -> ModIface -> IfG RecompileRequired |
