diff --git a/compiler/hlds_module.m b/compiler/hlds_module.m index ec65e4873..9b839658a 100644 --- a/compiler/hlds_module.m +++ b/compiler/hlds_module.m @@ -954,6 +954,10 @@ % Unused argument info about predicates in the current module % which has been exported in .opt files. + % + % XXX This field is effectively write-only: the ONLY call + % to its getter predicate is from the code in add_pragma_gen.m + % that adds new entries to this map. mri_proc_to_unused_args_map :: proc_to_unused_args_map, % For every procedure that requires its own tabling structure, diff --git a/compiler/input_specialization.m b/compiler/input_specialization.m index 83ab41256..86bdf7c17 100644 --- a/compiler/input_specialization.m +++ b/compiler/input_specialization.m @@ -65,7 +65,8 @@ % (mode numbers) in those diagnostics, but they will map the then-actual % proc_ids back to their original proc_ids using the maybe_input_spec field, % which is set by code in this module. This mapping back is done by -% describe_one_proc_name and its variants in hlds_error_util. +% describe_one_proc_name and its variants, and by its subcontractor +% original_proc_id, in hlds_error_util. % % obsolete_proc % The compiler records this pragma in the obsolete_in_favour_of field @@ -111,17 +112,51 @@ % structure_sharing % structure_reuse % Both structure_sharing and structure_reuse pragmas can contain -% structure_sharing_domains, which contain proc_ids. We handle this +% structure_sharing_domains, which contain proc_ids. For pragmas read in +% from other modules' .opt and/or .trans_opt files, we handle this % the same way we handle the interaction with tabling: if a predicate -% that *could* be input specialized has one or more procedures that have -% sharing and/or reuse pragmas, we generate an error message, and -% do not perform the input specialization. +% that *could* be input specialized has one or more procedures for which +% we have read sharing and/or reuse pragmas, we generate an error message, +% and do not perform the input specialization. +% +% When creating .opt and/or .trans_opt files, we do not output either +% structure_sharing and structure_reuse pragmas for procedures that +% are either logically deleted by input specialization (since they are +% not supposed to be referred to at all), or are themselves the +% specialized procedures created by input specialization (since we +% don't yet know whether we want to export those procedures outside +% their defining module, and no pragma in a .opt/.trans_opt file +% should refer to a procedure that its reader may have no knowledge of). % -% type_spec -% unused_args % exceptions % trailing % mm_tabling +% The compiler records these pragmas in the exception_info, trailing_info, +% and mm_tabling_info fields of the proc_info respectively. When input +% specialization specializes a procedure, these fields get copied as well, +% and since specialization leaves the body goal of the procedure unchanged, +% the analysis results they contain remain valid. +% +% When intermodule optimization writes out these pragmas, we have handle +% two issues. First as with the structure_sharing and structure_reuse +% pragmas, we do not write out these pragmas for either procedures +% logically deleted by input specialization, nor for the new specialized +% procedures created by it. As for the procedures that do not fall into +% either of those categories, the second issue is that their procedure number +% may have been changed by input specialization. We therefore map +% their procedure ids back to the original. +% +% unused_args +% We handle writing out unused_args pragmas to .opt/.trans_opt files +% the same say we handle writing exceptions, trailing, and mm_tabling +% pragmas, and for the same reason. +% +% For reading them in, we do not have to do anything special, because +% while add the contents of each unused_args pragma we read in to a +% table in the module_info, we do not actually DO anything with the +% contents of the table :-) +% +% type_spec % We do not yet have code to handle these pragmas correctly. % %---------------------------------------------------------------------------% diff --git a/compiler/intermod_analysis.m b/compiler/intermod_analysis.m index ab8be21af..39eb18b06 100644 --- a/compiler/intermod_analysis.m +++ b/compiler/intermod_analysis.m @@ -140,6 +140,7 @@ :- implementation. +:- import_module hlds.hlds_error_util. % for original_proc_id :- import_module hlds.hlds_markers. :- import_module hlds.hlds_pred_tests. :- import_module hlds.hlds_proc. @@ -194,7 +195,6 @@ append_analysis_pragmas_to_opt_file(ModuleInfo, UnusedArgsInfosSet, % We have nothing to append to the .opt file. true else - UnusedArgsInfos = set.to_sorted_list(UnusedArgsInfosSet), module_info_get_valid_pred_ids(ModuleInfo, PredIds), generate_order_pred_infos(ModuleInfo, PredIds, OrderPredInfos), @@ -202,6 +202,7 @@ append_analysis_pragmas_to_opt_file(ModuleInfo, UnusedArgsInfosSet, TermInfos, TermInfos2, SharingInfos, ReuseInfos, Exceptions, TrailingInfos, MMTablingInfos), + set.to_sorted_list(UnusedArgsInfosSet, UnusedArgsInfos), maybe_format_block_start_blank_line(string.builder.handle, UnusedArgsInfos, !State), list.foldl(mercury_format_pragma_unused_args(string.builder.handle), @@ -416,6 +417,11 @@ gather_pragma_termination_for_pred(ModuleInfo, OrderPredInfo, gather_pragma_termination_for_proc(OrderPredInfo, _ProcId, ProcInfo, !TermInfosCord) :- + proc_info_get_maybe_input_spec(ProcInfo, MaybeInputSpec), + ( + ( MaybeInputSpec = not_involved_in_input_spec + ; MaybeInputSpec = input_spec_original_proc_kept(_) + ), OrderPredInfo = order_pred_info(PredName, _PredArity, PredOrFunc, _PredId, PredInfo), ModuleName = pred_info_module(PredInfo), @@ -423,14 +429,35 @@ gather_pragma_termination_for_proc(OrderPredInfo, _ProcId, ProcInfo, proc_info_declared_argmodes(ProcInfo, ArgModes), proc_info_get_maybe_arg_size_info(ProcInfo, MaybeArgSize), proc_info_get_maybe_termination_info(ProcInfo, MaybeTermination), - PredNameModesPF = proc_pf_name_modes(PredOrFunc, PredSymName, ArgModes), - MaybeParseTreeArgSize = maybe_arg_size_info_to_parse_tree(MaybeArgSize), + PredNameModesPF = + proc_pf_name_modes(PredOrFunc, PredSymName, ArgModes), + MaybeParseTreeArgSize = + maybe_arg_size_info_to_parse_tree(MaybeArgSize), MaybeParseTreeTermination = maybe_termination_info_to_parse_tree(MaybeTermination), TermInfo = decl_pragma_termination_info(PredNameModesPF, MaybeParseTreeArgSize, MaybeParseTreeTermination, dummy_context, item_no_seq_num), - cord.snoc(TermInfo, !TermInfosCord). + cord.snoc(TermInfo, !TermInfosCord) + ; + ( MaybeInputSpec = input_spec_original_proc_logically_deleted(_) + ; MaybeInputSpec = input_specialized_proc(_) + ) + % Logically deleted procedures should not be visible + % from *any* module, even the one defining them. + % + % XXX input_spec pragmas are too new to know whether it is + % worth including either them, or the declarations and definitions + % of the procedures resulting from them, in .opt or .trans_opt files. + % Until we know the answer to that question, it is better to err + % on the side of including the declarations of such predicates + % in .opt/.trans_opt files without their termination info + % (which leads to suboptimal termination results but works) + % than on the side of including their termination into + % but not their declarations (which leads to a compiler crash + % when the lookup of the predicate the termination pragma applies + % fails). + ). :- func maybe_arg_size_info_to_parse_tree(maybe(arg_size_info)) = maybe(pragma_arg_size_info). @@ -510,6 +537,11 @@ gather_pragma_termination2_for_pred(ModuleInfo, OrderPredInfo, gather_pragma_termination2_for_proc(OrderPredInfo, _ProcId, ProcInfo, !TermInfo2sCord) :- + proc_info_get_maybe_input_spec(ProcInfo, MaybeInputSpec), + ( + ( MaybeInputSpec = not_involved_in_input_spec + ; MaybeInputSpec = input_spec_original_proc_kept(_) + ), OrderPredInfo = order_pred_info(PredName, _PredArity, PredOrFunc, _PredId, PredInfo), ModuleName = pred_info_module(PredInfo), @@ -523,7 +555,8 @@ gather_pragma_termination2_for_proc(OrderPredInfo, _ProcId, ProcInfo, % NOTE: If this predicate is changed, then parse_pragma.m must also % be changed, so that it can parse the resulting pragmas. - PredNameModesPF = proc_pf_name_modes(PredOrFunc, PredSymName, ArgModes), + PredNameModesPF = + proc_pf_name_modes(PredOrFunc, PredSymName, ArgModes), proc_info_get_headvars(ProcInfo, HeadVars), SizeVarMap = term2_info_get_size_var_map(Term2Info), @@ -552,7 +585,13 @@ gather_pragma_termination2_for_proc(OrderPredInfo, _ProcId, ProcInfo, TermInfo2 = decl_pragma_termination2_info(PredNameModesPF, MaybeSuccessArgSizeInfo, MaybeFailureArgSizeInfo, MaybePragmaTermination, dummy_context, item_no_seq_num), - cord.snoc(TermInfo2, !TermInfo2sCord). + cord.snoc(TermInfo2, !TermInfo2sCord) + ; + ( MaybeInputSpec = input_spec_original_proc_logically_deleted(_) + ; MaybeInputSpec = input_specialized_proc(_) + ) + % The comment in gather_pragma_termination_for_proc applies here too. + ). %---------------------% @@ -622,6 +661,11 @@ gather_pragma_exceptions_for_pred(ModuleInfo, OrderPredInfo, gather_pragma_exceptions_for_proc(ModuleInfo, OrderPredInfo, ProcId, ProcInfo, !ExceptionsCord) :- + proc_info_get_maybe_input_spec(ProcInfo, MaybeInputSpec), + ( + ( MaybeInputSpec = not_involved_in_input_spec + ; MaybeInputSpec = input_spec_original_proc_kept(_) + ), OrderPredInfo = order_pred_info(PredName, UserArity, PredOrFunc, PredId, PredInfo), ( if @@ -644,15 +688,22 @@ gather_pragma_exceptions_for_proc(ModuleInfo, OrderPredInfo, then ModuleName = pred_info_module(PredInfo), PredSymName = qualified(ModuleName, PredName), - proc_id_to_int(ProcId, ModeNum), + original_proc_id(ProcInfo, ProcId, OrigProcId), + proc_id_to_int(OrigProcId, ModeNum), PredNameArityPFMn = proc_pf_name_arity_mn(PredOrFunc, PredSymName, UserArity, ModeNum), ProcExceptionInfo = proc_exception_info(Status, _), - ExceptionInfo = gen_pragma_exceptions_info(PredNameArityPFMn, Status, - dummy_context, item_no_seq_num), + ExceptionInfo = gen_pragma_exceptions_info(PredNameArityPFMn, + Status, dummy_context, item_no_seq_num), cord.snoc(ExceptionInfo, !ExceptionsCord) else true + ) + ; + ( MaybeInputSpec = input_spec_original_proc_logically_deleted(_) + ; MaybeInputSpec = input_specialized_proc(_) + ) + % The comment in gather_pragma_termination_for_proc applies here too. ). %---------------------------------------------------------------------------% @@ -680,6 +731,11 @@ gather_pragma_trailing_info_for_pred(ModuleInfo, OrderPredInfo, gather_pragma_trailing_info_for_proc(ModuleInfo, OrderPredInfo, ProcId, ProcInfo, !TrailingInfosCord) :- + proc_info_get_maybe_input_spec(ProcInfo, MaybeInputSpec), + ( + ( MaybeInputSpec = not_involved_in_input_spec + ; MaybeInputSpec = input_spec_original_proc_kept(_) + ), OrderPredInfo = order_pred_info(PredName, UserArity, PredOrFunc, PredId, PredInfo), proc_info_get_trailing_info(ProcInfo, MaybeProcTrailingInfo), @@ -691,7 +747,8 @@ gather_pragma_trailing_info_for_proc(ModuleInfo, OrderPredInfo, then ModuleName = pred_info_module(PredInfo), PredSymName = qualified(ModuleName, PredName), - proc_id_to_int(ProcId, ModeNum), + original_proc_id(ProcInfo, ProcId, OrigProcId), + proc_id_to_int(OrigProcId, ModeNum), PredNameArityPFMn = proc_pf_name_arity_mn(PredOrFunc, PredSymName, UserArity, ModeNum), ProcTrailingInfo = proc_trailing_info(Status, _), @@ -700,6 +757,12 @@ gather_pragma_trailing_info_for_proc(ModuleInfo, OrderPredInfo, cord.snoc(TrailingInfo, !TrailingInfosCord) else true + ) + ; + ( MaybeInputSpec = input_spec_original_proc_logically_deleted(_) + ; MaybeInputSpec = input_specialized_proc(_) + ) + % The comment in gather_pragma_termination_for_proc applies here too. ). %---------------------------------------------------------------------------% @@ -726,6 +789,11 @@ gather_pragma_mm_tabling_info_for_pred(ModuleInfo, OrderPredInfo, gather_pragma_mm_tabling_info_for_proc(ModuleInfo, OrderPredInfo, ProcId, ProcInfo, !MMTablingInfosCord) :- + proc_info_get_maybe_input_spec(ProcInfo, MaybeInputSpec), + ( + ( MaybeInputSpec = not_involved_in_input_spec + ; MaybeInputSpec = input_spec_original_proc_kept(_) + ), OrderPredInfo = order_pred_info(PredName, PredArity, PredOrFunc, PredId, PredInfo), proc_info_get_mm_tabling_info(ProcInfo, MaybeProcMMTablingInfo), @@ -737,7 +805,8 @@ gather_pragma_mm_tabling_info_for_proc(ModuleInfo, OrderPredInfo, then ModuleName = pred_info_module(PredInfo), PredSymName = qualified(ModuleName, PredName), - proc_id_to_int(ProcId, ModeNum), + original_proc_id(ProcInfo, ProcId, OrigProcId), + proc_id_to_int(OrigProcId, ModeNum), PredNameArityPFMn = proc_pf_name_arity_mn(PredOrFunc, PredSymName, PredArity, ModeNum), ProcMMTablingInfo = proc_mm_tabling_info(Status, _), @@ -747,6 +816,12 @@ gather_pragma_mm_tabling_info_for_proc(ModuleInfo, OrderPredInfo, cord.snoc(MMTablingInfo, !MMTablingInfosCord) else true + ) + ; + ( MaybeInputSpec = input_spec_original_proc_logically_deleted(_) + ; MaybeInputSpec = input_specialized_proc(_) + ) + % The comment in gather_pragma_termination_for_proc applies here too. ). %---------------------------------------------------------------------------% @@ -772,6 +847,11 @@ gather_pragma_structure_sharing_for_pred(ModuleInfo, OrderPredInfo, gather_pragma_structure_sharing_for_proc(ModuleInfo, OrderPredInfo, ProcId, ProcInfo, !SharingInfosCord) :- + proc_info_get_maybe_input_spec(ProcInfo, MaybeInputSpec), + ( + ( MaybeInputSpec = not_involved_in_input_spec + ; MaybeInputSpec = input_spec_original_proc_kept(_) + ), OrderPredInfo = order_pred_info(PredName, _PredArity, PredOrFunc, PredId, PredInfo), ( if @@ -792,13 +872,20 @@ gather_pragma_structure_sharing_for_proc(ModuleInfo, OrderPredInfo, PredSymName, ArgModes), proc_info_get_headvars(ProcInfo, HeadVars), lookup_var_types(VarTable, HeadVars, HeadVarTypes), - SharingStatus = structure_sharing_domain_and_status(Sharing, _Status), + SharingStatus = + structure_sharing_domain_and_status(Sharing, _Status), SharingInfo = decl_pragma_struct_sharing_info(PredNameModesPF, HeadVars, HeadVarTypes, VarSet, TypeVarSet, yes(Sharing), dummy_context, item_no_seq_num), cord.snoc(SharingInfo, !SharingInfosCord) else true + ) + ; + ( MaybeInputSpec = input_spec_original_proc_logically_deleted(_) + ; MaybeInputSpec = input_specialized_proc(_) + ) + % The comment in gather_pragma_termination_for_proc applies here too. ). %---------------------------------------------------------------------------% @@ -823,6 +910,11 @@ gather_pragma_structure_reuse_for_pred(ModuleInfo, OrderPredInfo, gather_pragma_structure_reuse_for_proc(ModuleInfo, OrderPredInfo, ProcId, ProcInfo, !ReuseInfosCord) :- + proc_info_get_maybe_input_spec(ProcInfo, MaybeInputSpec), + ( + ( MaybeInputSpec = not_involved_in_input_spec + ; MaybeInputSpec = input_spec_original_proc_kept(_) + ), OrderPredInfo = order_pred_info(PredName, _PredArity, PredOrFunc, PredId, PredInfo), ( if @@ -851,6 +943,12 @@ gather_pragma_structure_reuse_for_proc(ModuleInfo, OrderPredInfo, cord.snoc(ReuseInfo, !ReuseInfosCord) else true + ) + ; + ( MaybeInputSpec = input_spec_original_proc_logically_deleted(_) + ; MaybeInputSpec = input_specialized_proc(_) + ) + % The comment in gather_pragma_termination_for_proc applies here too. ). %---------------------------------------------------------------------------% diff --git a/compiler/unused_args_warn_pragma.m b/compiler/unused_args_warn_pragma.m index 16d1152ed..b8159b0d1 100644 --- a/compiler/unused_args_warn_pragma.m +++ b/compiler/unused_args_warn_pragma.m @@ -65,6 +65,7 @@ :- import_module hlds.mode_test. :- import_module hlds.pred_name. :- import_module hlds.pred_proc_id. +:- import_module hlds.proc_info_types. :- import_module hlds.status. :- import_module libs. :- import_module libs.options. @@ -278,6 +279,8 @@ may_gather_warning_pragma_for_pred(PredInfo) :- :- type warn_unused_pred_args ---> warn_unused_pred_args( pred_info, + % The proc_id is the original proc_id of the procedure, + % even if this was changed later by input specialization. one_or_more(pair(proc_id, unused_proc_args)) ). @@ -309,6 +312,14 @@ maybe_add_proc_to_unused_args_map(ModuleInfo, PredInfo, PredId, ProcId, ( UnusedArgs = [_ | _], pred_info_proc_info(PredInfo, ProcId, ProcInfo), + proc_info_get_maybe_input_spec(ProcInfo, MaybeInputSpec), + ( + ( + MaybeInputSpec = not_involved_in_input_spec, + OrigProcId = ProcId + ; + MaybeInputSpec = input_spec_original_proc_kept(OrigProcId) + ), proc_info_get_argmodes(ProcInfo, ArgModes0), list.det_drop(NumExtraArgs, ArgModes0, ArgModes), record_which_unused_args_are_marked(ModuleInfo, ArgModes, @@ -316,16 +327,26 @@ maybe_add_proc_to_unused_args_map(ModuleInfo, PredInfo, PredId, ProcId, % If UnusedArgs is not empty, then UnusedProcArgs cannot be empty. det_list_to_one_or_more(UnusedProcArgs, OoMUnusedProcArgs), ( if - map.search(!.WarnUnusedPredArgsMap, PredId, WarnUnusedPredArgs0) + map.search(!.WarnUnusedPredArgsMap, PredId, + WarnUnusedPredArgs0) then - WarnUnusedPredArgs0 = warn_unused_pred_args(_PredInfo, ProcAL0), - one_or_more.cons(ProcId - OoMUnusedProcArgs, ProcAL0, ProcAL), + WarnUnusedPredArgs0 = + warn_unused_pred_args(_PredInfo, ProcAL0), + one_or_more.cons(OrigProcId - OoMUnusedProcArgs, + ProcAL0, ProcAL), WarnUnusedPredArgs = warn_unused_pred_args(PredInfo, ProcAL), - map.det_update(PredId, WarnUnusedPredArgs, !WarnUnusedPredArgsMap) + map.det_update(PredId, WarnUnusedPredArgs, + !WarnUnusedPredArgsMap) else - ProcAL = one_or_more(ProcId - OoMUnusedProcArgs, []), + ProcAL = one_or_more(OrigProcId - OoMUnusedProcArgs, []), WarnUnusedPredArgs = warn_unused_pred_args(PredInfo, ProcAL), - map.det_insert(PredId, WarnUnusedPredArgs, !WarnUnusedPredArgsMap) + map.det_insert(PredId, WarnUnusedPredArgs, + !WarnUnusedPredArgsMap) + ) + ; + ( MaybeInputSpec = input_spec_original_proc_logically_deleted(_) + ; MaybeInputSpec = input_specialized_proc(_) + ) ) ; UnusedArgs = [] @@ -383,6 +404,11 @@ warn_unused_args_in_pred(_PredId, WarnUnusedPredArgs, !Specs) :- % - all procedures have some unused arguments, and % - they all have the *same set* of unused arguments, *and* % they agree on which unused args are marked as such. + % Note that "all procedures" here means "all procedures for which + % we have entries in WarnUnusedPredArgs". Procedures that were ignored + % by maybe_add_proc_to_unused_args_map because of an unsuitable value + % of MaybeInputSpec do not count as parts of "all", since they are + % effectively invisible to the user. ( if map.is_empty(UnmentionedProcTable), UnusedArgsToProcAL = [UnusedProcArgs - _OoMProcIds] @@ -538,13 +564,23 @@ maybe_gather_unused_args_pragma(PredInfo, ProcId, UnusedArgs, ), UnusedArgs = [_ | _] then + pred_info_get_proc_table(PredInfo, ProcTable), + map.lookup(ProcTable, ProcId, ProcInfo), + proc_info_get_maybe_input_spec(ProcInfo, MaybeInputSpec), + ( + ( + MaybeInputSpec = not_involved_in_input_spec, + OrigProcId = ProcId + ; + MaybeInputSpec = input_spec_original_proc_kept(OrigProcId) + ), ModuleName = pred_info_module(PredInfo), PredOrFunc = pred_info_is_pred_or_func(PredInfo), PredName = pred_info_name(PredInfo), PredSymName = qualified(ModuleName, PredName), pred_info_get_orig_arity(PredInfo, PredFormArity), user_arity_pred_form_arity(PredOrFunc, UserArity, PredFormArity), - proc_id_to_int(ProcId, ModeNum), + proc_id_to_int(OrigProcId, ModeNum), PredNameArityPFMn = proc_pf_name_arity_mn(PredOrFunc, PredSymName, UserArity, ModeNum), % We can either collect a set of gen_pragma_unused_args @@ -555,6 +591,11 @@ maybe_gather_unused_args_pragma(PredInfo, ProcId, UnusedArgs, UnusedArgInfo = gen_pragma_unused_args_info(PredNameArityPFMn, UnusedArgs, dummy_context, item_no_seq_num), set.insert(UnusedArgInfo, !UnusedArgInfos) + ; + ( MaybeInputSpec = input_spec_original_proc_logically_deleted(_) + ; MaybeInputSpec = input_specialized_proc(_) + ) + ) else true ).