summaryrefslogtreecommitdiff
path: root/compiler/iface
diff options
context:
space:
mode:
authorDavid Feuer <david.feuer@gmail.com>2017-12-11 13:03:52 -0500
committerBen Gamari <ben@smart-cactus.org>2017-12-11 13:03:53 -0500
commit708ed9ca4dbf372817fe84a2fe486940123bddfb (patch)
tree30d67b789552b9f017674d4e9f2b6341cc75eede /compiler/iface
parentcafe98345cb5d4b11f2059d60d2f20e976ef4f2a (diff)
downloadhaskell-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.hs67
-rw-r--r--compiler/iface/LoadIface.hs2
-rw-r--r--compiler/iface/MkIface.hs45
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