mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 17:33:38 +00:00
... with the du_data_ctor/1 cons_id, which contains a du_ctor/3.
Putting all the info about discriminated union data constructors into a
separate type allows code that works only with the cons_ids of du types
to stop having to worry about all the other kinds of cons_ids.
compiler/prog_data.m:
As above.
Delete the cons_ctor type from this module after moving it to
recompilation.usage.m, which is the only part of the compiler
that uses it.
compiler/add_foreign_enum.m:
Replace cons_id_to_tag_map with du_ctor_to_tag_map, since the only
cons_ids the map handles are du_ctors.
compiler/hlds_cons.m:
Replace cons_ids with du_ctors in the cons_table and in the
info we keep about du types' fields.
compiler/hlds_data.m:
Replace cons_ids with du_ctors in cheaper_tag_tests.
Provide two forms of a utility function. Both return du_ctors,
but one wraps them up as cons_ids.
compiler/type_assign.m:
Replace cons_ids with du_ctors in cons_type_info_sources.
compiler/type_util.m:
Switch many of the utility predicates and functions in this module
to operate on du_ctors instead of cons_ids. Split some of the others
to have both du_ctor and cons_id versions.
Replace a predicate that returned a set of solutions one at a time
on backtracking with a predicate that returns all the solutions
at once in a list.
Reduce unnecessary variability in variable names.
Add some XXXs for code with unclear motivations.
compiler/typecheck_error_undef.m:
Delete a function argument that was used only in a sanity check,
because the code at its only call site derived that argument using code
that made it impossible for the sanity check to fail.
Factor out some common code.
compiler/parse_tree_out_cons_id.m:
For three functions that operate on cons_ids, add versions
that do the same job on du_ctors.
compiler/inst_match.m:
Conform to the changes above. This diff rewrites from scratch
the algorithm for testing whether a list of bound insts covers
*all* the du_ctors of a type, because the old code was both inefficient
and very opaque.
compiler/float_regs.m:
Conform to the changes above, and delete a conditionally enabled abort
that shouldn't ever be enabled.
compiler/inst_util.m:
Conform to the changes above, and rename a predicate to avoid
an ambiguity.
compiler/mode_errors.m:
Conform to the changes above, and switch to printing the cons_ids
in some error messages using the standard mechanisms of
write_error_spec.m.
compiler/resolve_unify_functor.m:
Conform to the changes above. Factor out repeated tests against
du_data_ctor.
compiler/term_norm.m:
Conform to the changes above. Add XXXs for some bugs.
compiler/add_type.m:
compiler/assertion.m:
compiler/builtin_lib_types.m:
compiler/comp_unit_interface.m:
compiler/complexity.m:
compiler/const_struct.m:
compiler/cse_detection.m:
compiler/ctgc.selector.m:
compiler/dead_proc_elim.m:
compiler/deep_profiling.m:
compiler/delay_partial_inst.m:
compiler/direct_arg_in_out.m:
compiler/distance_granularity.m:
compiler/du_type_layout.m:
compiler/error_msg_inst.m:
compiler/field_access.m:
compiler/format_call.m:
compiler/goal_expr_to_goal.m:
compiler/goal_util.m:
compiler/hhf.m:
compiler/higher_order.specialize_calls.m:
compiler/higher_order.specialize_unify_compare.m:
compiler/hlds_code_util.m:
compiler/hlds_dependency_graph.m:
compiler/hlds_out_goal.m:
compiler/hlds_out_type_table.m:
compiler/hlds_out_util.m:
compiler/implementation_defined_literals.m:
compiler/inst_abstract_unify.m:
compiler/inst_check.m:
compiler/inst_merge.m:
compiler/inst_mode_type_prop.m:
compiler/inst_test.m:
compiler/instmap.m:
compiler/intermod.m:
compiler/intermod_decide.m:
compiler/lco.m:
compiler/ml_global_data.m:
compiler/ml_unify_gen_construct.m:
compiler/ml_unify_gen_deconstruct.m:
compiler/ml_unify_gen_util.m:
compiler/mode_top_functor.m:
compiler/mode_util.m:
compiler/modecheck_coerce.m:
compiler/modecheck_goal.m:
compiler/modecheck_unify.m:
compiler/modecheck_util.m:
compiler/module_qual.qualify_items.m:
compiler/old_type_constraints.m:
compiler/parse_inst_mode_name.m:
compiler/parse_tree_out_item.m:
compiler/parse_tree_to_term.m:
compiler/polymorphism_goal.m:
compiler/polymorphism_lambda.m:
compiler/pre_typecheck.m:
compiler/prog_ctgc.m:
compiler/prog_mode.m:
compiler/prog_rep.m:
compiler/prog_type.m:
compiler/prog_util.m:
compiler/purity.m:
compiler/qual_info.m:
compiler/rbmm.execution_path.m:
compiler/rbmm.region_transformation.m:
compiler/recompilation.usage.m:
compiler/recompilation.used_file.m:
compiler/recompute_instmap_deltas.m:
compiler/simplify_goal.m:
compiler/simplify_goal_call.m:
compiler/simplify_goal_switch.m:
compiler/simplify_goal_unify.m:
compiler/size_prof.m:
compiler/ssdebug.m:
compiler/stack_opt.m:
compiler/structure_reuse.direct_choose_reuse.m:
compiler/structure_reuse.direct_detect_garbage.m:
compiler/superhomogeneous.m:
compiler/table_gen.m:
compiler/term_constr_build.m:
compiler/typecheck_clauses.m:
compiler/typecheck_error_util.m:
compiler/typecheck_errors.m:
compiler/unify_gen_test.m:
compiler/unify_gen_util.m:
compiler/unify_proc.m:
compiler/untupling.m:
compiler/unused_imports.m:
compiler/xml_documentation.m:
Conform to the changes above.
tests/invalid/coerce_int.err_exp:
tests/invalid/coerce_mode_error.err_exp:
tests/invalid/coerce_mode_error2.err_exp:
tests/invalid/coerce_recursive_inst.err_exp:
tests/invalid/coerce_recursive_type.err_exp:
Expect diagnostics generated using the standard error_spec representations
of cons_ids.
293 lines
12 KiB
Mathematica
293 lines
12 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2005-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 rbmm.execution_path.m.
|
|
% Main author: Quan Phan.
|
|
%
|
|
% This module collects all execution paths (ExecPath) of procedures.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module transform_hlds.rbmm.execution_path.
|
|
:- interface.
|
|
|
|
:- import_module hlds.
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module transform_hlds.rbmm.region_liveness_info.
|
|
|
|
% Collects execution paths for each procedure.
|
|
%
|
|
:- pred execution_path_analysis(module_info::in, execution_path_table::out)
|
|
is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module hlds.goal_form.
|
|
:- import_module hlds.goal_path.
|
|
:- import_module hlds.hlds_goal.
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module transform_hlds.smm_common.
|
|
|
|
:- import_module list.
|
|
:- import_module map.
|
|
:- import_module pair.
|
|
:- import_module require.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Execution path analysis
|
|
%
|
|
|
|
execution_path_analysis(ModuleInfo, ExecPathTable) :-
|
|
module_info_get_valid_pred_ids(ModuleInfo, PredIds),
|
|
map.init(ExecPathTable0),
|
|
list.foldl(execution_path_analysis_pred(ModuleInfo), PredIds,
|
|
ExecPathTable0, ExecPathTable).
|
|
|
|
:- pred execution_path_analysis_pred(module_info::in, pred_id::in,
|
|
execution_path_table::in, execution_path_table::out)
|
|
is det.
|
|
|
|
execution_path_analysis_pred(ModuleInfo, PredId, !ExecPathTable) :-
|
|
module_info_pred_info(ModuleInfo, PredId, PredInfo),
|
|
ProcIds = pred_info_all_non_imported_procids(PredInfo),
|
|
list.foldl(execution_path_analysis_proc(ModuleInfo, PredId), ProcIds,
|
|
!ExecPathTable).
|
|
|
|
:- pred execution_path_analysis_proc(module_info::in, pred_id::in,
|
|
proc_id::in, execution_path_table::in, execution_path_table::out) is det.
|
|
|
|
execution_path_analysis_proc(ModuleInfo, PredId, ProcId, !ExecPathTable) :-
|
|
PPId = proc(PredId, ProcId),
|
|
( if some_are_special_preds([PPId], ModuleInfo) then
|
|
true
|
|
else
|
|
module_info_proc_info(ModuleInfo, PPId, ProcInfo),
|
|
compute_execution_paths(ProcInfo, ModuleInfo, ExecPaths),
|
|
map.set(PPId, ExecPaths, !ExecPathTable)
|
|
).
|
|
|
|
% Compute all execution paths in the procedure.
|
|
%
|
|
:- pred compute_execution_paths(proc_info::in, module_info::in,
|
|
list(execution_path)::out) is det.
|
|
|
|
compute_execution_paths(ProcInfo0, ModuleInfo, ExecPaths) :-
|
|
% Fill the goals with program point information.
|
|
fill_goal_path_slots_in_proc(ModuleInfo, ProcInfo0, ProcInfo),
|
|
proc_info_get_goal(ProcInfo, Goal),
|
|
ExecPaths0 = [[]],
|
|
execution_paths_covered_goal(ProcInfo, Goal, ExecPaths0, ExecPaths).
|
|
|
|
% Extend the given execution paths to cover this goal.
|
|
%
|
|
:- pred execution_paths_covered_goal(proc_info::in, hlds_goal::in,
|
|
list(execution_path)::in, list(execution_path)::out) is det.
|
|
|
|
execution_paths_covered_goal(ProcInfo, Goal, !ExecPaths) :-
|
|
Goal = hlds_goal(GoalExpr, GoalInfo),
|
|
HasSubGoals = goal_expr_has_subgoals(GoalExpr),
|
|
(
|
|
HasSubGoals = does_not_have_subgoals,
|
|
( if
|
|
( GoalExpr = unify(_, _, _, _, _)
|
|
; GoalExpr = plain_call(_, _, _, _, _, _)
|
|
; GoalExpr = conj(_ConjType, [])
|
|
; GoalExpr = disj([])
|
|
)
|
|
then
|
|
% Retrieve the program point of this goal.
|
|
ProgPoint = program_point_init(GoalInfo),
|
|
append_to_each_execution_path(!.ExecPaths,
|
|
[[pair(ProgPoint, Goal)]], !:ExecPaths)
|
|
else
|
|
% XXX: other kinds of atomic calls (generic_call,
|
|
% foreign_proc), TEMPORARILY ignored their corresponding pps.
|
|
% XXX: handle event_call and unsafe_cast generic_calls
|
|
append_to_each_execution_path(!.ExecPaths, [[]], !:ExecPaths)
|
|
)
|
|
;
|
|
HasSubGoals = has_subgoals,
|
|
execution_paths_covered_compound_goal(ProcInfo, Goal, !ExecPaths)
|
|
).
|
|
|
|
% Extend current execution paths to cover this compound goal.
|
|
%
|
|
:- pred execution_paths_covered_compound_goal(proc_info::in, hlds_goal::in,
|
|
list(execution_path)::in, list(execution_path)::out) is det.
|
|
|
|
execution_paths_covered_compound_goal(ProcInfo, CompoundGoal, !ExecPaths) :-
|
|
CompoundGoal = hlds_goal(Expr, _),
|
|
(
|
|
Expr = conj(_ConjType, [Conj | Conjs]),
|
|
execution_paths_covered_conj(ProcInfo, [Conj | Conjs], !ExecPaths)
|
|
;
|
|
Expr = switch(_, _, Cases),
|
|
execution_paths_covered_cases(ProcInfo, CompoundGoal, Cases,
|
|
!ExecPaths)
|
|
;
|
|
Expr = disj([Disj | Disjs]),
|
|
execution_paths_covered_disj(ProcInfo, [Disj | Disjs],
|
|
!ExecPaths)
|
|
;
|
|
Expr = negation(Goal),
|
|
execution_paths_covered_goal(ProcInfo, Goal, !ExecPaths)
|
|
;
|
|
Expr = scope(_, Goal),
|
|
% XXX We should special-case the handling of from_ground_term_construct
|
|
% scopes.
|
|
execution_paths_covered_goal(ProcInfo, Goal, !ExecPaths)
|
|
;
|
|
Expr = if_then_else(_V, Cond, Then, Else),
|
|
execution_paths_covered_goal(ProcInfo, Cond,
|
|
!.ExecPaths, ExecPathsCond),
|
|
execution_paths_covered_goal(ProcInfo, Then,
|
|
ExecPathsCond, ExecPathsCondThen),
|
|
execution_paths_covered_goal(ProcInfo, Else,
|
|
!.ExecPaths, ExecPathsElse),
|
|
!:ExecPaths = ExecPathsCondThen ++ ExecPathsElse
|
|
;
|
|
( Expr = unify(_, _, _, _, _)
|
|
; Expr = plain_call(_, _, _, _, _, _)
|
|
; Expr = conj(_, [])
|
|
; Expr = disj([])
|
|
; Expr = call_foreign_proc(_, _, _, _, _, _, _)
|
|
; Expr = generic_call(_, _, _, _, _)
|
|
; Expr = shorthand(_)
|
|
),
|
|
unexpected($pred, "encountered atomic or unsupported goal")
|
|
).
|
|
|
|
% Extend execution paths to cover the goals in this conjunction.
|
|
%
|
|
:- pred execution_paths_covered_conj(proc_info::in, list(hlds_goal)::in,
|
|
list(execution_path)::in, list(execution_path)::out) is det.
|
|
|
|
execution_paths_covered_conj(_, [], !ExecPaths).
|
|
execution_paths_covered_conj(ProcInfo, [Conj | Conjs], !ExecPaths) :-
|
|
execution_paths_covered_goal(ProcInfo, Conj, !ExecPaths),
|
|
execution_paths_covered_conj(ProcInfo, Conjs, !ExecPaths).
|
|
|
|
% Extend execution paths to cover a disjunction.
|
|
% To do this we extend the execution paths from the beginning of the
|
|
% disjunction for each disjunct to obtain a set of execution paths
|
|
% for each disjuct. At the end of the disjunction we combine these.
|
|
%
|
|
:- pred execution_paths_covered_disj(proc_info::in, list(hlds_goal)::in,
|
|
list(execution_path)::in, list(execution_path)::out) is det.
|
|
|
|
execution_paths_covered_disj(_, [], _, []).
|
|
execution_paths_covered_disj(ProcInfo, [Disj | Disjs], !ExecPaths) :-
|
|
execution_paths_covered_goal(ProcInfo, Disj, !.ExecPaths,
|
|
ExecPathsDisj),
|
|
execution_paths_covered_disj(ProcInfo, Disjs, !.ExecPaths,
|
|
ExecPathsDisjs),
|
|
!:ExecPaths = ExecPathsDisj ++ ExecPathsDisjs.
|
|
|
|
% Extend execution paths to cover a switch.
|
|
% Switches are handled like disjunctions except that unifications
|
|
% involving the switch var sometimes need special handling.
|
|
% Unifications between the switch vars and a constant or a functor
|
|
% of arity zero are not explicitly present in the goal. This causes
|
|
% the execution paths to have fewer program points than they should.
|
|
% If this happens we need to add a program point for the removed
|
|
% unification. The goal corresponding to this introduced program
|
|
% point is the switch goal itself. This is so that we can get
|
|
% information about the switch var in the live variable analysis.
|
|
%
|
|
:- pred execution_paths_covered_cases(proc_info::in, hlds_goal::in,
|
|
list(case)::in, list(execution_path)::in, list(execution_path)::out)
|
|
is det.
|
|
|
|
execution_paths_covered_cases(_, _, [], _, []).
|
|
execution_paths_covered_cases(ProcInfo, Switch, [Case | Cases], !ExecPaths) :-
|
|
Case = case(MainConsId, OtherConsIds, CaseGoal),
|
|
expect(unify(OtherConsIds, []), $pred, "NYI: multi-cons-id cases"),
|
|
Switch = hlds_goal(_SwitchExpr, Info),
|
|
ProgPoint = program_point_init(Info),
|
|
|
|
% Handle the unification on the switch var if it has been removed.
|
|
% We add a dummy program point for this unification.
|
|
(
|
|
MainConsId = du_data_ctor(du_ctor(_SymName, Arity, _)),
|
|
( if Arity = 0 then
|
|
append_to_each_execution_path(!.ExecPaths,
|
|
[[pair(ProgPoint, Switch)]], ExecPathsBeforeCase)
|
|
else
|
|
ExecPathsBeforeCase = !.ExecPaths
|
|
)
|
|
;
|
|
( MainConsId = some_int_const(_)
|
|
; MainConsId = float_const(_Float)
|
|
; MainConsId = char_const(_Char)
|
|
; MainConsId = string_const(_String)
|
|
),
|
|
% need to add a dummy pp
|
|
append_to_each_execution_path(!.ExecPaths,
|
|
[[pair(ProgPoint, Switch)]], ExecPathsBeforeCase)
|
|
;
|
|
( MainConsId = tuple_cons(_)
|
|
; MainConsId = closure_cons(_)
|
|
; MainConsId = impl_defined_const(_)
|
|
; MainConsId = type_ctor_info_const(_, _, _)
|
|
; MainConsId = base_typeclass_info_const(_, _, _, _)
|
|
; MainConsId = type_info_cell_constructor(_)
|
|
; MainConsId = typeclass_info_cell_constructor
|
|
; MainConsId = type_info_const(_)
|
|
; MainConsId = typeclass_info_const(_)
|
|
; MainConsId = ground_term_const(_, _)
|
|
; MainConsId = tabling_info_const(_)
|
|
; MainConsId = table_io_entry_desc(_)
|
|
; MainConsId = deep_profiling_proc_layout(_)
|
|
),
|
|
unexpected($pred, "unexpected cons_id")
|
|
),
|
|
execution_paths_covered_goal(ProcInfo, CaseGoal,
|
|
ExecPathsBeforeCase, ExecPathsCase),
|
|
execution_paths_covered_cases(ProcInfo, Switch, Cases,
|
|
!.ExecPaths, ExecPathsCases),
|
|
!:ExecPaths = ExecPathsCase ++ ExecPathsCases.
|
|
|
|
% Extend each execution path in the first list with each in the
|
|
% second list, all the extended execution paths are put in the third list.
|
|
%
|
|
:- pred append_to_each_execution_path(list(execution_path)::in,
|
|
list(execution_path)::in, list(execution_path)::out) is det.
|
|
|
|
append_to_each_execution_path([], _, []).
|
|
append_to_each_execution_path([ExecPath | ExecPaths], Extensions,
|
|
ExtendedExecPaths) :-
|
|
extend_exectution_path(ExecPath, Extensions, ExtendedExecPaths0),
|
|
append_to_each_execution_path(ExecPaths, Extensions,
|
|
ExtendedExecPaths1),
|
|
ExtendedExecPaths = ExtendedExecPaths0 ++ ExtendedExecPaths1.
|
|
|
|
% extend_exectution_path(ExecPath, Extensions, ExtendedExecPaths):
|
|
%
|
|
% ExtendedExecPaths is the list created by appending each extension
|
|
% in Extensions to ExecPath.
|
|
%
|
|
:- pred extend_exectution_path(execution_path::in, list(execution_path)::in,
|
|
list(execution_path)::out) is det.
|
|
|
|
extend_exectution_path(_, [], []).
|
|
extend_exectution_path(ExecPath, [Extension | Extensions],
|
|
ExtendedExecPaths) :-
|
|
ExtendedExecPath = ExecPath ++ Extension,
|
|
extend_exectution_path(ExecPath, Extensions, ExtendedExecPaths0),
|
|
ExtendedExecPaths = [ExtendedExecPath | ExtendedExecPaths0].
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module transform_hlds.rbmm.execution_path.
|
|
%---------------------------------------------------------------------------%
|