-
-\begin{code}
-mkFinalId :: IdSet -- The Ids with arity info from the code generator
- -> Bool -- True <=> recursive, so don't include unfolding
- -> Id
- -> CoreExpr -- The Id's right hand side
- -> (Id, IdSet) -- The emitted id, plus any *extra* needed Ids
-
-mkFinalId codegen_ids is_rec id rhs
- = (id `setIdInfo` new_idinfo, new_needed_ids)
- where
- core_idinfo = idInfo id
- stg_idinfo = case lookupVarSet codegen_ids id of
- Just id' -> idInfo id'
- Nothing -> pprTrace "ifaceBinds not found:" (ppr id) $
- idInfo id
-
- new_idinfo | opt_OmitInterfacePragmas
- = vanillaIdInfo
- | otherwise
- = core_idinfo `setArityInfo` arity_info
- `setCafInfo` cafInfo stg_idinfo
- `setUnfoldingInfo` unfold_info
- `setWorkerInfo` worker_info
- `setSpecInfo` emptyCoreRules
- -- We zap the specialisations because they are
- -- passed on separately through the modules IdCoreRules
-
- ------------ Arity --------------
- arity_info = arityInfo stg_idinfo
- stg_arity = arityLowerBound arity_info
-
- ------------ Worker --------------
- -- We only treat a function as having a worker if
- -- the exported arity (which is now the number of visible lambdas)
- -- is the same as the arity at the moment of the w/w split
- -- If so, we can safely omit the unfolding inside the wrapper, and
- -- instead re-generate it from the type/arity/strictness info
- -- But if the arity has changed, we just take the simple path and
- -- put the unfolding into the interface file, forgetting the fact
- -- that it's a wrapper.
- --
- -- How can this happen? Sometimes we get
- -- f = coerce t (\x y -> $wf x y)
- -- at the moment of w/w split; but the eta reducer turns it into
- -- f = coerce t $wf
- -- which is perfectly fine except that the exposed arity so far as
- -- the code generator is concerned (zero) differs from the arity
- -- when we did the split (2).
- --
- -- All this arises because we use 'arity' to mean "exactly how many
- -- top level lambdas are there" in interface files; but during the
- -- compilation of this module it means "how many things can I apply
- -- this to".
- worker_info = case workerInfo core_idinfo of
- info@(HasWorker work_id wrap_arity)
- | wrap_arity == stg_arity -> info
- | otherwise -> pprTrace "ifaceId: arity change:" (ppr id)
- NoWorker
- NoWorker -> NoWorker
-
- has_worker = case worker_info of
- HasWorker _ _ -> True
- other -> False
-
- HasWorker work_id _ = worker_info
-
- ------------ Unfolding --------------
- inline_pragma = inlinePragInfo core_idinfo
- dont_inline = isNeverInlinePrag inline_pragma
- loop_breaker = isLoopBreaker (occInfo core_idinfo)
- bottoming_fn = isBottomingStrictness (strictnessInfo core_idinfo)
-
- unfolding = mkTopUnfolding rhs
- rhs_is_small = neverUnfold unfolding
-
- unfold_info | show_unfold = unfolding
- | otherwise = noUnfolding
-
- show_unfold = not has_worker && -- Not unnecessary
- not bottoming_fn && -- Not necessary
- not dont_inline &&
- not loop_breaker &&
- rhs_is_small && -- Small enough
- okToUnfoldInHiFile rhs -- No casms etc
-
-
- ------------ Extra free Ids --------------
- new_needed_ids | opt_OmitInterfacePragmas = emptyVarSet
- | otherwise = worker_ids `unionVarSet`
- unfold_ids `unionVarSet`
- spec_ids
-
- spec_ids = filterVarSet interestingId (rulesRhsFreeVars (specInfo core_idinfo))
-
- worker_ids | has_worker && interestingId work_id = unitVarSet work_id
- -- Conceivably, the worker might come from
- -- another module
- | otherwise = emptyVarSet
-
- unfold_ids | show_unfold = find_fvs rhs
- | otherwise = emptyVarSet
-
- find_fvs expr = exprSomeFreeVars interestingId expr
-
-interestingId id = isId id && isLocallyDefined id && not (hasNoBinding id)
+ hpt = hsc_HPT hsc_env
+ pit = eps_PIT eps
+
+ import_all mod = case lookupModuleEnv dir_imp_mods mod of
+ Just (_,imp_all) -> imp_all
+ Nothing -> False
+
+ -- ent_map groups together all the things imported and used
+ -- from a particular module in this package
+ ent_map :: ModuleEnv [Name]
+ ent_map = foldNameSet add_mv emptyModuleEnv used_names
+ add_mv name mv_map = extendModuleEnv_C add_item mv_map mod [name]
+ where
+ mod = nameModule name
+ add_item names _ = name:names
+
+ -- We want to create a Usage for a home module if
+ -- a) we used something from; has something in used_names
+ -- b) we imported all of it, even if we used nothing from it
+ -- (need to recompile if its export list changes: export_vers)
+ -- c) is a home-package orphan module (need to recompile if its
+ -- instance decls change: rules_vers)
+ mkUsage :: ModuleName -> Maybe (Usage Name)
+ mkUsage mod_name
+ | isNothing maybe_iface -- We can't depend on it if we didn't
+ || not (isHomeModule mod) -- even open the interface!
+ || (null used_names
+ && not all_imported
+ && not orphan_mod)
+ = Nothing -- Record no usage info
+
+ | otherwise
+ = Just (Usage { usg_name = moduleName mod,
+ usg_mod = mod_vers,
+ usg_exports = export_vers,
+ usg_entities = ent_vers,
+ usg_rules = rules_vers })
+ where
+ maybe_iface = lookupIfaceByModName hpt pit mod_name
+ -- In one-shot mode, the interfaces for home-package
+ -- modules accumulate in the PIT not HPT. Sigh.
+
+ Just iface = maybe_iface
+ mod = mi_module iface
+ version_info = mi_version iface
+ orphan_mod = mi_orphan iface
+ version_env = vers_decls version_info
+ mod_vers = vers_module version_info
+ rules_vers = vers_rules version_info
+ all_imported = import_all mod
+ export_vers | all_imported = Just (vers_exports version_info)
+ | otherwise = Nothing
+
+ -- The sort is to put them into canonical order
+ used_names = lookupModuleEnv ent_map mod `orElse` []
+ ent_vers = [(n, lookupVersion version_env n)
+ | n <- sortLt lt_occ used_names ]
+ lt_occ n1 n2 = nameOccName n1 < nameOccName n2