mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-22 12:53:47 +00:00
The code_info type was originally designed to be a single data structure
that holds all of the state of the LLDS code generator. It HAD to be a single
data structure then, because the DCGs we used to pass state around only
supported passing around ONE piece of state. Nevertheless, it contained
three separate kinds of information:
1 static information, which never changed during the lifetime of a code_info
structure (such as the pred and proc id of the procedure being compiled),
2 persistent information, whose updates were never undone (such as the maximum
number of temporaries that were ever needed at any one time), and
3 location dependent information, such as "which variables are stored where",
whose updates *can* be undone when the code generator jumps back to
a previously visited point in the code, e.g. to start generating code
for the next disjunct in a disjunction.
Originally, these three kinds of fields were all jumbled up together, but
about ten years ago, I grouped all the fields of the same kind together,
into substructures of code_info named code_info_static, code_info_persistent
and code_info_loc_dep respectively. This improved matters, but some problems
remained, the most important of which is that the code_info always contained
the location dependent information, even when it wasn't meaningful, and there
was no way of indicating this fact. (After initialization, the other two parts
are always meaningful.)
This diff separates out the location dependent part of the code_info
into a new type, code_loc_dep, that can be passed around independently
of the code_info, which now contains only the first two kinds of information
above. In places where the location-dependent information is not meaningful,
you don't need to have a current code_loc_dep.
This separation also makes it easier to see what updates to the code generator
state change only the persistent part (the updated code_info type), only
the location-dependent part (the new code_loc_dep type), or both.
In the process of making this change, I found several places where the
location-dependent part of the code_info (now the code_loc_dep) was being
updated, only for those updates to be thrown away, unread, a short time later.
This happened at the ends of branches in e.g. switches, with the updated
code_loc_deps being thrown away when code generation started working on
the next branch.
compiler/code_loc_dep.m:
New module containing the location-dependent part of the LLDS code
generator state. Its contents are derived from those parts of the
old contents of code_info.m that deal with location-dependent state.
Many of the predicates moved here work on only on the code_loc_dep
structure, some others work on both the code_info and code_loc_dep
structure, and a few work only on the code_info. Predicates in the last
category are in code_loc_dep.m only if they are either (a) used only
in this module, or (b) used only with other predicates in this module.
compiler/ll_backend.m:
compiler/notes/compiler_design.html:
Mention the new module.
compiler/code_info.m:
Delete the code now in code_loc_dep.m.
Make the vartypes a field in the static part of the code_info, since it is
used quite often. (We used to look it up in the proc_info every time.)
Put the declarations and definitions of the access predicates in an order
that is consistent with the order of the fields they work on.
Give some fields and predicates more descriptive names.
compiler/call_gen.m:
compiler/code_gen.m:
compiler/commit_gen.m:
compiler/dense_switch.m:
compiler/disj_gen.m:
compiler/ite_gen.m:
compiler/ll_backend.m:
compiler/lookup_switch.m:
compiler/lookup_util.m:
compiler/middle_rec.m:
compiler/par_conj_gen.m:
compiler/pragma_c_gen.m:
compiler/proc_gen.m:
compiler/string_switch.m:
compiler/switch_case.m:
compiler/switch_gen.m:
compiler/tag_switch.m:
compiler/trace_gen.m:
compiler/unify_gen.m:
compiler/var_locn.m:
Conform to and take advantage of the changes above.
Often this required passing an in/out pair of code_loc_deps as well as
an in/out pair of code_infos, but in many cases, one or more of these
would not be needed.
Don't make changes to the code_loc_dep at the end of an arm of a branched
control structure if those updates are about be thrown away when we
start generating code for the next arm.
In several cases, switch to a strategy of taking a snapshot of the
code_loc_dep before entering a branched control structure as a whole,
and restoring that state at the start of each arm. We used to take
a snapshot at the start of each branch, and restore it at its end,
to be ready for the next branch. The former is easier to make
correctness arguments about, since the code_loc_dep in an arm
often has limited scope.
Make some minor unrelated improvements, such as eliminating the
unnecessary use of solutions/2, and reordering tests for slightly
better performance.
114 lines
4.4 KiB
Mathematica
114 lines
4.4 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1997-1998, 2003-2007, 2009-2011 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: commit_gen.m.
|
|
% Main authors: conway, fjh, zs.
|
|
%
|
|
% The predicates of this module generate code for performing commits.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module ll_backend.commit_gen.
|
|
:- interface.
|
|
|
|
:- import_module hlds.code_model.
|
|
:- import_module hlds.hlds_goal.
|
|
:- import_module ll_backend.code_info.
|
|
:- import_module ll_backend.code_loc_dep.
|
|
:- import_module ll_backend.llds.
|
|
:- import_module parse_tree.set_of_var.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred generate_scope(scope_reason::in, code_model::in, hlds_goal_info::in,
|
|
set_of_progvar::in, hlds_goal::in, llds_code::out,
|
|
code_info::in, code_info::out, code_loc_dep::in, code_loc_dep::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module ll_backend.code_gen.
|
|
% :- import_module parse_tree.prog_data.
|
|
% :- import_module set.
|
|
|
|
:- import_module cord.
|
|
:- import_module maybe.
|
|
:- import_module require.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
generate_scope(Reason, OuterCodeModel, OuterGoalInfo,
|
|
ForwardLiveVarsBeforeGoal, Goal, Code, !CI, !CLD) :-
|
|
(
|
|
Reason = trace_goal(_, MaybeTraceRuntimeCond, _, _, _),
|
|
MaybeTraceRuntimeCond = yes(_)
|
|
->
|
|
% These goals should have been transformed into other forms of goals
|
|
% by simplify.m at the end of semantic analysis.
|
|
unexpected($module, $pred, "trace_goal")
|
|
;
|
|
generate_commit(OuterCodeModel, OuterGoalInfo,
|
|
ForwardLiveVarsBeforeGoal, Goal, Code, !CI, !CLD)
|
|
).
|
|
|
|
:- pred generate_commit(code_model::in, hlds_goal_info::in, set_of_progvar::in,
|
|
hlds_goal::in, llds_code::out,
|
|
code_info::in, code_info::out, code_loc_dep::in, code_loc_dep::out) is det.
|
|
|
|
generate_commit(OuterCodeModel, OuterGoalInfo, ForwardLiveVarsBeforeGoal,
|
|
Goal, Code, !CI, !CLD) :-
|
|
AddTrailOps = should_add_trail_ops(!.CI, OuterGoalInfo),
|
|
AddRegionOps = should_add_region_ops(!.CI, OuterGoalInfo),
|
|
|
|
Goal = hlds_goal(_, InnerGoalInfo),
|
|
InnerCodeModel = goal_info_get_code_model(InnerGoalInfo),
|
|
(
|
|
OuterCodeModel = model_det,
|
|
(
|
|
InnerCodeModel = model_det,
|
|
code_gen.generate_goal(InnerCodeModel, Goal, Code, !CI, !CLD)
|
|
;
|
|
InnerCodeModel = model_semi,
|
|
unexpected($module, $pred, "semidet model in det context")
|
|
;
|
|
InnerCodeModel = model_non,
|
|
prepare_for_det_commit(AddTrailOps, AddRegionOps,
|
|
ForwardLiveVarsBeforeGoal, InnerGoalInfo, CommitInfo,
|
|
PreCommit, !CI, !CLD),
|
|
code_gen.generate_goal(InnerCodeModel, Goal, GoalCode, !CI, !CLD),
|
|
generate_det_commit(CommitInfo, Commit, !CI, !CLD),
|
|
Code = PreCommit ++ GoalCode ++ Commit
|
|
)
|
|
;
|
|
OuterCodeModel = model_semi,
|
|
(
|
|
InnerCodeModel = model_det,
|
|
code_gen.generate_goal(InnerCodeModel, Goal, Code, !CI, !CLD)
|
|
;
|
|
InnerCodeModel = model_semi,
|
|
code_gen.generate_goal(InnerCodeModel, Goal, Code, !CI, !CLD)
|
|
;
|
|
InnerCodeModel = model_non,
|
|
prepare_for_semi_commit(AddTrailOps, AddRegionOps,
|
|
ForwardLiveVarsBeforeGoal, InnerGoalInfo, CommitInfo,
|
|
PreCommit, !CI, !CLD),
|
|
code_gen.generate_goal(InnerCodeModel, Goal, GoalCode, !CI, !CLD),
|
|
generate_semi_commit(CommitInfo, Commit, !CI, !CLD),
|
|
Code = PreCommit ++ GoalCode ++ Commit
|
|
)
|
|
;
|
|
OuterCodeModel = model_non,
|
|
code_gen.generate_goal(InnerCodeModel, Goal, Code, !CI, !CLD)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module ll_backend.commit_gen.
|
|
%---------------------------------------------------------------------------%
|