Files
mercury/compiler/goal_contains.m
Zoltan Somogyi 0c23ad7c64 Carve five new modules out of goal_util.m.
Each of the new modules has much better cohesion than the old goal_util.m.

There are no algorithmic changes.

compiler/goal_contains.m:
    New module for predicates that compute what subgoals a goal contains.

compiler/goal_refs.m:
    New module for predicates that compute what predicates a goal
    calls or otherwise references.

compiler/goal_reorder.m:
    New module for predicates that test whether two goals can be reordered.

compiler/goal_transform.m:
    New module for predicates that transform goals.

compiler/goal_vars.m:
    New module for predicates that compute what variables occur in a goal.

compiler/goal_util.m:
    Delete the code moved to the new modules. Move some related predicates
    next to each other.

compiler/hlds.m:
compiler/notes/compiler_design.html:
    Include and document the new modules.

compiler/*.m:
    Conform to the changes above. Most import just one of the old
    goal_util.m's six successor modules; some import two; while a very few
    import three. None import more than that.
2025-05-22 22:54:48 +10:00

236 lines
7.9 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 1995-2012 The University of Melbourne.
% Copyright (C) 2015-2019, 2021-2025 The Mercury team.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%---------------------------------------------------------------------------%
%
% File: goal_contains.m.
%
% This module provides predicates to answer the question
% "what subgoals does this goal contain?".
%
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- module hlds.goal_contains.
:- interface.
:- import_module hlds.hlds_goal.
:- import_module bool.
%---------------------------------------------------------------------------%
% Test whether the goal contains a reconstruction
% (a construction where the `construct_how' field is `cell_to_reuse(_)').
%
:- pred goal_contains_reconstruction(hlds_goal::in, bool::out) is det.
%---------------------%
% goal_contains_goal(Goal, SubGoal) is true iff Goal contains SubGoal,
% i.e. iff Goal = SubGoal or Goal contains SubGoal as a direct
% or indirect sub-goal.
%
:- pred goal_contains_goal(hlds_goal::in, hlds_goal::out) is multi.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
:- import_module hlds.hlds_pred.
:- import_module mdbcomp.
:- import_module mdbcomp.sym_name.
:- import_module parse_tree.
:- import_module parse_tree.prog_data.
:- import_module parse_tree.prog_data_foreign.
:- import_module list.
:- import_module maybe.
%---------------------------------------------------------------------------%
goal_contains_reconstruction(Goal, ContainsReconstruction) :-
Goal = hlds_goal(GoalExpr, _),
(
GoalExpr = conj(_ConjType, Conjuncts),
goals_contain_reconstruction(Conjuncts, ContainsReconstruction)
;
GoalExpr = disj(Disjuncts),
goals_contain_reconstruction(Disjuncts, ContainsReconstruction)
;
GoalExpr = switch(_, _, Cases),
cases_contain_reconstruction(Cases, ContainsReconstruction)
;
GoalExpr = if_then_else(_, Cond, Then, Else),
( if
( goal_contains_reconstruction(Cond, yes)
; goal_contains_reconstruction(Then, yes)
; goal_contains_reconstruction(Else, yes)
)
then
ContainsReconstruction = yes
else
ContainsReconstruction = no
)
;
GoalExpr = negation(SubGoal),
goal_contains_reconstruction(SubGoal, ContainsReconstruction)
;
GoalExpr = scope(Reason, SubGoal),
( if
Reason = from_ground_term(_, FGT),
( FGT = from_ground_term_construct
; FGT = from_ground_term_deconstruct
)
then
% Construct scopes contain only construction unifications
% that do no reuse. Deconstruct scopes do not contain
% any constructions at all.
ContainsReconstruction = no
else
goal_contains_reconstruction(SubGoal, ContainsReconstruction)
)
;
GoalExpr = unify(_, _, _, Unify, _),
( if
Unify = construct(_, _, _, _, HowToConstruct, _, _),
HowToConstruct = reuse_cell(_)
then
ContainsReconstruction = yes
else
ContainsReconstruction = no
)
;
( GoalExpr = plain_call(_, _, _, _, _, _)
; GoalExpr = generic_call(_, _, _, _, _)
; GoalExpr = call_foreign_proc(_, _, _, _, _, _, _)
),
ContainsReconstruction = no
;
GoalExpr = shorthand(Shorthand),
(
Shorthand = bi_implication(GoalA, GoalB),
( if
goal_contains_reconstruction(GoalA, yes),
goal_contains_reconstruction(GoalB, yes)
then
ContainsReconstruction = yes
else
ContainsReconstruction = no
)
;
Shorthand = atomic_goal(_AtomicGoalType, _OuterVars, _InnerVars,
_OutputVars, MainGoal, OrElseGoals, _Inners),
( if
goal_contains_reconstruction(MainGoal, yes),
goals_contain_reconstruction(OrElseGoals, yes)
then
ContainsReconstruction = yes
else
ContainsReconstruction = no
)
;
Shorthand = try_goal(_MaybeTryIOStateVars, _ResultVar, SubGoal),
goal_contains_reconstruction(SubGoal, ContainsReconstruction)
)
).
:- pred goals_contain_reconstruction(list(hlds_goal)::in, bool::out) is det.
goals_contain_reconstruction([], no).
goals_contain_reconstruction([Goal | Goals], ContainsReconstruction) :-
goal_contains_reconstruction(Goal, HeadContainsReconstruction),
(
HeadContainsReconstruction = yes,
ContainsReconstruction = yes
;
HeadContainsReconstruction = no,
goals_contain_reconstruction(Goals, ContainsReconstruction)
).
:- pred cases_contain_reconstruction(list(case)::in, bool::out) is det.
cases_contain_reconstruction([], no).
cases_contain_reconstruction([Case | Cases], ContainsReconstruction) :-
Case = case(_, _, CaseGoal),
goal_contains_reconstruction(CaseGoal, HeadContainsReconstruction),
(
HeadContainsReconstruction = yes,
ContainsReconstruction = yes
;
HeadContainsReconstruction = no,
cases_contain_reconstruction(Cases, ContainsReconstruction)
).
%---------------------------------------------------------------------------%
goal_contains_goal(Goal, ContainedGoal) :-
(
ContainedGoal = Goal
;
Goal = hlds_goal(GoalExpr, _),
direct_subgoal(GoalExpr, DirectSubGoal),
goal_contains_goal(DirectSubGoal, ContainedGoal)
).
% direct_subgoal(Goal, DirectSubGoal) is true iff
% DirectSubGoal is a direct subgoal of Goal.
%
:- pred direct_subgoal(hlds_goal_expr::in, hlds_goal::out) is nondet.
direct_subgoal(GoalExpr, DirectSubGoal) :-
require_complete_switch [GoalExpr]
(
( GoalExpr = conj(_, DirectSubGoals)
; GoalExpr = disj(DirectSubGoals)
),
list.member(DirectSubGoal, DirectSubGoals)
;
GoalExpr = switch(_, _, Cases),
list.member(Case, Cases),
Case = case(_, _, DirectSubGoal)
;
GoalExpr = if_then_else(_, Cond, Then, Else),
( DirectSubGoal = Cond
; DirectSubGoal = Then
; DirectSubGoal = Else
)
;
GoalExpr = negation(DirectSubGoal)
;
GoalExpr = scope(_, DirectSubGoal)
;
( GoalExpr = unify(_, _, _, _, _)
; GoalExpr = plain_call(_, _, _, _, _, _)
; GoalExpr = generic_call(_, _, _, _, _)
; GoalExpr = call_foreign_proc(_, _, _, _, _, _, _)
),
fail
;
GoalExpr = shorthand(Shorthand),
% NOTE We used to fail for shorthand goals. This was either a bug,
% or a limitation that should have been documented.
(
Shorthand = bi_implication(SubGoalA, SubGoalB),
( DirectSubGoal = SubGoalA
; DirectSubGoal = SubGoalB
)
;
Shorthand = atomic_goal(_, _, _, _, MainGoal, OrElseGoals, _),
( DirectSubGoal = MainGoal
; list.member(DirectSubGoal, OrElseGoals)
)
;
Shorthand = try_goal(_, _, DirectSubGoal)
)
).
%---------------------------------------------------------------------------%
:- end_module hlds.goal_contains.
%---------------------------------------------------------------------------%