mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-12 20:34:19 +00:00
530 lines
22 KiB
Mathematica
530 lines
22 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ff=unix ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 2006-2012 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% File: structure_reuse.versions.m.
|
|
% Main authors: nancy.
|
|
%
|
|
% Provide the functionality to create optimised versions of those procedures
|
|
% for which reuse was detected.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module structure_reuse.versions.
|
|
:- interface.
|
|
|
|
:- import_module hlds.
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module transform_hlds.ctgc.structure_reuse.domain.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% For each of the entries in the reuse table:
|
|
%
|
|
% * if the listed reuse is conditional, then duplicate the
|
|
% pred-info/proc-info of the original procedure, changing all potential
|
|
% reuse annotation to real reuses;
|
|
% * if the listed reuse is unconditional, then no duplication is needed,
|
|
% yet the goal needs to be traversed to correctly replace all
|
|
% procedure calls to calls to reuse versions whenever needed.
|
|
% * if the listed reuse is "no reuse", then obviously, nothing needs to
|
|
% be done.
|
|
%
|
|
% This process updates the module information by adding the new predicates,
|
|
% and recording the pred-proc-id to the reuse pred-proc-id mappings in
|
|
% module_info.
|
|
%
|
|
:- pred create_reuse_procedures(reuse_as_table::in, reuse_as_table::out,
|
|
module_info::in, module_info::out) is det.
|
|
|
|
% Create a copy of the predicate/procedure information specified by the
|
|
% given pred_proc_id, and return the pred_proc_id of that copy. The copy
|
|
% is not altered w.r.t. structure reuse. It is a plain copy, nothing more
|
|
% than that.
|
|
%
|
|
:- pred create_fresh_pred_proc_info_copy(pred_proc_id::in, no_clobber_args::in,
|
|
pred_proc_id::out, module_info::in, module_info::out) is det.
|
|
|
|
% Create a fake reuse procedure that simply calls the non-reuse procedure.
|
|
%
|
|
:- pred create_fake_reuse_procedure(pred_proc_id::in, no_clobber_args::in,
|
|
module_info::in, module_info::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module check_hlds.
|
|
:- import_module check_hlds.mode_util.
|
|
:- import_module hlds.hlds_goal.
|
|
:- import_module hlds.passes_aux.
|
|
:- import_module hlds.pred_table.
|
|
:- import_module hlds.quantification.
|
|
:- import_module hlds.status.
|
|
:- import_module libs.
|
|
:- import_module libs.globals.
|
|
:- import_module libs.op_mode.
|
|
:- import_module libs.options.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.prog_util.
|
|
:- import_module transform_hlds.ctgc.structure_reuse.analysis.
|
|
|
|
:- import_module bimap.
|
|
:- import_module bool.
|
|
:- import_module list.
|
|
:- import_module map.
|
|
:- import_module maybe.
|
|
:- import_module require.
|
|
:- import_module set.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type reuse_name == sym_name.
|
|
|
|
:- func generate_reuse_name(module_info, pred_proc_id, list(int)) = reuse_name.
|
|
|
|
generate_reuse_name(ModuleInfo, PPId, NoClobbers) = ReuseName :-
|
|
PPId = proc(_, ProcId),
|
|
module_info_pred_proc_info(ModuleInfo, PPId, PredInfo, _ProcInfo),
|
|
PredModule = pred_info_module(PredInfo),
|
|
PredOrFunc = pred_info_is_pred_or_func(PredInfo),
|
|
PredName = pred_info_name(PredInfo),
|
|
proc_id_to_int(ProcId, ProcInt),
|
|
make_pred_name(PredModule, "ctgc", yes(PredOrFunc), PredName,
|
|
newpred_structure_reuse(ProcInt, NoClobbers), ReuseName).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
create_reuse_procedures(!ReuseTable, !ModuleInfo) :-
|
|
% This process can be split into separate steps:
|
|
% - determine all the pred-proc-ids of procedure with conditional reuse;
|
|
% - create duplicates of these procedures;
|
|
% - traverse all these procedures + the procedures with unconditional reuse
|
|
% to correctly update the reuse annotations.
|
|
|
|
% Get the list of conditional reuse procedures already created.
|
|
ExistingReusePPIds = bimap.coordinates(!.ReuseTable ^ reuse_version_map),
|
|
ExistingReusePPIdsSet = set.from_list(ExistingReusePPIds),
|
|
|
|
map.foldl2(divide_reuse_procs(ExistingReusePPIdsSet),
|
|
!.ReuseTable ^ reuse_info_map, [], CondOrigPPIds, [], UncondOrigPPIds),
|
|
|
|
% Create duplicates of the procedures which have conditional reuse. The
|
|
% "intermediate" reuse procedures will already have been created during the
|
|
% analysis, so this creates just the reuse versions where all possible
|
|
% arguments are potentially reusable.
|
|
list.map_foldl2(maybe_create_full_reuse_proc_copy,
|
|
CondOrigPPIds, ReuseCondPPIds, !ModuleInfo, !ReuseTable),
|
|
|
|
% Process all the goals to update the reuse annotations. In the reuse
|
|
% versions of procedures we can take advantage of potential reuse
|
|
% opportunities.
|
|
list.foldl(check_cond_process_proc(convert_potential_reuse, !.ReuseTable),
|
|
ReuseCondPPIds, !ModuleInfo),
|
|
list.foldl(check_cond_process_proc(convert_potential_reuse, !.ReuseTable),
|
|
ExistingReusePPIds, !ModuleInfo),
|
|
|
|
% In the original procedures, only the unconditional reuse opportunities
|
|
% can be taken.
|
|
list.foldl(process_proc(leave_potential_reuse, !.ReuseTable),
|
|
CondOrigPPIds, !ModuleInfo),
|
|
list.foldl(process_proc(leave_potential_reuse, !.ReuseTable),
|
|
UncondOrigPPIds, !ModuleInfo).
|
|
|
|
% Separate procedures in the reuse table into those with some conditional
|
|
% reuse opportunities, and those with only unconditional reuse.
|
|
% Skip any procedure which is already a reuse copy of another procedure.
|
|
%
|
|
:- pred divide_reuse_procs(set(pred_proc_id)::in,
|
|
pred_proc_id::in, reuse_as_and_status::in,
|
|
list(pred_proc_id)::in, list(pred_proc_id)::out,
|
|
list(pred_proc_id)::in, list(pred_proc_id)::out) is det.
|
|
|
|
divide_reuse_procs(ExistingReusePPIdsSet, PPId, ReuseAs_Status,
|
|
!CondPPIds, !UncondPPIds) :-
|
|
ReuseAs_Status = reuse_as_and_status(ReuseAs, _),
|
|
( if set.contains(ExistingReusePPIdsSet, PPId) then
|
|
true
|
|
else if reuse_as_conditional_reuses(ReuseAs) then
|
|
!:CondPPIds = [PPId | !.CondPPIds]
|
|
else if reuse_as_all_unconditional_reuses(ReuseAs) then
|
|
!:UncondPPIds = [PPId | !.UncondPPIds]
|
|
else if reuse_as_no_reuses(ReuseAs) then
|
|
true
|
|
else
|
|
unexpected($pred, "conditions failed")
|
|
).
|
|
|
|
:- pred maybe_create_full_reuse_proc_copy(pred_proc_id::in, pred_proc_id::out,
|
|
module_info::in, module_info::out, reuse_as_table::in, reuse_as_table::out)
|
|
is det.
|
|
|
|
maybe_create_full_reuse_proc_copy(PPId, NewPPId, !ModuleInfo, !ReuseTable) :-
|
|
NoClobbers = [],
|
|
( if
|
|
reuse_as_table_search_reuse_version_proc(!.ReuseTable,
|
|
PPId, NoClobbers, _)
|
|
then
|
|
unexpected($pred, "procedure already exists")
|
|
else
|
|
true
|
|
),
|
|
create_fresh_pred_proc_info_copy(PPId, NoClobbers, NewPPId, !ModuleInfo),
|
|
( if reuse_as_table_search(!.ReuseTable, PPId, ReuseAs_Status) then
|
|
reuse_as_table_set(NewPPId, ReuseAs_Status, !ReuseTable),
|
|
reuse_as_table_insert_reuse_version_proc(PPId, NoClobbers, NewPPId,
|
|
!ReuseTable)
|
|
else
|
|
unexpected($pred, "no reuse information")
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
create_fresh_pred_proc_info_copy(PPId, NoClobbers, NewPPId, !ModuleInfo) :-
|
|
module_info_pred_proc_info(!.ModuleInfo, PPId, PredInfo0, ProcInfo0),
|
|
ReusePredName = generate_reuse_name(!.ModuleInfo, PPId, NoClobbers),
|
|
PPId = proc(PredId, _),
|
|
create_fresh_pred_proc_info_copy_2(PredId, PredInfo0, ProcInfo0,
|
|
ReusePredName, ReusePredInfo, ReuseProcId),
|
|
|
|
NewPPId = proc(ReusePredId, ReuseProcId),
|
|
|
|
module_info_get_predicate_table(!.ModuleInfo, PredTable0),
|
|
predicate_table_insert(ReusePredInfo, ReusePredId, PredTable0, PredTable),
|
|
module_info_set_predicate_table(PredTable, !ModuleInfo),
|
|
|
|
module_info_get_structure_reuse_preds(!.ModuleInfo, ReusePreds0),
|
|
set.insert(ReusePredId, ReusePreds0, ReusePreds),
|
|
module_info_set_structure_reuse_preds(ReusePreds, !ModuleInfo).
|
|
|
|
:- pred create_fresh_pred_proc_info_copy_2(pred_id::in, pred_info::in,
|
|
proc_info::in, reuse_name::in, pred_info::out, proc_id::out) is det.
|
|
|
|
create_fresh_pred_proc_info_copy_2(PredId, PredInfo, ProcInfo, ReusePredName,
|
|
ReusePredInfo, ReuseProcId) :-
|
|
ModuleName = pred_info_module(PredInfo),
|
|
PredOrFunc = pred_info_is_pred_or_func(PredInfo),
|
|
pred_info_get_context(PredInfo, ProgContext),
|
|
pred_info_get_origin(PredInfo, PredOrigin),
|
|
pred_info_get_status(PredInfo, PredStatus0),
|
|
% If the predicate was opt_imported then the specialised copy should be
|
|
% local, otherwise it will be eliminated by dead proc elimination.
|
|
( if PredStatus0 = pred_status(status_opt_imported) then
|
|
PredStatus = pred_status(status_local)
|
|
else
|
|
PredStatus = PredStatus0
|
|
),
|
|
pred_info_get_markers(PredInfo, PredMarkers),
|
|
pred_info_get_arg_types(PredInfo, MerTypes),
|
|
pred_info_get_typevarset(PredInfo, TVarset),
|
|
pred_info_get_exist_quant_tvars(PredInfo, ExistQTVars),
|
|
pred_info_get_class_context(PredInfo, ProgConstraints),
|
|
pred_info_get_assertions(PredInfo, AssertIds),
|
|
pred_info_get_var_name_remap(PredInfo, VarNameRemap),
|
|
NewPredOrigin = origin_transformed(transform_structure_reuse, PredOrigin,
|
|
PredId),
|
|
pred_info_create(ModuleName, ReusePredName, PredOrFunc, ProgContext,
|
|
NewPredOrigin, PredStatus, PredMarkers, MerTypes, TVarset,
|
|
ExistQTVars, ProgConstraints, AssertIds, VarNameRemap,
|
|
ProcInfo, ReuseProcId, ReusePredInfo).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type convert_potential_reuse
|
|
---> convert_potential_reuse
|
|
; leave_potential_reuse.
|
|
|
|
% When generating target code, we may find a set of reuse conditions on a
|
|
% procedure which are *harsher* than the reuse conditions that we found
|
|
% during the `--make-analysis-registry' step. This can happen due extra
|
|
% analysis information gathered for other modules in the meantime. In that
|
|
% case, we may have external callers to the procedure which have verified
|
|
% only against the *laxer* reuse conditions.
|
|
%
|
|
% Hence we need to be careful that we don't generate any code which
|
|
% violates the weaker reuse conditions. One (conservative) way to do that
|
|
% is to ignore all the potential reuse annotations and only use the
|
|
% unconditional reuse annotations.
|
|
%
|
|
% XXX the same problem occurs with `--intermodule-optimisation'
|
|
%
|
|
:- pred check_cond_process_proc(convert_potential_reuse::in,
|
|
reuse_as_table::in, pred_proc_id::in, module_info::in, module_info::out)
|
|
is det.
|
|
|
|
check_cond_process_proc(ConvertPotentialReuse, ReuseTable, ReusePPId,
|
|
!ModuleInfo) :-
|
|
module_info_get_globals(!.ModuleInfo, Globals),
|
|
globals.lookup_bool_option(Globals, intermodule_analysis,
|
|
IntermodAnalysis),
|
|
globals.get_op_mode(Globals, OpMode),
|
|
( if
|
|
IntermodAnalysis = yes,
|
|
OpMode \= opm_top_args(opma_augment(opmau_make_analysis_registry))
|
|
then
|
|
structure_reuse_answer_harsher_than_in_analysis_registry(!.ModuleInfo,
|
|
ReuseTable, ReusePPId, IsHarsher)
|
|
else
|
|
IsHarsher = no
|
|
),
|
|
(
|
|
IsHarsher = yes,
|
|
% Ignoring potential reuse is equivalent to having only unconditional
|
|
% structure reuse.
|
|
process_proc(leave_potential_reuse, ReuseTable, ReusePPId, !ModuleInfo)
|
|
;
|
|
IsHarsher = no,
|
|
process_proc(ConvertPotentialReuse, ReuseTable, ReusePPId, !ModuleInfo)
|
|
).
|
|
|
|
% Process the goal of the procedure with the given pred_proc_id so that
|
|
% all potential reuses are replaced by real reuses, and all calls to
|
|
% procedures that have a reuse version are replaced by calls to their
|
|
% reuse version (if of course, that is in accordance with the reuse
|
|
% annotations).
|
|
%
|
|
:- pred process_proc(convert_potential_reuse::in, reuse_as_table::in,
|
|
pred_proc_id::in, module_info::in, module_info::out) is det.
|
|
|
|
process_proc(ConvertPotentialReuse, ReuseTable, PPId, !ModuleInfo) :-
|
|
trace [io(!IO)] (
|
|
write_proc_progress_message("(reuse version) ", PPId, !.ModuleInfo,
|
|
!IO)
|
|
),
|
|
some [!ProcInfo] (
|
|
module_info_pred_proc_info(!.ModuleInfo, PPId, PredInfo0, !:ProcInfo),
|
|
pred_info_get_status(PredInfo0, PredStatus),
|
|
( if PredStatus = pred_status(status_imported(_)) then
|
|
% The bodies may contain junk, so don't try to process.
|
|
true
|
|
else
|
|
proc_info_get_goal(!.ProcInfo, Goal0),
|
|
process_goal(ConvertPotentialReuse, ReuseTable, !.ModuleInfo,
|
|
Goal0, Goal),
|
|
proc_info_set_goal(Goal, !ProcInfo),
|
|
|
|
% A dead variable needs to appear in the non-local set of the
|
|
% construction unification in which its space is reused, so we
|
|
% requantify. Then we recompute instmap deltas with the updated
|
|
% non-local sets.
|
|
requantify_proc_general(ordinary_nonlocals_no_lambda, !ProcInfo),
|
|
recompute_instmap_delta_proc(
|
|
do_not_recompute_atomic_instmap_deltas,
|
|
!ProcInfo, !ModuleInfo),
|
|
module_info_set_pred_proc_info(PPId, PredInfo0, !.ProcInfo,
|
|
!ModuleInfo)
|
|
)
|
|
).
|
|
|
|
:- pred process_goal(convert_potential_reuse::in, reuse_as_table::in,
|
|
module_info::in, hlds_goal::in, hlds_goal::out) is det.
|
|
|
|
process_goal(ConvertPotentialReuse, ReuseTable, ModuleInfo, !Goal) :-
|
|
!.Goal = hlds_goal(GoalExpr0, GoalInfo0),
|
|
(
|
|
GoalExpr0 = conj(ConjType, Goals0),
|
|
list.map(process_goal(ConvertPotentialReuse, ReuseTable, ModuleInfo),
|
|
Goals0, Goals),
|
|
GoalExpr = conj(ConjType, Goals),
|
|
!:Goal = hlds_goal(GoalExpr, GoalInfo0)
|
|
;
|
|
GoalExpr0 = plain_call(CalleePredId, CalleeProcId, Args, BI, UC,
|
|
CalleePredName),
|
|
ReuseDescription0 = goal_info_get_reuse(GoalInfo0),
|
|
( if
|
|
% If the reuse description already says "reuse", then this is
|
|
% a call to a procedure which might have specified conditions, yet
|
|
% whose conditions are always met, hence do not imply conditions on
|
|
% the procedure in which this call appears. We must therefore
|
|
% make sure to call the appropriate version of the called
|
|
% procedure.
|
|
ReuseDescription0 = reuse(reuse_call(_CondDescr, NoClobbers))
|
|
then
|
|
determine_reuse_version(ReuseTable, ModuleInfo, CalleePredId,
|
|
CalleeProcId, CalleePredName, NoClobbers, ReuseCalleePredId,
|
|
ReuseCalleeProcId, ReuseCalleePredName),
|
|
GoalExpr = plain_call(ReuseCalleePredId, ReuseCalleeProcId,
|
|
Args, BI, UC, ReuseCalleePredName),
|
|
!:Goal = hlds_goal(GoalExpr, GoalInfo0)
|
|
else if
|
|
ReuseDescription0 = potential_reuse(reuse_call(CondDescr,
|
|
NoClobbers)),
|
|
ConvertPotentialReuse = convert_potential_reuse
|
|
then
|
|
ConvertPotentialReuse = convert_potential_reuse,
|
|
% Replace the call to the reuse version, and change the
|
|
% potential reuse annotation to a real annotation.
|
|
determine_reuse_version(ReuseTable, ModuleInfo,
|
|
CalleePredId, CalleeProcId, CalleePredName, NoClobbers,
|
|
ReuseCalleePredId, ReuseCalleeProcId, ReuseCalleePredName),
|
|
GoalExpr = plain_call(ReuseCalleePredId, ReuseCalleeProcId,
|
|
Args, BI, UC, ReuseCalleePredName),
|
|
ReuseDescription = reuse(reuse_call(CondDescr, NoClobbers)),
|
|
goal_info_set_reuse(ReuseDescription, GoalInfo0, GoalInfo),
|
|
!:Goal = hlds_goal(GoalExpr, GoalInfo)
|
|
else
|
|
true
|
|
)
|
|
;
|
|
GoalExpr0 = generic_call(_, _, _, _, _)
|
|
;
|
|
GoalExpr0 = unify(_, _, _, Unification0, _),
|
|
ReuseDescription0 = goal_info_get_reuse(GoalInfo0),
|
|
(
|
|
(
|
|
ReuseDescription0 = reuse(Descr)
|
|
;
|
|
ReuseDescription0 = potential_reuse(Descr),
|
|
ConvertPotentialReuse = convert_potential_reuse
|
|
),
|
|
ReuseDescription = reuse(Descr),
|
|
unification_set_reuse(Descr, Unification0, Unification),
|
|
GoalExpr = GoalExpr0 ^ unify_kind := Unification,
|
|
goal_info_set_reuse(ReuseDescription, GoalInfo0, GoalInfo),
|
|
!:Goal = hlds_goal(GoalExpr, GoalInfo)
|
|
;
|
|
ReuseDescription0 = potential_reuse(_),
|
|
ConvertPotentialReuse = leave_potential_reuse
|
|
;
|
|
ReuseDescription0 = no_reuse_info
|
|
;
|
|
ReuseDescription0 = no_possible_reuse
|
|
;
|
|
ReuseDescription0 = missed_reuse(_)
|
|
)
|
|
;
|
|
GoalExpr0 = disj(Goals0),
|
|
list.map(process_goal(ConvertPotentialReuse, ReuseTable, ModuleInfo),
|
|
Goals0, Goals),
|
|
GoalExpr = disj(Goals),
|
|
!:Goal = hlds_goal(GoalExpr, GoalInfo0)
|
|
;
|
|
GoalExpr0 = switch(A, B, Cases0),
|
|
list.map(process_case(ConvertPotentialReuse, ReuseTable, ModuleInfo),
|
|
Cases0, Cases),
|
|
GoalExpr = switch(A, B, Cases),
|
|
!:Goal = hlds_goal(GoalExpr, GoalInfo0)
|
|
;
|
|
% XXX To check and compare with the theory.
|
|
GoalExpr0 = negation(_Goal)
|
|
;
|
|
GoalExpr0 = scope(Reason, SubGoal0),
|
|
( if Reason = from_ground_term(_, from_ground_term_construct) then
|
|
true
|
|
else
|
|
process_goal(ConvertPotentialReuse, ReuseTable, ModuleInfo,
|
|
SubGoal0, SubGoal),
|
|
GoalExpr = scope(Reason, SubGoal),
|
|
!:Goal = hlds_goal(GoalExpr, GoalInfo0)
|
|
)
|
|
;
|
|
GoalExpr0 = if_then_else(Vars, IfGoal0, ThenGoal0, ElseGoal0),
|
|
process_goal(ConvertPotentialReuse, ReuseTable, ModuleInfo,
|
|
IfGoal0, IfGoal),
|
|
process_goal(ConvertPotentialReuse, ReuseTable, ModuleInfo,
|
|
ThenGoal0, ThenGoal),
|
|
process_goal(ConvertPotentialReuse, ReuseTable, ModuleInfo,
|
|
ElseGoal0, ElseGoal),
|
|
GoalExpr = if_then_else(Vars, IfGoal, ThenGoal, ElseGoal),
|
|
!:Goal = hlds_goal(GoalExpr, GoalInfo0)
|
|
;
|
|
GoalExpr0 = call_foreign_proc(_Attrs, _ForeignPredId, _ForeignProcId,
|
|
_Args, _ExtraArgs, _MaybeTraceRuntimeCond, _Impl)
|
|
;
|
|
GoalExpr0 = shorthand(_),
|
|
% These should have been expanded out by now.
|
|
unexpected($pred, "shorthand")
|
|
).
|
|
|
|
:- pred unification_set_reuse(short_reuse_description::in,
|
|
unification::in, unification::out) is det.
|
|
|
|
unification_set_reuse(ShortReuseDescription, !Unification) :-
|
|
( if
|
|
HowToConstruct0 = !.Unification ^ construct_how,
|
|
ShortReuseDescription = cell_reused(DeadVar, _, PossibleConsIds,
|
|
CellsToUpdate)
|
|
then
|
|
(
|
|
HowToConstruct0 = construct_statically
|
|
% Leave static terms as-is.
|
|
;
|
|
( HowToConstruct0 = construct_dynamically
|
|
; HowToConstruct0 = construct_in_region(_)
|
|
; HowToConstruct0 = reuse_cell(_)
|
|
),
|
|
CellToReuse = cell_to_reuse(DeadVar, PossibleConsIds,
|
|
CellsToUpdate),
|
|
HowToConstruct = reuse_cell(CellToReuse),
|
|
!Unification ^ construct_how := HowToConstruct
|
|
)
|
|
else
|
|
true
|
|
).
|
|
|
|
:- pred determine_reuse_version(reuse_as_table::in, module_info::in,
|
|
pred_id::in, proc_id::in, sym_name::in, list(int)::in,
|
|
pred_id::out, proc_id::out, reuse_name::out) is det.
|
|
|
|
determine_reuse_version(ReuseTable, ModuleInfo, PredId, ProcId, PredName,
|
|
NoClobbers, ReusePredId, ReuseProcId, ReusePredName) :-
|
|
( if
|
|
reuse_as_table_search_reuse_version_proc(ReuseTable,
|
|
proc(PredId, ProcId), NoClobbers, Result)
|
|
then
|
|
Result = proc(ReusePredId, ReuseProcId),
|
|
module_info_pred_info(ModuleInfo, ReusePredId, ReusePredInfo),
|
|
ModuleName = pred_info_module(ReusePredInfo),
|
|
Name = pred_info_name(ReusePredInfo),
|
|
ReusePredName = qualified(ModuleName, Name)
|
|
else
|
|
ReusePredId = PredId,
|
|
ReuseProcId = ProcId,
|
|
ReusePredName = PredName
|
|
).
|
|
|
|
:- pred process_case(convert_potential_reuse::in, reuse_as_table::in,
|
|
module_info::in, case::in, case::out) is det.
|
|
|
|
process_case(ConvertPotentialReuse, ReuseMap, ModuleInfo, Case0, Case) :-
|
|
Case0 = case(MainConsId, OtherConsIds, Goal0),
|
|
process_goal(ConvertPotentialReuse, ReuseMap, ModuleInfo, Goal0, Goal),
|
|
Case = case(MainConsId, OtherConsIds, Goal).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
create_fake_reuse_procedure(PPId, NoClobbers, !ModuleInfo) :-
|
|
PPId = proc(PredId, ProcId),
|
|
module_info_pred_proc_info(!.ModuleInfo, PPId, OldPredInfo, OldProcInfo),
|
|
OldPredModule = pred_info_module(OldPredInfo),
|
|
OldPredName = pred_info_name(OldPredInfo),
|
|
proc_info_interface_determinism(OldProcInfo, Determinism),
|
|
|
|
create_fresh_pred_proc_info_copy(PPId, NoClobbers, NewPPId, !ModuleInfo),
|
|
some [!PredInfo, !ProcInfo] (
|
|
module_info_pred_proc_info(!.ModuleInfo, NewPPId, !:PredInfo,
|
|
!:ProcInfo),
|
|
proc_info_get_goal(!.ProcInfo, Body),
|
|
Body = hlds_goal(_, GoalInfo0),
|
|
proc_info_get_headvars(!.ProcInfo, HeadVars),
|
|
GoalExpr = plain_call(PredId, ProcId, HeadVars, not_builtin, no,
|
|
qualified(OldPredModule, OldPredName)),
|
|
goal_info_set_determinism(Determinism, GoalInfo0, GoalInfo),
|
|
Goal = hlds_goal(GoalExpr, GoalInfo),
|
|
proc_info_set_goal(Goal, !ProcInfo),
|
|
module_info_set_pred_proc_info(NewPPId, !.PredInfo, !.ProcInfo,
|
|
!ModuleInfo)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- end_module structure_reuse.versions.
|
|
%-----------------------------------------------------------------------------%
|