diff --git a/compiler/Mercury.options b/compiler/Mercury.options index 9bbe2056a..b795fadc2 100644 --- a/compiler/Mercury.options +++ b/compiler/Mercury.options @@ -103,8 +103,6 @@ MCFLAGS-check_hlds.prop_mode_constraints += --no-warn-obsolete # Bug workarounds. -MCFLAGS-hlds.make_hlds.make_hlds_passes += --no-deforestation - # XXX work around a bug that sometimes appears at -O4 and above. # mmc -r analysis.file.c -s asm_fast.gc -O4 --intermodule-optimisation MCFLAGS-analysis.file += --no-optimise-higher-order diff --git a/compiler/check_for_missing_type_defns.m b/compiler/check_for_missing_type_defns.m index 9b014bb7d..fc89d0b28 100644 --- a/compiler/check_for_missing_type_defns.m +++ b/compiler/check_for_missing_type_defns.m @@ -62,9 +62,11 @@ check_for_missing_type_defns_in_type(TypeCtor, TypeDefn, !Specs) :- get_type_defn_body(TypeDefn, TypeBody), TypeBody = hlds_abstract_type(_) then - % We expect the builtin types character, float, int, uint and string to - % have abstract declarations with no definitions. The following types - % from the type_desc module also only have abstract declarations: + % We expect the builtin types character, float, int, uint and string + % to have abstract declarations with no definitions. + % + % The following types from the type_desc module also only have + % abstract declarations: % % - type_desc/0 % - pseudo_type_desc/0 @@ -80,7 +82,7 @@ check_for_missing_type_defns_in_type(TypeCtor, TypeDefn, !Specs) :- sym_name_get_module_name(SymName, ModuleName), not any_mercury_builtin_module(ModuleName), - % Several of the type defineds in type_desc do not have + % Several of the types defined in type_desc do not have % Mercury definitions. not ModuleName = unqualified("type_desc"), not list.member(TypeCtor, BuiltinTypeCtors), diff --git a/compiler/cse_detection.m b/compiler/cse_detection.m index 048c4b7ee..af8586913 100644 --- a/compiler/cse_detection.m +++ b/compiler/cse_detection.m @@ -1108,7 +1108,7 @@ update_existential_data_structures(FirstOldNew, LaterOldNews, !CseInfo) :- % rtti_varmaps, and apply the type substitution to the var_table. list.append(FirstOldNew, LaterOldNew, OldNew), map.from_assoc_list(OldNew, OldNewMap), - apply_substitutions_to_rtti_varmaps(Renaming, map.init, OldNewMap, + apply_renamings_and_subst_to_rtti_varmaps(Renaming, map.init, OldNewMap, RttiVarMaps0, RttiVarMaps), rename_vars_in_var_table(Renaming, VarTable0, VarTable), diff --git a/compiler/deforest.m b/compiler/deforest.m index ec66d3eea..341e894ab 100644 --- a/compiler/deforest.m +++ b/compiler/deforest.m @@ -128,10 +128,11 @@ deforest_module(ProgressStream, !ModuleInfo) :- % cost improvement of new versions a little more accurate and % also to avoid redoing optimizations. module_info_ensure_dependency_info(!ModuleInfo, DepInfo), - DepList = dependency_info_get_condensed_bottom_up_sccs(DepInfo), + BottomUpPredProcIds = + dependency_info_get_condensed_bottom_up_sccs(DepInfo), pd_info_init(ProgressStream, !.ModuleInfo, ProcArgInfo, PDInfo0), - list.foldl(deforest_proc, DepList, PDInfo0, PDInfo), + list.foldl(deforest_proc, BottomUpPredProcIds, PDInfo0, PDInfo), pd_info_get_module_info(PDInfo, !:ModuleInfo), module_info_clobber_dependency_info(!ModuleInfo), pd_info_get_versions(PDInfo, VersionIndex), @@ -210,6 +211,8 @@ deforest_proc(PredProcId, !PDInfo) :- deforest_proc_deltas(PredProcId, CostDelta, SizeDelta, !PDInfo) :- some [!ModuleInfo, !PredInfo, !ProcInfo, !Goal] ( + PredProcId = proc(PredId, ProcId), + pd_info_enter_pred(PredId, !PDInfo), pd_info_get_progress_stream(!.PDInfo, ProgressStream), pd_info_get_module_info(!.PDInfo, !:ModuleInfo), trace [io(!IO)] ( @@ -232,6 +235,10 @@ deforest_proc_deltas(PredProcId, CostDelta, SizeDelta, !PDInfo) :- "after constraints\n", !.Goal, !IO) ), deforest_goal(!Goal, !PDInfo), + trace [io(!IO)] ( + pd_debug_output_goal(!.PDInfo, "deforest_proc_deltas", + "after deforest_goal\n", !.Goal, !IO) + ), pd_info_get_proc_info(!.PDInfo, !:ProcInfo), proc_info_set_goal(!.Goal, !ProcInfo), pd_info_get_changed(!.PDInfo, Changed), @@ -241,11 +248,19 @@ deforest_proc_deltas(PredProcId, CostDelta, SizeDelta, !PDInfo) :- pd_info_get_module_info(!.PDInfo, !:ModuleInfo), requantify_proc_general(ord_nl_no_lambda, !ProcInfo), proc_info_get_goal(!.ProcInfo, !:Goal), + trace [io(!IO)] ( + pd_debug_output_goal(!.PDInfo, "deforest_proc_deltas", + "after requantify\n", !.Goal, !IO) + ), proc_info_get_initial_instmap(!.ModuleInfo, !.ProcInfo, InstMap0), proc_info_get_var_table(!.ProcInfo, VarTable), proc_info_get_inst_varset(!.ProcInfo, InstVarSet), recompute_instmap_delta(recomp_atomics, VarTable, InstVarSet, InstMap0, !Goal, !ModuleInfo), + trace [io(!IO)] ( + pd_debug_output_goal(!.PDInfo, "deforest_proc_deltas", + "after instmap deltas\n", !.Goal, !IO) + ), pd_info_set_module_info(!.ModuleInfo, !PDInfo), pd_info_get_pred_info(!.PDInfo, !:PredInfo), proc_info_set_goal(!.Goal, !ProcInfo), @@ -255,7 +270,6 @@ deforest_proc_deltas(PredProcId, CostDelta, SizeDelta, !PDInfo) :- ( RerunDet = yes, - PredProcId = proc(PredId, ProcId), % If the determinism of some sub-goals has changed, % then we re-run determinism analysis. As with inlining.m, % this avoids problems with inlining erroneous procedures. diff --git a/compiler/higher_order.make_specialized_preds.m b/compiler/higher_order.make_specialized_preds.m index 11f845341..81603b5c9 100644 --- a/compiler/higher_order.make_specialized_preds.m +++ b/compiler/higher_order.make_specialized_preds.m @@ -594,7 +594,7 @@ specialize_and_add_new_proc(NewPred, !.NewProcInfo, map.init(EmptyVarRenaming), % XXX1 See a XXX2 comment below about why this call is here. - apply_substitutions_to_rtti_varmaps(TypeRenaming, TypeSubn, + apply_renamings_and_subst_to_rtti_varmaps(TypeRenaming, TypeSubn, EmptyVarRenaming, RttiVarMaps0, RttiVarMaps1), % Add entries in the typeinfo_varmap for the extra typeinfos. diff --git a/compiler/hlds_out_goal.m b/compiler/hlds_out_goal.m index cacdac613..388cfdd2c 100644 --- a/compiler/hlds_out_goal.m +++ b/compiler/hlds_out_goal.m @@ -971,7 +971,7 @@ format_var_to_abs_locns(VarNameSrc, VarNamePrint, Indent, MaybeWidth = yes(Width), WidthStr = " " ++ Width ), - string.builder.format("%s%%\t%s\t-> %s%s\n", + string.builder.format("%s%% %s -> %s%s\n", [s(IndentStr), s(VarStr), s(LocnStr), s(WidthStr)], !State), format_var_to_abs_locns(VarNameSrc, VarNamePrint, Indent, VarLocs, !State). diff --git a/compiler/hlds_out_typeclass_table.m b/compiler/hlds_out_typeclass_table.m index b3f9e7347..6df459448 100644 --- a/compiler/hlds_out_typeclass_table.m +++ b/compiler/hlds_out_typeclass_table.m @@ -221,12 +221,19 @@ format_instance_defn(Info, InstanceDefn, !State) :- !State) ), - ConstraintStrs = - list.map(mercury_constraint_to_string(TVarSet, VarNamePrint), - Constraints), - ConstraintsStr = string.join_list(", ", ConstraintStrs), - string.builder.format("%s%% Constraints: %s\n", - [s(IndentStr), s(ConstraintsStr)], !State), + ( + Constraints = [], + string.builder.format("%s%% Constraints: none\n", + [s(IndentStr)], !State) + ; + Constraints = [_ | _], + ConstraintStrs = + list.map(mercury_constraint_to_string(TVarSet, VarNamePrint), + Constraints), + ConstraintsStr = string.join_list(", ", ConstraintStrs), + string.builder.format("%s%% Constraints: %s\n", + [s(IndentStr), s(ConstraintsStr)], !State) + ), ( Body = instance_body_abstract, diff --git a/compiler/hlds_rtti.m b/compiler/hlds_rtti.m index 94486b9b6..d5038813e 100644 --- a/compiler/hlds_rtti.m +++ b/compiler/hlds_rtti.m @@ -271,15 +271,16 @@ :- pred rtti_varmaps_rtti_prog_vars(rtti_varmaps::in, list(prog_var)::out) is det. - % apply_substitutions_to_rtti_varmaps(TRenaming, TSubst, Subst, + % apply_renamings_and_subst_to_rtti_varmaps(TRenaming, TSubst, Renaming, % !RttiVarMaps): % % Apply substitutions to the rtti_varmaps data. First apply TRenaming - % to all types, then apply TSubst to all types. Apply Subst to all + % to all types, then apply TSubst to all types. Apply Renaming to all % prog_vars. % -:- pred apply_substitutions_to_rtti_varmaps(tvar_renaming::in, tsubst::in, - prog_var_renaming::in, rtti_varmaps::in, rtti_varmaps::out) is det. +:- pred apply_renamings_and_subst_to_rtti_varmaps(tvar_renaming::in, + tsubst::in, prog_var_renaming::in, + rtti_varmaps::in, rtti_varmaps::out) is det. % rtti_varmaps_transform_types(Pred, !RttiVarMaps): % @@ -683,7 +684,8 @@ rtti_varmaps_rtti_prog_vars(RttiVarMaps, Vars) :- map.keys(RttiVarMaps ^ rv_tci_constraint_map, TCIVars), list.append(TIVars, TCIVars, Vars). -apply_substitutions_to_rtti_varmaps(TRenaming, TSubst, Subst, !RttiVarMaps) :- +apply_renamings_and_subst_to_rtti_varmaps(TRenaming, TSubst, Subst, + !RttiVarMaps) :- ( if % Optimize the simple case. map.is_empty(Subst), diff --git a/compiler/inlining.m b/compiler/inlining.m index 64a6d4865..082fd4f86 100644 --- a/compiler/inlining.m +++ b/compiler/inlining.m @@ -32,9 +32,9 @@ % It will not inline procedures which have a `:- pragma no_inline(name/arity).' % % If inlining a procedure takes the total number of variables over a given -% threshold (from a command-line option), then the procedure is not inlined -% - note that this means that some calls to a procedure may inlined while -% others are not. +% threshold (from a command-line option), then the procedure is not inlined. +% Note that this means that some calls to a procedure may be inlined +% while others are not. % % It builds the call-graph (if necessary) works from the bottom of the % call-graph towards the top, first performing inlining on a procedure, @@ -93,13 +93,14 @@ :- import_module io. :- import_module list. -:- import_module map. %---------------------------------------------------------------------------% :- pred inline_in_module(io.text_output_stream::in, module_info::in, module_info::out) is det. +%---------------------------------------------------------------------------% + % This heuristic is used for both local and intermodule inlining. % XXX No, it isn't; it is not used in this module. % The reason why I (zs) haven't moved it to intermod.m is that @@ -110,29 +111,32 @@ :- pred is_simple_goal(hlds_goal::in, int::in) is semidet. +%---------------------------------------------------------------------------% + % do_inline_call(ModuleInfo, UnivQVars, Context, - % CalleePredInfo, CalleeProcInfo, Args, Goal, + % CalleePredInfo, CalleeProcInfo, ArgVars, Goal, % !TVarSet, !VarTable, !RttiVarMaps): % % Given the universally quantified type variables in the caller's type, % the pred_info and proc_info for the called procedure, the context % and arguments to the call, and various information about the variables - % and types in the procedure currently being analysed, rename the goal - % for the called procedure so that it can be inlined. - % ZZZ + % and types in the procedure currently being analysed, return the + % body goal of the callee in a form where + % - its head variables have been replaced by ArgVars, + % - its variables have been renamed apart from the caller's variables, + % - the new variables been entered into the caller's TVarSet, VarTable, + % and RttiVarMaps. + % In other words, the returned Goal is the result of inlining + % the call to CalleeProcInfo with ArgVars. + % + % This predicate is exported to deforestation.m. % :- pred do_inline_call(module_info::in, list(tvar)::in, prog_context::in, pred_info::in, proc_info::in, list(prog_var)::in, hlds_goal::out, tvarset::in, tvarset::out, var_table::in, var_table::out, rtti_varmaps::in, rtti_varmaps::out) is det. - % rename_goal(CalledProcHeadVars, CallArgs, - % CallerVarTypes0, CalleeVarTypes, CallerVarTypes, - % VarRenaming, CalledGoal, RenamedGoal). - % -:- pred rename_goal(list(prog_var)::in, list(prog_var)::in, - var_table::in, var_table::in, var_table::out, - map(prog_var, prog_var)::out, hlds_goal::in, hlds_goal::out) is det. +%---------------------------------------------------------------------------% :- type may_inline_purity_promised_pred ---> may_not_inline_purity_promised_pred @@ -143,6 +147,8 @@ % % Determine whether a call to the given predicate can be inlined. % + % This predicate is exported to deforestation.m. + % :- pred can_inline_proc(module_info::in, pred_id::in, proc_id::in, builtin_state::in, may_inline_purity_promised_pred::in) is semidet. @@ -159,6 +165,9 @@ :- import_module hlds.goal_util. :- import_module hlds.hlds_dependency_graph. :- import_module hlds.hlds_markers. +:- import_module hlds.hlds_out. +:- import_module hlds.hlds_out.hlds_out_goal. +:- import_module hlds.hlds_out.hlds_out_util. :- import_module hlds.hlds_proc_util. :- import_module hlds.passes_aux. :- import_module hlds.pred_name. @@ -171,21 +180,25 @@ :- import_module libs.options. :- import_module mdbcomp. :- import_module mdbcomp.sym_name. +:- import_module parse_tree.parse_tree_out_info. :- import_module parse_tree.prog_data_foreign. :- import_module parse_tree.prog_data_pragma. :- import_module parse_tree.prog_type. :- import_module parse_tree.prog_type_unify. :- import_module parse_tree.set_of_var. +:- import_module parse_tree.var_db. :- import_module transform_hlds.complexity. :- import_module transform_hlds.dead_proc_elim. :- import_module bool. :- import_module int. +:- import_module map. :- import_module maybe. :- import_module multi_map. :- import_module pair. :- import_module require. :- import_module set. +:- import_module string. :- import_module term. :- import_module varset. @@ -195,9 +208,11 @@ % inlining process. Most (but not all) of these fields hold the % values of compiler invocation options. % + % After construction, the whole inline_params structure is read-only. :- type inline_params ---> inline_params( ip_progress_stream :: io.text_output_stream, + ip_debug_pred_id :: maybe(int), ip_simple :: maybe_inline_simple, ip_single_use :: maybe_inline_single_use, @@ -301,10 +316,12 @@ inline_in_module(ProgressStream, !ModuleInfo) :- % - the threshold for determining whether to inline the simple conj's % - the upper limit on the number of variables we want in procedures; % if inlining a procedure would cause the number of variables to exceed - % this threshold then we don't inline it. - % - whether we're in an MLDS grade + % this threshold then we do not inline it. + % - whether we are in an MLDS grade module_info_get_globals(!.ModuleInfo, Globals), + globals.lookup_maybe_int_option(Globals, debug_inline_pred_id, + MaybeDebugPredId), globals.get_opt_tuple(Globals, OptTuple), Simple = OptTuple ^ ot_inline_simple, SingleUse = OptTuple ^ ot_inline_single_use, @@ -325,13 +342,14 @@ inline_in_module(ProgressStream, !ModuleInfo) :- else map.init(NeededMap) ), - Params = inline_params(ProgressStream, Simple, SingleUse, HighLevelCode, + Params = inline_params(ProgressStream, MaybeDebugPredId, + Simple, SingleUse, HighLevelCode, CallCost, CompoundThreshold, SimpleThreshold, VarThreshold, NeededMap), % Build the call graph and extract the list of SCCs. We process % SCCs bottom up, so that if a caller wants to inline a callee % in a lower SCC, it gets the *already optimized* version of the callee. - % We don't try to do anything special about calls where the callee + % We do not try to do anything special about calls where the callee % is in the *same* SCC as the caller. module_info_ensure_dependency_info(!ModuleInfo, DepInfo), @@ -470,7 +488,7 @@ should_proc_be_inlined(Params, ModuleInfo, PredProcId) :- Needed = maybe_eliminable(NumUses), NumUses = 1 ), - % Don't inline directly recursive predicates unless explicitly requested. + % Do not inline directly recursive predicates unless explicitly requested. not goal_calls(CalledGoal, PredProcId), pred_info_get_origin(PredInfo, Origin), @@ -487,7 +505,7 @@ is_simple_clause_list(Clauses, SimpleThreshold) :- % For flat goals, we are more likely to be able to optimize stuff away, % so we use a higher threshold. - % XXX This should be a separate option, we shouldn't hardcode + % XXX This should be a separate option, we should not hardcode % the number `3' (which is just a guess). is_flat_simple_goal(Goal) @@ -500,7 +518,7 @@ is_simple_goal(CalledGoal, SimpleThreshold) :- ; % For flat goals, we are more likely to be able to optimize stuff away, % so we use a higher threshold. - % XXX this should be a separate option, we shouldn't hardcode + % XXX this should be a separate option, we should not hardcode % the number `3' (which is just a guess). Size < SimpleThreshold * 3, @@ -574,9 +592,24 @@ inline_in_proc(Params, ShouldInlineProcs, ShouldInlineTailProcs, PredProcId, PredProcId = proc(PredId, ProcId), + MaybeDebugPredId = Params ^ ip_debug_pred_id, + ( if + MaybeDebugPredId = yes(DebugPredId), + pred_id_to_int(PredId) = DebugPredId + then + MaybeDebugStream = yes(Params ^ ip_progress_stream) + else + MaybeDebugStream = no + ), + module_info_pred_info(!.ModuleInfo, PredId, !:PredInfo), pred_info_proc_info(!.PredInfo, ProcId, !:ProcInfo), + trace [io(!IO)] ( + maybe_dump_proc_goal(MaybeDebugStream, "start", yes(PredId), + !.ModuleInfo, !.PredInfo, !.ProcInfo, !IO) + ), + pred_info_get_univ_quant_tvars(!.PredInfo, UnivQTVars), pred_info_get_typevarset(!.PredInfo, TypeVarSet0), @@ -602,6 +635,11 @@ inline_in_proc(Params, ShouldInlineProcs, ShouldInlineTailProcs, PredProcId, proc_info_set_rtti_varmaps(RttiVarMaps, !ProcInfo), proc_info_set_goal(Goal, !ProcInfo), + trace [io(!IO)] ( + maybe_dump_proc_goal(MaybeDebugStream, "inlined", no, + !.ModuleInfo, !.PredInfo, !.ProcInfo, !IO) + ), + ( InlinedParallel = we_have_inlined_parallel_conj, proc_info_set_has_parallel_conj(has_parallel_conj, !ProcInfo) @@ -619,7 +657,12 @@ inline_in_proc(Params, ShouldInlineProcs, ShouldInlineTailProcs, PredProcId, % generate those caller variables can be optimized away. requantify_proc_general(ord_nl_no_lambda, !ProcInfo), recompute_instmap_delta_proc(recomp_atomics, - !ProcInfo, !ModuleInfo) + !ProcInfo, !ModuleInfo), + + trace [io(!IO)] ( + maybe_dump_proc_goal(MaybeDebugStream, "instmap_deltas", no, + !.ModuleInfo, !.PredInfo, !.ProcInfo, !IO) + ) ; DidInlining = we_have_not_inlined ), @@ -628,7 +671,13 @@ inline_in_proc(Params, ShouldInlineProcs, ShouldInlineTailProcs, PredProcId, ( PurityChanged = have_changed_purity, - repuritycheck_proc(!.ModuleInfo, PredProcId, !PredInfo) + repuritycheck_proc(!.ModuleInfo, PredProcId, !PredInfo), + + trace [io(!IO)] ( + pred_info_proc_info(!.PredInfo, ProcId, PurityProcInfo), + maybe_dump_proc_goal(MaybeDebugStream, "repuritycheck", no, + !.ModuleInfo, !.PredInfo, PurityProcInfo, !IO) + ) ; PurityChanged = have_not_changed_purity ), @@ -642,12 +691,49 @@ inline_in_proc(Params, ShouldInlineProcs, ShouldInlineTailProcs, PredProcId, DetChanged = may_have_changed_detism, ProgressStream = Params ^ ip_progress_stream, det_infer_proc_ignore_msgs(ProgressStream, PredId, ProcId, - !ModuleInfo) + !ModuleInfo), + + trace [io(!IO)] ( + module_info_pred_proc_info(!.ModuleInfo, PredId, ProcId, + DetPredInfo, DetProcInfo), + maybe_dump_proc_goal(MaybeDebugStream, "det_infer_proc", no, + !.ModuleInfo, DetPredInfo, DetProcInfo, !IO) + ) ; DetChanged = have_not_changed_detism ) ). +:- pred maybe_dump_proc_goal(maybe(io.text_output_stream)::in, string::in, + maybe(pred_id)::in, module_info::in, pred_info::in, proc_info::in, + io::di, io::uo) is det. + +maybe_dump_proc_goal(MaybeDebugStream, Desc, MaybePredId, ModuleInfo, + PredInfo, ProcInfo, !IO) :- + ( + MaybeDebugStream = no + ; + MaybeDebugStream = yes(DebugStream), + ( + MaybePredId = no, + io.format(DebugStream, "\n%s:\n", [s(Desc)], !IO) + ; + MaybePredId = yes(PredId), + io.format(DebugStream, "\n%s for pred id %d:\n", + [s(Desc), i(pred_id_to_int(PredId))], !IO) + ), + module_info_get_globals(ModuleInfo, Globals), + OutInfo = init_hlds_out_info(Globals, output_debug), + proc_info_get_var_table(ProcInfo, VarTable), + pred_info_get_typevarset(PredInfo, TVarSet), + proc_info_get_inst_varset(ProcInfo, InstVarSet), + proc_info_get_goal(ProcInfo, Goal), + write_goal_nl(OutInfo, DebugStream, ModuleInfo, + vns_var_table(VarTable), print_name_and_num, TVarSet, InstVarSet, + 1u, "\n", Goal, !IO), + io.flush_output(DebugStream, !IO) + ). + %---------------------------------------------------------------------------% :- pred inlining_in_goal(hlds_goal::in, hlds_goal::out, @@ -928,10 +1014,10 @@ do_inline_call(ModuleInfo, ExternalTypeParams, CallContext, % either for the caller or callee, since for any type vars in the % callee which get bound to type vars in the caller, the type_info % location will be given by the entry in the caller's type_info - % locations map (and vice versa). It doesn't matter if the final + % locations map (and vice versa). It does not matter if the final % type_info locations map contains some entries for type variables % which have been substituted away, because those entries simply - % won't be used. + % will not be used. lookup_var_types(CalleeVarTable1, HeadVars, HeadTypes), lookup_var_types(VarTable0, ArgVars, ArgTypes), @@ -956,26 +1042,34 @@ do_inline_call(ModuleInfo, ExternalTypeParams, CallContext, ), % Now rename apart the variables in the called goal. - rename_goal(HeadVars, ArgVars, VarTable1, CalleeVarTable, VarTable, - Subn, CalleeBodyGoal, Goal0), + rename_vars_in_goal(HeadVars, ArgVars, VarTable1, CalleeVarTable, VarTable, + Renaming, CalleeBodyGoal, Goal0), goal_set_context(CallContext, Goal0, Goal), - apply_substitutions_to_rtti_varmaps(TypeRenaming, TypeSubn, Subn, + apply_renamings_and_subst_to_rtti_varmaps(TypeRenaming, TypeSubn, Renaming, CalleeRttiVarMaps0, CalleeRttiVarMaps1), % Prefer the type_info_locn from the caller. % The type_infos or typeclass_infos passed to the callee may have been % produced by extracting type_infos or typeclass_infos from - % typeclass_infos in the caller, so they won't necessarily be the same. + % typeclass_infos in the caller, so they will not necessarily be the same. rtti_varmaps_overlay(CalleeRttiVarMaps1, RttiVarMaps0, RttiVarMaps). -rename_goal(HeadVars, ArgVars, VarTable0, CalleeVarTable, VarTable, - Renaming, CalledGoal, Goal) :- + % rename_vars_in_goal(CalledProcHeadVars, CallArgs, + % CallerVarTypes0, CalleeVarTypes, CallerVarTypes, + % VarRenaming, CalledGoal, RenamedGoal). + % +:- pred rename_vars_in_goal(list(prog_var)::in, list(prog_var)::in, + var_table::in, var_table::in, var_table::out, + prog_var_renaming::out, hlds_goal::in, hlds_goal::out) is det. + +rename_vars_in_goal(HeadVars, ArgVars, VarTable0, CalleeVarTable, VarTable, + Renaming, CalleeBodyGoal, Goal) :- map.from_corresponding_lists(HeadVars, ArgVars, Renaming0), var_table_vars(CalleeVarTable, CalleeListOfVars), clone_variables(CalleeListOfVars, CalleeVarTable, VarTable0, VarTable, Renaming0, Renaming), - must_rename_vars_in_goal(Renaming, CalledGoal, Goal). + must_rename_vars_in_goal(Renaming, CalleeBodyGoal, Goal). %---------------------------------------------------------------------------% @@ -994,7 +1088,7 @@ rename_goal(HeadVars, ArgVars, VarTable0, CalleeVarTable, VarTable, % Check to see if we should inline the callee at a call site. % % Returns should_not_inline if the called predicate cannot be inlined, - % e.g. because it is a builtin, we don't have code for it, etc, + % e.g. because it is a builtin, we do not have code for it, etc, % or if the callee is simply not in the set of procedures % that we have earlier decided we should inline. % @@ -1048,6 +1142,8 @@ should_inline_at_call_site(Info, GoalExpr0, GoalInfo0, ShouldInline) :- ShouldInline = should_not_inline ). +%---------------------------------------------------------------------------% + can_inline_proc(ModuleInfo, PredId, ProcId, BuiltinState, MayInlinePromisedPure) :- module_info_get_globals(ModuleInfo, Globals), @@ -1061,11 +1157,11 @@ can_inline_proc(ModuleInfo, PredId, ProcId, BuiltinState, can_inline_proc_2(ModuleInfo, PredId, ProcId, BuiltinState, HighLevelCode, MayInlinePurityPromisedPred) :- - % Don't inline builtins, the code generator will handle them. + % Do not inline builtins; the code generator will handle them. BuiltinState = not_builtin, module_info_pred_proc_info(ModuleInfo, PredId, ProcId, PredInfo, ProcInfo), - % Don't try to inline imported predicates, since we don't + % Do not try to inline imported predicates, since we do not % have the code for them. not pred_info_is_imported(PredInfo), @@ -1077,15 +1173,15 @@ can_inline_proc_2(ModuleInfo, PredId, ProcId, BuiltinState, HighLevelCode, ), % Only try to inline procedures which are evaluated using normal - % evaluation. Currently we can't inline procs evaluated using any of the + % evaluation. Currently we cannot inline procs evaluated using any of the % other methods because the code generator for the methods can only handle % whole procedures not code fragments. proc_info_get_eval_method(ProcInfo, eval_normal), - % Don't inline anything we have been specifically requested not to inline. + % Do not inline anything we have been specifically requested not to inline. not pred_info_requested_no_inlining(PredInfo), - % Don't inline any procedure whose complexity we are trying to determine, + % Do not inline any procedure whose complexity we are trying to determine, % since the complexity transformation can't transform *part* of a % procedure. module_info_get_maybe_complexity_proc_map(ModuleInfo, @@ -1114,7 +1210,7 @@ can_inline_proc_2(ModuleInfo, PredId, ProcId, BuiltinState, HighLevelCode, ok_to_inline_language(ForeignLanguage, Target) ), - % Don't inline a foreign_proc if it is has been marked with the + % Do not inline a foreign_proc if it is has been marked with the % attribute that requests the code not be duplicated. ( MaybeMayDuplicate = get_may_duplicate(ForeignAttributes) @@ -1143,7 +1239,7 @@ can_inline_proc_2(ModuleInfo, PredId, ProcId, BuiltinState, HighLevelCode, ( MayInlinePurityPromisedPred = may_inline_purity_promised_pred ; - % For some optimizations (such as deforestation) we don't want to + % For some optimizations (such as deforestation) we do not want to % inline predicates which are promised pure because the extra impurity % propagated through the goal will defeat any attempts at optimization. % diff --git a/compiler/modecheck_coerce.m b/compiler/modecheck_coerce.m index b62821f6d..c682381fd 100644 --- a/compiler/modecheck_coerce.m +++ b/compiler/modecheck_coerce.m @@ -162,7 +162,7 @@ modecheck_coerce_vars(ModuleInfo0, X, Y, TypeX, TypeY, InstX, InstY, Result, modecheck_set_var_inst(X, FinalInstX, no, !ModeInfo), ModeX = from_to_mode(InstX, FinalInstX), ( if inst_is_free(ModuleInfo, InstY) then - % Y is free so bind the coercion result to Y. + % Y is free, so bind the coercion result to Y. modecheck_set_var_inst(Y, FinalInstY, no, !ModeInfo), ModeY = from_to_mode(InstY, FinalInstY), Result = coerce_mode_ok([X, Y], [ModeX, ModeY], no_extra_goals) @@ -376,7 +376,8 @@ modecheck_coerce_from_bound_make_bound_functor(ModuleInfo, TVarSet, LiveX, inst_result_contains_types_unknown, inst_result_no_type_ctor_propagated ), - InstY = bound(UniqY, InstResults, BoundFunctorsY), + list.sort(BoundFunctorsY, SortedBoundFunctorsY), + InstY = bound(UniqY, InstResults, SortedBoundFunctorsY), Result = ok1(InstY) ; DeeperErrors = [_ | _], @@ -836,7 +837,8 @@ modecheck_coerce_from_ground_make_bound_inst(ModuleInfo, TVarSet, inst_result_contains_types_unknown, inst_result_no_type_ctor_propagated ), - InstY = bound(UniqY, InstResults, BoundFunctorsY). + list.sort(BoundFunctorsY, SortedBoundFunctorsY), + InstY = bound(UniqY, InstResults, SortedBoundFunctorsY). :- pred modecheck_coerce_from_ground_make_bound_functor(module_info::in, tvarset::in, is_live::in, uniqueness::in, set(mer_type)::in, diff --git a/compiler/options.m b/compiler/options.m index 8bfd7eeff..c2323bd86 100644 --- a/compiler/options.m +++ b/compiler/options.m @@ -374,6 +374,7 @@ % Verbosity options ; verbose ; very_verbose + ; very_verbose_pred_ids ; statistics ; verbose_make ; output_compile_error_lines @@ -1135,7 +1136,9 @@ ; debug_term % term = constraint termination analysis ; debug_dead_proc_elim ; debug_higher_order_specialization + ; debug_inline_pred_id ; debug_pd % pd = partial deduction/deforestation + ; debug_pd_pred_id ; debug_indirect_reuse ; debug_trail_usage ; debug_unneeded_code @@ -2321,6 +2324,15 @@ optdb(oc_verbosity, verbose, bool(no), optdb(oc_verbosity, very_verbose, bool(no), short_help('V', "very-verbose", [], [ w("Output very verbose progress messages.")])). +optdb(oc_verbosity, very_verbose_pred_ids, bool(no), + priv_help("very-verbose-pred-ids", [ + w("Output very verbose progress messages, including"), + % So far, there has been no need for this with MLDS target code, + % but it could be easily added. + w("pred ids, when generating LLDS target code."), + w("This can be helpful when a problem occurs"), + w("when generating code for a compiler transformed predicate,"), + w("whose names are not fully printed with -V.")])). optdb(oc_verbosity, statistics, bool(no), short_help('S', "statistics", [], [ w("Output messages about the compiler's time/space usage"), @@ -5839,10 +5851,18 @@ optdb(oc_dev_verb, debug_higher_order_specialization, bool(no), priv_help("debug-higher-order-specialization", [ w("Output messages about the procedure specializations done"), w("by higher_order.m.")])). +optdb(oc_dev_verb, debug_inline_pred_id, maybe_int(no), + priv_arg_help("debug-inline-pred-id", "predid", [ + w("Output detailed debugging traces of the inlining process,"), + w("but only for the given pred id.")])). optdb(oc_dev_verb, debug_pd, bool(no), priv_help("debug-pd", [ w("Output detailed debugging traces of the partial deduction"), w("and deforestation process.")])). +optdb(oc_dev_verb, debug_pd_pred_id, maybe_int(no), + priv_arg_help("debug-pd-pred-id", "predid", [ + w("Output detailed debugging traces of the partial deduction"), + w("and deforestation process, but only for the given pred id.")])). optdb(oc_dev_verb, debug_indirect_reuse, bool(no), priv_help("debug-indirect-reuse", [ w("Output detailed debugging traces of the indirect reuse pass"), diff --git a/compiler/par_loop_control.m b/compiler/par_loop_control.m index dd0da0de9..5b0247644 100644 --- a/compiler/par_loop_control.m +++ b/compiler/par_loop_control.m @@ -1364,7 +1364,7 @@ update_outer_proc(PredProcId, InnerPredProcId, InnerPredName, ModuleInfo, % Fix rtti varmaps. proc_info_get_rtti_varmaps(!.ProcInfo, RttiVarmaps0), - apply_substitutions_to_rtti_varmaps(map.init, map.init, Remap, + apply_renamings_and_subst_to_rtti_varmaps(map.init, map.init, Remap, RttiVarmaps0, RttiVarmaps), proc_info_set_rtti_varmaps(RttiVarmaps, !ProcInfo), diff --git a/compiler/parse_tree_out_inst.m b/compiler/parse_tree_out_inst.m index a5cfb055f..627dfac68 100644 --- a/compiler/parse_tree_out_inst.m +++ b/compiler/parse_tree_out_inst.m @@ -179,7 +179,19 @@ mercury_format_inst(Lang, InstVarSet, Inst, S, !U) :- mercury_format_uniqueness(Uniq, "bound", S, !U), add_string("(", S, !U), mercury_format_bound_functors(Lang, InstVarSet, BoundFunctors, S, !U), - add_string(")", S, !U) + add_string(")", S, !U), + ( if + Lang = output_debug, + list.sort(BoundFunctors, SortedBoundFunctors), + BoundFunctors \= SortedBoundFunctors + then + add_string("\nSHOULD HAVE BEEN SORTED AS (", S, !U), + mercury_format_bound_functors(Lang, InstVarSet, + SortedBoundFunctors, S, !U), + add_string(")", S, !U) + else + true + ) ; Inst = ground(Uniq, HOInstInfo), ( diff --git a/compiler/pd_info.m b/compiler/pd_info.m index 4070c6c12..00a5fe6f6 100644 --- a/compiler/pd_info.m +++ b/compiler/pd_info.m @@ -53,6 +53,8 @@ :- pred pd_info_init(io.text_output_stream::in, module_info::in, pd_arg_info::in, pd_info::out) is det. +:- pred pd_info_enter_pred(pred_id::in, pd_info::in, pd_info::out) is det. + :- pred pd_info_init_unfold_info(pred_proc_id::in, pred_info::in, proc_info::in, pd_info::in, pd_info::out) is det. @@ -136,9 +138,10 @@ ---> pd_info( % Read-only fields. pdi_progress_stream :: io.text_output_stream, - pdi_maybe_debug_stream :: maybe(io.text_output_stream), + pdi_what_to_debug :: pd_what_to_debug, % Writeable fields. + pdi_maybe_debug_stream :: maybe(io.text_output_stream), pdi_module_info :: module_info, pdi_maybe_unfold_info :: maybe(unfold_info), pdi_goal_version_index :: goal_version_index, @@ -152,18 +155,36 @@ pdi_useless_versions :: useless_versions ). +:- type pd_what_to_debug + ---> pd_no_debug + % Do not generate debug info for any procedure. + ; pd_only_debug(int) + % Generate debug info only procedures in the predicate + % with this pred_id. + ; pd_debug_all. + % Generate debug info for all procedures. + %---------------------------------------------------------------------------% pd_info_init(ProgressStream, ModuleInfo, ProcArgInfos, PDInfo) :- module_info_get_globals(ModuleInfo, Globals), + globals.lookup_maybe_int_option(Globals, debug_pd_pred_id, + MaybeDebugPDPredId), globals.lookup_bool_option(Globals, debug_pd, DebugPD), ( - DebugPD = no, - MaybeDebugStream = maybe.no + MaybeDebugPDPredId = yes(DebugPDPredId), + WhatToDebug = pd_only_debug(DebugPDPredId) ; - DebugPD = yes, - MaybeDebugStream = maybe.yes(ProgressStream) + MaybeDebugPDPredId = no, + ( + DebugPD = no, + WhatToDebug = pd_no_debug + ; + DebugPD = yes, + WhatToDebug = pd_debug_all + ) ), + MaybeDebugStream = maybe.no, MaybeUnfoldInfo = maybe.no, map.init(GoalVersionIndex), map.init(Versions), @@ -172,11 +193,30 @@ pd_info_init(ProgressStream, ModuleInfo, ProcArgInfos, PDInfo) :- Depth = 0, set.init(CreatedVersions), set.init(UselessVersions), - PDInfo = pd_info(ProgressStream, MaybeDebugStream, ModuleInfo, + PDInfo = pd_info(ProgressStream, WhatToDebug, MaybeDebugStream, ModuleInfo, MaybeUnfoldInfo, GoalVersionIndex, Versions, ProcArgInfos, counter.init(0), GlobalTermInfo, ParentVersions, Depth, CreatedVersions, UselessVersions). +pd_info_enter_pred(PredId, !PDInfo) :- + WhatToDebug = !.PDInfo ^ pdi_what_to_debug, + ( + WhatToDebug = pd_no_debug, + !PDInfo ^ pdi_maybe_debug_stream := no + ; + WhatToDebug = pd_only_debug(DebugPredId), + ( if pred_id_to_int(PredId) = DebugPredId then + ProgressStream = !.PDInfo ^ pdi_progress_stream, + !PDInfo ^ pdi_maybe_debug_stream := yes(ProgressStream) + else + !PDInfo ^ pdi_maybe_debug_stream := no + ) + ; + WhatToDebug = pd_debug_all, + ProgressStream = !.PDInfo ^ pdi_progress_stream, + !PDInfo ^ pdi_maybe_debug_stream := yes(ProgressStream) + ). + pd_info_init_unfold_info(PredProcId, PredInfo, ProcInfo, !PDInfo) :- pd_info_get_module_info(!.PDInfo, ModuleInfo), proc_info_get_argmodes(ProcInfo, ArgModes), diff --git a/compiler/proc_gen.m b/compiler/proc_gen.m index 22040d0ae..7608089b6 100644 --- a/compiler/proc_gen.m +++ b/compiler/proc_gen.m @@ -124,7 +124,12 @@ generate_module_code(ProgressStream, ModuleInfo, CProcs, !GlobalData) :- % Check if we want to use parallel code generation. module_info_get_globals(ModuleInfo, Globals), globals.lookup_bool_option(Globals, parallel_code_gen, ParallelCodeGen), - globals.lookup_bool_option(Globals, very_verbose, VeryVerbose), + globals.lookup_bool_option(Globals, very_verbose, VeryVerbose0), + globals.lookup_bool_option(Globals, very_verbose_pred_ids, + VeryVerbosePredIds), + ( VeryVerbosePredIds = no, VeryVerbose = VeryVerbose0 + ; VeryVerbosePredIds = yes, VeryVerbose = yes + ), globals.lookup_bool_option(Globals, detailed_statistics, Statistics), ( @@ -151,21 +156,25 @@ generate_module_code(ProgressStream, ModuleInfo, CProcs, !GlobalData) :- generate_module_code_par(ProgressStream, ModuleInfo, ConstStructMap, PredIds, CProcsCord, !GlobalData) else - generate_module_code_seq(ProgressStream, VeryVerbose, Statistics, + generate_module_code_seq(ProgressStream, + VeryVerbose, VeryVerbosePredIds, Statistics, ModuleInfo, ConstStructMap, PredIds, CProcsCord, !GlobalData) ), CProcs = cord.list(CProcsCord). %---------------------% -:- pred generate_module_code_seq(io.text_output_stream::in, bool::in, bool::in, +:- pred generate_module_code_seq(io.text_output_stream::in, + bool::in, bool::in, bool::in, module_info::in, const_struct_map::in, list(pred_id)::in, cord(c_procedure)::out, global_data::in, global_data::out) is det. -generate_module_code_seq(ProgressStream, VeryVerbose, Statistics, +generate_module_code_seq(ProgressStream, + VeryVerbose, VeryVerbosePredIds, Statistics, ModuleInfo, ConstStructMap, PredIds, CProcsCord, !GlobalData) :- list.foldl2( - generate_code_for_pred(ProgressStream, VeryVerbose, Statistics, + generate_code_for_pred(ProgressStream, + VeryVerbose, VeryVerbosePredIds, Statistics, ModuleInfo, ConstStructMap), PredIds, cord.init, CProcsCord, !GlobalData). @@ -208,7 +217,7 @@ generate_module_code_par(ProgressStream, ModuleInfo, ConstStructMap, ( list.condense(ListsOfPredIdsA, PredIdsA), list.foldl2( - generate_code_for_pred(ProgressStream, no, no, + generate_code_for_pred(ProgressStream, no, no, no, ModuleInfo, ConstStructMap), PredIdsA, cord.init, CProcsCordA, GlobalData0, GlobalDataA) % XXX the following should be a parallel conjunction @@ -216,7 +225,7 @@ generate_module_code_par(ProgressStream, ModuleInfo, ConstStructMap, list.condense(ListsOfPredIdsB, PredIdsB), bump_type_num_counter(type_num_skip, GlobalData0, GlobalData1), list.foldl2( - generate_code_for_pred(ProgressStream, no, no, + generate_code_for_pred(ProgressStream, no, no, no, ModuleInfo, ConstStructMap), PredIdsB, cord.init, CProcsCordB0, GlobalData1, GlobalDataB) ), @@ -249,12 +258,14 @@ interleave_loop([H | T], RevAs0, RevAs, RevBs0, RevBs) :- %---------------------------------------------------------------------------% -:- pred generate_code_for_pred(io.text_output_stream::in, bool::in, bool::in, +:- pred generate_code_for_pred(io.text_output_stream::in, + bool::in, bool::in, bool::in, module_info::in, const_struct_map::in, pred_id::in, cord(c_procedure)::in, cord(c_procedure)::out, global_data::in, global_data::out) is det. -generate_code_for_pred(ProgressStream, VeryVerbose, Statistics, ModuleInfo, +generate_code_for_pred(ProgressStream, + VeryVerbose, VeryVerbosePredIds, Statistics, ModuleInfo, ConstStructMap, PredId, !CProcsCord, !GlobalData) :- module_info_pred_info(ModuleInfo, PredId, PredInfo), ProcIds = pred_info_will_codegen_proc_ids(PredInfo), @@ -265,8 +276,18 @@ generate_code_for_pred(ProgressStream, VeryVerbose, Statistics, ModuleInfo, ( VeryVerbose = yes, trace [io(!IO)] ( - io.format(ProgressStream, "%% Generating code for %s\n", - [s(pred_id_to_user_string(ModuleInfo, PredId))], !IO) + ( + VeryVerbosePredIds = no, + io.format(ProgressStream, + "%% Generating code for %s\n", + [s(pred_id_to_user_string(ModuleInfo, PredId))], !IO) + ; + VeryVerbosePredIds = yes, + io.format(ProgressStream, + "%% Generating code for %s (%d)\n", + [s(pred_id_to_user_string(ModuleInfo, PredId)), + i(pred_id_to_int(PredId))], !IO) + ) ), ( TailProcIds = [], diff --git a/compiler/prog_data.m b/compiler/prog_data.m index 174ff4354..a67a279b6 100644 --- a/compiler/prog_data.m +++ b/compiler/prog_data.m @@ -1347,7 +1347,18 @@ prog_constraint_get_arg_types(Constraint) = Constraint ^ constraint_arg_types. ; free ; bound(uniqueness, inst_test_results, list(bound_functor)) - % The list(bound_functor) must be sorted. + % The list(bound_functor) must be sorted, as with list.sort. + % This includes the cons_ids inside the bound_functors + % being compared lexicographically. + % + % We cannot compare the cons_ids using their declaration + % order in their shared type because we are not (yet) + % guaranteed to know what that type is. And even if we could + % rely on knowing that, there would be no point. + % As far as I (zs) know as of 2026 Jul 23, the only reason + % we require sortedness is to allow intersections and unions + % between two bound insts to be done in linear time + % instead of N log N or quadratic time. ; defined_inst(inst_name) % A defined_inst is possibly recursive inst whose value is diff --git a/compiler/simplify_goal_conj.m b/compiler/simplify_goal_conj.m index dafedc430..2c494456c 100644 --- a/compiler/simplify_goal_conj.m +++ b/compiler/simplify_goal_conj.m @@ -977,7 +977,7 @@ excess_assigns_in_conj(ConjInfo, Goals0, Goals, !Info) :- simplify_info_set_var_table(VarTable, !Info), simplify_info_get_rtti_varmaps(!.Info, RttiVarMaps0), - apply_substitutions_to_rtti_varmaps(map.init, map.init, Subn, + apply_renamings_and_subst_to_rtti_varmaps(map.init, map.init, Subn, RttiVarMaps0, RttiVarMaps), simplify_info_set_rtti_varmaps(RttiVarMaps, !Info) ). diff --git a/compiler/simplify_info.m b/compiler/simplify_info.m index 12598def3..a22ac610b 100644 --- a/compiler/simplify_info.m +++ b/compiler/simplify_info.m @@ -515,7 +515,7 @@ simplify_info_apply_substitutions_and_duplicate(ToVar, FromVar, TSubst, apply_rec_subst_to_var_table(is_type_a_dummy(ModuleInfo), TSubst, VarTable0, VarTable), Renaming = map.singleton(ToVar, FromVar), - apply_substitutions_to_rtti_varmaps(map.init, TSubst, Renaming, + apply_renamings_and_subst_to_rtti_varmaps(map.init, TSubst, Renaming, RttiVarMaps0, RttiVarMaps1), rtti_var_info_duplicate(FromVar, ToVar, RttiVarMaps1, RttiVarMaps), simplify_info_set_var_table(VarTable, !Info), diff --git a/tests/warnings/help_text.err_exp b/tests/warnings/help_text.err_exp index b55e7d7dc..0fac83544 100644 --- a/tests/warnings/help_text.err_exp +++ b/tests/warnings/help_text.err_exp @@ -771,6 +771,13 @@ Verbosity options --very-verbose Output very verbose progress messages. + PRIVATE OPTION + --very-verbose-pred-ids + Output very verbose progress messages, including pred ids, when + generating LLDS target code. This can be helpful when a problem occurs + when generating code for a compiler transformed predicate, whose names + are not fully printed with -V. + -S --statistics Output messages about the compiler's time/space usage at the boundaries @@ -3920,11 +3927,23 @@ Options for developers only Output messages about the procedure specializations done by higher_order.m. + PRIVATE OPTION + --debug-inline-pred-id + --no-debug-inline-pred-id + Output detailed debugging traces of the inlining process, but only for + the given pred id. + PRIVATE OPTION --debug-pd Output detailed debugging traces of the partial deduction and deforestation process. + PRIVATE OPTION + --debug-pd-pred-id + --no-debug-pd-pred-id + Output detailed debugging traces of the partial deduction and + deforestation process, but only for the given pred id. + PRIVATE OPTION --debug-indirect-reuse Output detailed debugging traces of the indirect reuse pass of the