mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-18 10:53:40 +00:00
This step significantly improves module cohesion.
compiler/inst_abstract_unify.m:
New module carved out of inst_util.m, which does abstract unifications
on insts.
compiler/inst_merge.m:
New module carved out of inst_util.m, which merges insts.
compiler/inst_lookup.m:
New module carved partly out of inst_util.m and partly out of mode_util.m,
which looks up insts in the module_info, and then possibly expands out
the result.
compiler/mode_test.m:
New module carved out of mode_util.m, whose predicates
perform tests on modes.
compiler/mode_top_functor.m:
New module carved out of mode_util.m, which computes top_functor_modes
from modes.
compiler/inst_mode_type_prop.m:
New module carved out of mode_util.m, which propagates type information
into both insts and modes.
compiler/recompute_instmap_deltas.m:
New module carved out of mode_util.m, which recomputes goals'
instmap_deltas.
compiler/inst_test.m:
Move here the predicates in inst_util.m that perform tests on insts.
compiler/inst_util.m:
compiler/mode_util.m:
Delete the code that this diff moves to other modules.
compiler/check_hlds.m:
Add the new modules to the check_hlds package, the package that also
contains inst_util.m and mode_util.m. (Some of these modules could
be argued to fit better in the hlds package, but moving them there
would not be desirable while they depend on code that is still in the
check_hlds package.)
compiler/notes/compiler_design.html:
Document the new modules.
compiler/add_pragma_tabling.m:
compiler/arg_info.m:
compiler/bytecode_gen.m:
compiler/closure_analysis.m:
compiler/complexity.m:
compiler/deep_profiling.m:
compiler/deforest.m:
compiler/dep_par_conj.m:
compiler/det_report.m:
compiler/direct_arg_in_out.m:
compiler/distance_granularity.m:
compiler/equiv_type_hlds.m:
compiler/error_msg_inst.m:
compiler/fact_table.m:
compiler/float_regs.m:
compiler/follow_code.m:
compiler/goal_util.m:
compiler/higher_order.m:
compiler/hlds_pred.m:
compiler/hlds_rtti.m:
compiler/inlining.m:
compiler/inst_match.m:
compiler/inst_user.m:
compiler/instmap.m:
compiler/intermod.m:
compiler/interval.m:
compiler/introduce_exists_casts.m:
compiler/lambda.m:
compiler/lco.m:
compiler/liveness.m:
compiler/lookup_util.m:
compiler/loop_inv.m:
compiler/mark_tail_calls.m:
compiler/ml_args_util.m:
compiler/ml_code_util.m:
compiler/ml_foreign_proc_gen.m:
compiler/ml_unify_gen_construct.m:
compiler/ml_unify_gen_util.m:
compiler/mode_constraints.m:
compiler/mode_errors.m:
compiler/modecheck_call.m:
compiler/modecheck_coerce.m:
compiler/modecheck_goal.m:
compiler/modecheck_unify.m:
compiler/modecheck_util.m:
compiler/modes.m:
compiler/oisu_check.m:
compiler/par_conj_gen.m:
compiler/pd_util.m:
compiler/post_typecheck.m:
compiler/pragma_c_gen.m:
compiler/proc_requests.m:
compiler/prog_rep.m:
compiler/push_goals_together.m:
compiler/rbmm.region_transformation.m:
compiler/saved_vars.m:
compiler/simplify_goal_switch.m:
compiler/simplify_proc.m:
compiler/size_prof.m:
compiler/ssdebug.m:
compiler/stack_opt.m:
compiler/stm_expand.m:
compiler/stratify.m:
compiler/structure_reuse.versions.m:
compiler/structure_sharing.domain.m:
compiler/superhomogeneous.m:
compiler/table_gen.m:
compiler/term_constr_build.m:
compiler/term_pass2.m:
compiler/term_util.m:
compiler/tupling.m:
compiler/unify_gen_construct.m:
compiler/unify_gen_util.m:
compiler/unique_modes.m:
compiler/unneeded_code.m:
compiler/untupling.m:
compiler/unused_args.m:
Conform to the changes above by importing the required new modules,
sometimes in addition to inst_util.m or mode_util.m, but more usually
instead of them.
232 lines
9.7 KiB
Mathematica
232 lines
9.7 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1996-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: lookup_util.m.
|
|
% Author: zs.
|
|
%
|
|
% Utility predicates used by both lookup_switch.m and disj.m. These utility
|
|
% predicates help in the implementation of switches and disjunctions in which
|
|
% the code of each arm consists only of looking up the values of the output
|
|
% variables in a table.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module ll_backend.lookup_util.
|
|
:- interface.
|
|
|
|
:- import_module hlds.
|
|
:- import_module hlds.hlds_goal.
|
|
:- import_module hlds.hlds_llds.
|
|
:- import_module ll_backend.code_info.
|
|
:- import_module ll_backend.code_loc_dep.
|
|
:- import_module ll_backend.llds.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.set_of_var.
|
|
|
|
:- import_module list.
|
|
|
|
% Figure out which variables are bound in the goal.
|
|
% We do this by using the current instmap and the instmap delta in the
|
|
% goal info to work out which variables are [further] bound by the goal.
|
|
%
|
|
:- pred figure_out_output_vars(code_info::in, code_loc_dep::in,
|
|
hlds_goal_info::in, list(prog_var)::out) is det.
|
|
|
|
% To figure out if the outputs are constants, we
|
|
%
|
|
% - check whether the determinism and structure of the goal are right,
|
|
% - generate code for the case,
|
|
% - check to see if each of the output vars is a constant,
|
|
% - check to see that no actual code was generated.
|
|
%
|
|
% For large goals, step 2 can be expensive. Step 1 is a cheap way of
|
|
% finding out whether steps 3 and 4 would fail without first running
|
|
% step 2. Therefore the caller should call goal_is_conj_of_unify (which
|
|
% does step 1) on Goal before calling generate_constants_for_arm (which
|
|
% does steps 2, 3 and 4).
|
|
%
|
|
:- pred generate_constants_for_arm(position_info::in, hlds_goal::in,
|
|
list(prog_var)::in, abs_store_map::in, list(rval)::out,
|
|
branch_end::in, branch_end::out, set_of_progvar::out,
|
|
code_info::in, code_info::out) is semidet.
|
|
|
|
:- pred generate_constants_for_disjunct(position_info::in,
|
|
hlds_goal::in, list(prog_var)::in, abs_store_map::in,
|
|
list(rval)::out, branch_end::in, branch_end::out, set_of_progvar::out,
|
|
code_info::in, code_info::out) is semidet.
|
|
|
|
:- pred generate_constants_for_disjuncts(position_info::in,
|
|
list(hlds_goal)::in, list(prog_var)::in, abs_store_map::in,
|
|
list(list(rval))::out, branch_end::in, branch_end::out,
|
|
code_info::in, code_info::out) is semidet.
|
|
|
|
% set_liveness_and_end_branch(StoreMap, Liveness, !MaybeEnd, Code,
|
|
% !CI, !.CLD):
|
|
%
|
|
% Set the liveness to Liveness, move all the variables listed in StoreMap
|
|
% to their indicated locations, and end the current branch, updating
|
|
% !MaybeEnd in the process.
|
|
%
|
|
:- pred set_liveness_and_end_branch(abs_store_map::in, set_of_progvar::in,
|
|
branch_end::in, branch_end::out, llds_code::out, code_loc_dep::in) is det.
|
|
|
|
:- pred generate_offset_assigns(list(prog_var)::in, int::in, lval::in,
|
|
code_info::in, code_loc_dep::in, code_loc_dep::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module check_hlds.
|
|
:- import_module check_hlds.mode_test.
|
|
:- import_module hlds.code_model.
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module hlds.instmap.
|
|
:- import_module ll_backend.code_gen.
|
|
:- import_module ll_backend.exprn_aux.
|
|
|
|
:- import_module bool.
|
|
:- import_module cord.
|
|
:- import_module int.
|
|
:- import_module maybe.
|
|
:- import_module require.
|
|
|
|
figure_out_output_vars(CI, CLD, GoalInfo, OutVars) :-
|
|
InstMapDelta = goal_info_get_instmap_delta(GoalInfo),
|
|
( if instmap_delta_is_unreachable(InstMapDelta) then
|
|
OutVars = []
|
|
else
|
|
get_instmap(CLD, CurrentInstMap),
|
|
get_module_info(CI, ModuleInfo),
|
|
instmap_delta_changed_vars(InstMapDelta, ChangedVars),
|
|
apply_instmap_delta(InstMapDelta, CurrentInstMap, InstMapAfter),
|
|
list.filter(is_output_var(ModuleInfo, CurrentInstMap, InstMapAfter),
|
|
set_of_var.to_sorted_list(ChangedVars), OutVars)
|
|
).
|
|
|
|
:- pred is_output_var(module_info::in, instmap::in, instmap::in, prog_var::in)
|
|
is semidet.
|
|
|
|
is_output_var(ModuleInfo, CurrentInstMap, InstMapAfter, Var) :-
|
|
% If a variable has a final inst, then it changed
|
|
% instantiatedness during the switch.
|
|
instmap_lookup_var(CurrentInstMap, Var, Initial),
|
|
instmap_lookup_var(InstMapAfter, Var, Final),
|
|
mode_is_output(ModuleInfo, from_to_mode(Initial, Final)).
|
|
|
|
generate_constants_for_arm(BranchStart, Goal, Vars, StoreMap, !MaybeEnd,
|
|
CaseRvals, Liveness, !CI) :-
|
|
do_generate_constants_for_arm(BranchStart, Goal, Vars, StoreMap,
|
|
no, !MaybeEnd, CaseRvals, Liveness, !CI).
|
|
|
|
:- pred do_generate_constants_for_arm(position_info::in, hlds_goal::in,
|
|
list(prog_var)::in, abs_store_map::in, bool::in, list(rval)::out,
|
|
branch_end::in, branch_end::out, set_of_progvar::out,
|
|
code_info::in, code_info::out) is semidet.
|
|
|
|
do_generate_constants_for_arm(BranchStart, Goal, Vars, StoreMap, SetToUnknown,
|
|
CaseRvals, !MaybeEnd, Liveness, !CI) :-
|
|
Goal = hlds_goal(_GoalExpr, GoalInfo),
|
|
CodeModel = goal_info_get_code_model(GoalInfo),
|
|
some [!CLD] (
|
|
reset_to_position(BranchStart, !.CI, !:CLD),
|
|
code_gen.generate_goal(CodeModel, Goal, Code, !CI, !CLD),
|
|
cord.is_empty(Code),
|
|
get_forward_live_vars(!.CLD, Liveness),
|
|
|
|
get_exprn_opts(!.CI, ExprnOpts),
|
|
get_arm_rvals(Vars, CaseRvals, !CLD, ExprnOpts),
|
|
(
|
|
SetToUnknown = no
|
|
;
|
|
SetToUnknown = yes,
|
|
set_resume_point_to_unknown(!CLD)
|
|
),
|
|
% EndCode code may contain instructions that place Vars in the
|
|
% locations dictated by StoreMap, and thus does not have to be empty.
|
|
% (The array lookup code will put those variables in those locations
|
|
% directly.)
|
|
generate_branch_end(StoreMap, !MaybeEnd, _EndCode, !.CLD)
|
|
).
|
|
|
|
generate_constants_for_disjunct(BranchStart, Disjunct0, Vars, StoreMap, Soln,
|
|
!MaybeEnd, Liveness, !CI) :-
|
|
% The pre_goal_update sanity check insists on no_resume_point, to ensure
|
|
% that all resume points have been handled by surrounding code.
|
|
Disjunct0 = hlds_goal(DisjunctGoalExpr, DisjunctGoalInfo0),
|
|
goal_info_set_resume_point(no_resume_point,
|
|
DisjunctGoalInfo0, DisjunctGoalInfo),
|
|
Disjunct = hlds_goal(DisjunctGoalExpr, DisjunctGoalInfo),
|
|
do_generate_constants_for_arm(BranchStart, Disjunct, Vars, StoreMap,
|
|
yes, Soln, !MaybeEnd, Liveness, !CI).
|
|
|
|
generate_constants_for_disjuncts(_StartPos, [], _Vars,
|
|
_StoreMap, [], !MaybeEnd, !CI).
|
|
generate_constants_for_disjuncts(StartPos, [Disjunct0 | Disjuncts0], Vars,
|
|
StoreMap, [Soln | Solns], !MaybeEnd, !CI) :-
|
|
generate_constants_for_disjunct(StartPos, Disjunct0, Vars,
|
|
StoreMap, Soln, !MaybeEnd, _Liveness, !CI),
|
|
generate_constants_for_disjuncts(StartPos, Disjuncts0, Vars,
|
|
StoreMap, Solns, !MaybeEnd, !CI).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred get_arm_rvals(list(prog_var)::in, list(rval)::out,
|
|
code_loc_dep::in, code_loc_dep::out, exprn_opts::in) is semidet.
|
|
|
|
get_arm_rvals([], [], !CLD, _ExprnOpts).
|
|
get_arm_rvals([Var | Vars], [Rval | Rvals], !CLD, ExprnOpts) :-
|
|
produce_variable(Var, Code, Rval, !CLD),
|
|
cord.is_empty(Code),
|
|
rval_is_constant(Rval, ExprnOpts),
|
|
get_arm_rvals(Vars, Rvals, !CLD, ExprnOpts).
|
|
|
|
% rval_is_constant(Rval, ExprnOpts) is true iff Rval is a constant.
|
|
% This depends on the options governing nonlocal gotos, asm labels enabled
|
|
% and static ground terms, etc.
|
|
%
|
|
:- pred rval_is_constant(rval::in, exprn_opts::in) is semidet.
|
|
|
|
rval_is_constant(const(Const), ExprnOpts) :-
|
|
exprn_aux.const_is_constant(Const, ExprnOpts, yes).
|
|
rval_is_constant(unop(_, Exprn), ExprnOpts) :-
|
|
rval_is_constant(Exprn, ExprnOpts).
|
|
rval_is_constant(binop(_, Exprn0, Exprn1), ExprnOpts) :-
|
|
rval_is_constant(Exprn0, ExprnOpts),
|
|
rval_is_constant(Exprn1, ExprnOpts).
|
|
rval_is_constant(mkword(_, Exprn0), ExprnOpts) :-
|
|
rval_is_constant(Exprn0, ExprnOpts).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
set_liveness_and_end_branch(StoreMap, Liveness, !MaybeEnd, BranchEndCode,
|
|
!.CLD) :-
|
|
% We keep track of what variables are supposed to be live at the end
|
|
% of cases. We have to do this explicitly because generating a `fail' slot
|
|
% last would yield the wrong liveness. Also, by killing the variables
|
|
% that are not live anymore, we avoid generating code that moves their
|
|
% values aside.
|
|
get_forward_live_vars(!.CLD, OldLiveness),
|
|
set_forward_live_vars(Liveness, !CLD),
|
|
set_of_var.difference(OldLiveness, Liveness, DeadVars),
|
|
maybe_make_vars_forward_dead(DeadVars, no, !CLD),
|
|
generate_branch_end(StoreMap, !MaybeEnd, BranchEndCode, !.CLD).
|
|
|
|
generate_offset_assigns([], _, _, _CI, !CLD).
|
|
generate_offset_assigns([Var | Vars], Offset, BaseReg, CI, !CLD) :-
|
|
LookupLval = field(yes(ptag(0u8)), lval(BaseReg),
|
|
const(llconst_int(Offset))),
|
|
assign_lval_to_var(Var, LookupLval, Code, CI, !CLD),
|
|
expect(cord.is_empty(Code), $pred, "nonempty code"),
|
|
generate_offset_assigns(Vars, Offset + 1, BaseReg, CI, !CLD).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module ll_backend.lookup_util.
|
|
%---------------------------------------------------------------------------%
|