Files
mercury/compiler/arg_info.m
Zoltan Somogyi b39a3d855f This diff makes hlds_module.m and many callers of its predicates easier to read
Estimated hours taken: 6
Branches: main

This diff makes hlds_module.m and many callers of its predicates easier to read
and to maintain, but contains no changes in algorithms whatsoever.

compiler/hlds_module.m:
	Bring (most of) this module into line with our current coding
	standards. Use predmode declarations, functions, and state variable
	syntax when appropriate. (The 'most of' is because I left the part of
	the module dealing with predicate tables alone, not wishing to cause
	a conflict for Pete.)

	Reorder arguments of predicates where necessary for the use of state
	variable syntax, and where this improves readability.

	Replace old-style lambdas with new-style lambdas or with partially
	applied named procedures.

compiler/*.m:
	Conform to the changes in hlds_module.m. This mostly means using the
	new argument orders of predicates exported by hlds_module.m, and
	switching to state variable notation.

	Replace old-style lambdas with new-style lambdas or with partially
	applied named procedures in updated code.

	Replace unnecessary occurrences of four-space indentation with
	standard indentation in updated code.

library/list.m:
library/map.m:
library/tree234.m:
	Add list__foldl4 and map__foldl3, since in some compiler modules,
	state variable notation is more convenient (and the code more
	efficient) if we don't have to bundle up several data structures
	into a tuple just to iterate over them.

	Change the fold predicates to use state variable notation.

NEWS:
	Mention the new library functions.
2003-10-31 03:27:39 +00:00

389 lines
14 KiB
Mathematica

%-----------------------------------------------------------------------------%
% Copyright (C) 1994-2000,2002-2003 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: arg_info.m
% main author: fjh
% This module is one of the pre-passes of the code generator.
% It initializes the arg_info field of the proc_info structure in the HLDS,
% which records for each argument of each procedure, whether the
% argument is input/output/unused, and which register it is supposed to
% go into.
%-----------------------------------------------------------------------------%
:- module ll_backend__arg_info.
:- interface.
:- import_module backend_libs__code_model.
:- import_module hlds__hlds_module.
:- import_module hlds__hlds_pred.
:- import_module ll_backend__llds.
:- import_module parse_tree__prog_data.
:- import_module list, assoc_list, set.
% Annotate every non-aditi procedure in the module with information
% about its argument passing interface.
:- pred generate_arg_info(module_info::in, module_info::out) is det.
% Annotate a single procedure with information
% about its argument passing interface.
:- pred generate_proc_arg_info(list(type)::in, module_info::in,
proc_info::in, proc_info::out) is det.
% Given the list of types and modes of the arguments of a procedure
% and its code model, return its argument passing interface.
:- pred make_arg_infos(list(type)::in, list(mode)::in, code_model::in,
module_info::in, list(arg_info)::out) is det.
% Given a procedure that already has its arg_info field filled in,
% return a list giving its input variables and their initial locations.
:- pred arg_info__build_input_arg_list(proc_info::in,
assoc_list(prog_var, lval)::out) is det.
% Divide the given list of arguments into those treated as inputs
% by the calling convention and those treated as outputs.
:- pred arg_info__compute_in_and_out_vars(module_info::in,
list(prog_var)::in, list(mode)::in, list(type)::in,
list(prog_var)::out, list(prog_var)::out) is det.
% Return the arg_infos for the two input arguments of a unification
% of the specified code model.
:- pred arg_info__unify_arg_info(code_model::in, list(arg_info)::out) is det.
% Divide the given list of arguments and the arg_infos into three
% lists: the inputs, the outputs, and the unused arguments, in that
% order.
:- pred arg_info__partition_args(assoc_list(prog_var, arg_info)::in,
assoc_list(prog_var, arg_info)::out,
assoc_list(prog_var, arg_info)::out,
assoc_list(prog_var, arg_info)::out) is det.
% Divide the given list of arguments and the arg_infos into two
% lists: those which are treated as inputs by the calling convention
% and those which are treated as outputs by the calling convention.
:- pred arg_info__partition_args(assoc_list(prog_var, arg_info)::in,
assoc_list(prog_var, arg_info)::out,
assoc_list(prog_var, arg_info)::out) is det.
% Partition the head variables of the given procedure into three sets:
% the inputs, the outputs, and the unused arguments. This is done based
% on the arg_info annotations of the arguments, which means that this
% predicate should only be called after the arg_info pass has been
% run.
:- pred arg_info__partition_proc_args(proc_info::in, module_info::in,
set(prog_var)::out, set(prog_var)::out, set(prog_var)::out) is det.
% Like arg_info__partition_proc_args, but partitions the actual
% arguments of a call (given in the fourth argument) instead of the
% head variables. Since the first (proc_info) argument is now the
% proc_info of the callee, we need to pass the types of the arguments
% (in the caller) separately.
:- pred arg_info__partition_proc_call_args(proc_info::in, vartypes::in,
module_info::in, list(prog_var)::in, set(prog_var)::out,
set(prog_var)::out, set(prog_var)::out) is det.
% Like arg_info__partition_proc_call_args, but partitions the actual
% arguments of a generic call, so instead of looking up the types and
% modes of the arguments in the module_info, we get them from the
% arguments.
:- pred arg_info__partition_generic_call_args(module_info::in,
list(prog_var)::in, list(type)::in, list(mode)::in,
set(prog_var)::out, set(prog_var)::out, set(prog_var)::out) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module check_hlds__mode_util.
:- import_module ll_backend__code_util.
:- import_module std_util, map, int, require.
%-----------------------------------------------------------------------------%
% This whole section just traverses the module structure.
generate_arg_info(ModuleInfo0, ModuleInfo) :-
module_info_preds(ModuleInfo0, Preds),
map__keys(Preds, PredIds),
generate_pred_arg_info(PredIds, ModuleInfo0, ModuleInfo).
:- pred generate_pred_arg_info(list(pred_id)::in,
module_info::in, module_info::out) is det.
generate_pred_arg_info([], !ModuleInfo).
generate_pred_arg_info([PredId | PredIds], !ModuleInfo) :-
module_info_preds(!.ModuleInfo, PredTable),
map__lookup(PredTable, PredId, PredInfo),
generate_proc_list_arg_info(PredId, pred_info_procids(PredInfo),
!ModuleInfo),
generate_pred_arg_info(PredIds, !ModuleInfo).
:- pred generate_proc_list_arg_info(pred_id::in, list(proc_id)::in,
module_info::in, module_info::out) is det.
generate_proc_list_arg_info(_PredId, [], !ModuleInfo).
generate_proc_list_arg_info(PredId, [ProcId | ProcIds],
!ModuleInfo) :-
module_info_preds(!.ModuleInfo, PredTable0),
map__lookup(PredTable0, PredId, PredInfo0),
( hlds_pred__pred_info_is_aditi_relation(PredInfo0) ->
true
;
pred_info_procedures(PredInfo0, ProcTable0),
pred_info_arg_types(PredInfo0, ArgTypes),
map__lookup(ProcTable0, ProcId, ProcInfo0),
generate_proc_arg_info(ArgTypes, !.ModuleInfo,
ProcInfo0, ProcInfo),
map__det_update(ProcTable0, ProcId, ProcInfo, ProcTable),
pred_info_set_procedures(ProcTable, PredInfo0, PredInfo),
map__det_update(PredTable0, PredId, PredInfo, PredTable),
module_info_set_preds(PredTable, !ModuleInfo)
),
generate_proc_list_arg_info(PredId, ProcIds, !ModuleInfo).
generate_proc_arg_info(ArgTypes, ModuleInfo, !ProcInfo) :-
proc_info_argmodes(!.ProcInfo, ArgModes),
proc_info_interface_code_model(!.ProcInfo, CodeModel),
make_arg_infos(ArgTypes, ArgModes, CodeModel, ModuleInfo, ArgInfo),
proc_info_set_arg_info(ArgInfo, !ProcInfo).
%---------------------------------------------------------------------------%
% This is the useful part of the code ;-).
% This code is one of the places where we make assumptions
% about the calling convention. This is the only place in
% the compiler that makes such assumptions, but there are
% other places scattered around the runtime and the library
% which also rely on it.
% We assume all input arguments always go in sequentially numbered
% registers starting at register number 1. We also assume that
% all output arguments go in sequentially numbered registers
% starting at register number 1, except for model_semi procedures,
% where the first register is reserved for the result and hence
% the output arguments start at register number 2.
% We allocate unused args as if they were outputs. The calling
% convention requires that we allocate them a register, and the choice
% should not matter since unused args should be rare. However, we
% do have to make sure that all the predicates in this module
% implement this decision consistently. (No code outside this module
% should know about the outcome of this decision.)
make_arg_infos(ArgTypes, ArgModes, CodeModel, ModuleInfo, ArgInfo) :-
( CodeModel = model_semi ->
StartReg = 2
;
StartReg = 1
),
make_arg_infos_list(ArgModes, ArgTypes, 1, StartReg,
ModuleInfo, ArgInfo).
:- pred make_arg_infos_list(list(mode)::in, list(type)::in, int::in, int::in,
module_info::in, list(arg_info)::out) is det.
make_arg_infos_list([], [], _, _, _, []).
make_arg_infos_list([Mode | Modes], [Type | Types], InReg0, OutReg0,
ModuleInfo, [ArgInfo | ArgInfos]) :-
mode_to_arg_mode(ModuleInfo, Mode, Type, ArgMode),
( ArgMode = top_in ->
ArgReg = InReg0,
InReg1 = InReg0 + 1,
OutReg1 = OutReg0
;
ArgReg = OutReg0,
InReg1 = InReg0,
OutReg1 = OutReg0 + 1
),
ArgInfo = arg_info(ArgReg, ArgMode),
make_arg_infos_list(Modes, Types, InReg1, OutReg1,
ModuleInfo, ArgInfos).
make_arg_infos_list([], [_|_], _, _, _, _) :-
error("make_arg_infos_list: length mis-match").
make_arg_infos_list([_|_], [], _, _, _, _) :-
error("make_arg_infos_list: length mis-match").
%---------------------------------------------------------------------------%
arg_info__build_input_arg_list(ProcInfo, VarLvals) :-
proc_info_headvars(ProcInfo, HeadVars),
proc_info_arg_info(ProcInfo, ArgInfos),
assoc_list__from_corresponding_lists(HeadVars, ArgInfos, VarArgInfos),
arg_info__build_input_arg_list_2(VarArgInfos, VarLvals).
:- pred arg_info__build_input_arg_list_2(assoc_list(prog_var, arg_info)::in,
assoc_list(prog_var, lval)::out) is det.
arg_info__build_input_arg_list_2([], []).
arg_info__build_input_arg_list_2([V - Arg | Rest0], VarArgs) :-
Arg = arg_info(Loc, Mode),
( Mode = top_in ->
code_util__arg_loc_to_register(Loc, Reg),
VarArgs = [V - Reg | VarArgs0]
;
VarArgs = VarArgs0
),
arg_info__build_input_arg_list_2(Rest0, VarArgs0).
%---------------------------------------------------------------------------%
arg_info__compute_in_and_out_vars(ModuleInfo, Vars, Modes, Types,
InVars, OutVars) :-
(
arg_info__compute_in_and_out_vars_2(ModuleInfo,
Vars, Modes, Types, InVars1, OutVars1)
->
InVars = InVars1,
OutVars = OutVars1
;
error("arg_info__compute_in_and_out_vars: length mismatch")
).
:- pred arg_info__compute_in_and_out_vars_2(module_info::in,
list(prog_var)::in, list(mode)::in, list(type)::in,
list(prog_var)::out, list(prog_var)::out) is semidet.
arg_info__compute_in_and_out_vars_2(_ModuleInfo, [], [], [], [], []).
arg_info__compute_in_and_out_vars_2(ModuleInfo, [Var | Vars],
[Mode | Modes], [Type | Types], InVars, OutVars) :-
arg_info__compute_in_and_out_vars_2(ModuleInfo, Vars,
Modes, Types, InVars1, OutVars1),
mode_to_arg_mode(ModuleInfo, Mode, Type, ArgMode),
( ArgMode = top_in ->
InVars = [Var | InVars1],
OutVars = OutVars1
;
InVars = InVars1,
OutVars = [Var | OutVars1]
).
%---------------------------------------------------------------------------%
arg_info__unify_arg_info(model_det,
[arg_info(1, top_in), arg_info(2, top_in)]).
arg_info__unify_arg_info(model_semi,
[arg_info(1, top_in), arg_info(2, top_in)]).
arg_info__unify_arg_info(model_non, _) :-
error("arg_info: nondet unify!").
%---------------------------------------------------------------------------%
arg_info__partition_args(Args, Ins, Outs) :-
arg_info__partition_args(Args, Ins, Outs0, Unuseds),
list__append(Outs0, Unuseds, Outs).
arg_info__partition_args([], [], [], []).
arg_info__partition_args([Var - ArgInfo | Rest], Ins, Outs, Unuseds) :-
arg_info__partition_args(Rest, Ins0, Outs0, Unuseds0),
ArgInfo = arg_info(_, ArgMode),
(
ArgMode = top_in,
Ins = [Var - ArgInfo | Ins0],
Outs = Outs0,
Unuseds = Unuseds0
;
ArgMode = top_out,
Ins = Ins0,
Outs = [Var - ArgInfo | Outs0],
Unuseds = Unuseds0
;
ArgMode = top_unused,
Ins = Ins0,
Outs = Outs0,
Unuseds = [Var - ArgInfo | Unuseds0]
).
%---------------------------------------------------------------------------%
:- pred arg_info__input_args(list(arg_info)::in, list(arg_loc)::out) is det.
arg_info__input_args([], []).
arg_info__input_args([arg_info(Loc, Mode) | Args], Vs) :-
arg_info__input_args(Args, Vs0),
( Mode = top_in ->
Vs = [Loc | Vs0]
;
Vs = Vs0
).
%---------------------------------------------------------------------------%
arg_info__partition_proc_args(ProcInfo, ModuleInfo, Inputs, Outputs, Unuseds) :-
proc_info_headvars(ProcInfo, Vars),
proc_info_argmodes(ProcInfo, Modes),
proc_info_vartypes(ProcInfo, VarTypes),
map__apply_to_list(Vars, VarTypes, Types),
arg_info__do_partition_proc_args(ModuleInfo, Vars, Types, Modes,
Inputs, Outputs, Unuseds).
arg_info__partition_proc_call_args(ProcInfo, VarTypes, ModuleInfo, Vars,
Inputs, Outputs, Unuseds) :-
proc_info_argmodes(ProcInfo, Modes),
map__apply_to_list(Vars, VarTypes, Types),
arg_info__do_partition_proc_args(ModuleInfo, Vars, Types, Modes,
Inputs, Outputs, Unuseds).
arg_info__partition_generic_call_args(ModuleInfo, Vars, Types, Modes,
Inputs, Outputs, Unuseds) :-
arg_info__do_partition_proc_args(ModuleInfo, Vars, Types, Modes,
Inputs, Outputs, Unuseds).
:- pred arg_info__do_partition_proc_args(module_info::in, list(prog_var)::in,
list(type)::in, list(mode)::in, set(prog_var)::out,
set(prog_var)::out, set(prog_var)::out) is det.
arg_info__do_partition_proc_args(ModuleInfo, Vars, Types, Modes,
Inputs, Outputs, Unuseds) :-
(
arg_info__partition_proc_args_2(Vars, Types, Modes, ModuleInfo,
set__init, Inputs1, set__init, Outputs1,
set__init, Unuseds1)
->
Inputs = Inputs1,
Outputs = Outputs1,
Unuseds = Unuseds1
;
error("arg_info__do_partition_proc_args: list length mismatch")
).
:- pred arg_info__partition_proc_args_2(list(prog_var)::in, list(type)::in,
list(mode)::in, module_info::in,
set(prog_var)::in, set(prog_var)::out,
set(prog_var)::in, set(prog_var)::out,
set(prog_var)::in, set(prog_var)::out) is semidet.
arg_info__partition_proc_args_2([], [], [], _ModuleInfo,
Inputs, Inputs, Outputs, Outputs, Unuseds, Unuseds).
arg_info__partition_proc_args_2([Var | Vars], [Type | Types], [Mode | Modes],
ModuleInfo, Inputs0, Inputs, Outputs0, Outputs,
Unuseds0, Unuseds) :-
mode_to_arg_mode(ModuleInfo, Mode, Type, ArgMode),
(
ArgMode = top_in,
set__insert(Inputs0, Var, Inputs1),
Outputs1 = Outputs0,
Unuseds1 = Unuseds0
;
ArgMode = top_out,
Inputs1 = Inputs0,
set__insert(Outputs0, Var, Outputs1),
Unuseds1 = Unuseds0
;
ArgMode = top_unused,
Inputs1 = Inputs0,
Outputs1 = Outputs0,
set__insert(Unuseds0, Var, Unuseds1)
),
arg_info__partition_proc_args_2(Vars, Types, Modes, ModuleInfo,
Inputs1, Inputs, Outputs1, Outputs, Unuseds1, Unuseds).