mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-23 13:23:47 +00:00
compiler/check_hlds.m:
compiler/hlds.m:
compiler/mode_top_functor.m:
Move the mode_top_functor module from the check_hlds package
to the hlds package, because most of its users are outside check_hlds.
compiler/arg_info.m:
compiler/deep_profiling.m:
compiler/foreign_proc_gen.m:
compiler/hlds_rtti.m:
compiler/lco.m:
compiler/liveness.m:
compiler/mark_tail_calls.m:
compiler/ml_args_util.m:
compiler/ml_foreign_proc_gen.m:
compiler/ml_unify_gen_construct.m:
compiler/ml_unify_gen_util.m:
compiler/modecheck_unify.m:
compiler/structure_sharing.domain.m:
compiler/unify_gen_construct.m:
compiler/unify_gen_util.m:
Conform to the changes above. (Many of these modules do not import
anything from the check_hlds package after this.)
674 lines
26 KiB
Mathematica
674 lines
26 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1994-2000,2002-2007, 2010-2012 The University of Melbourne.
|
|
% Copyright (c) 2014-2017, 2019-2022, 2024-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: 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.
|
|
%
|
|
% The code in this module assumes that none of the modes are undefined.
|
|
% The predicates for partitioning arguments into input, unused and output
|
|
% should not be used before undefined modes have been detected. For an example
|
|
% of how this kind of partitioning can be done in the presence of undefined
|
|
% modes, see superhomogeneous.partition_args_and_lambda_vars/8.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module hlds.arg_info.
|
|
:- interface.
|
|
|
|
:- import_module hlds.code_model.
|
|
:- import_module hlds.hlds_goal.
|
|
:- import_module hlds.hlds_llds.
|
|
:- import_module hlds.hlds_markers.
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.var_table.
|
|
|
|
:- import_module assoc_list.
|
|
:- import_module list.
|
|
:- import_module set.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Annotate every 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(module_info::in, pred_markers::in,
|
|
list(mer_type)::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 the standard argument passing interface
|
|
% for procedure. This will pass float arguments via float registers
|
|
% if present, while passing all other arguments via regular registers.
|
|
%
|
|
:- pred make_standard_arg_infos(module_info::in, code_model::in,
|
|
list(mer_type)::in, list(mer_mode)::in, list(arg_info)::out) is det.
|
|
|
|
% As above, but pass the register type for each argument explicitly.
|
|
% This is necessary for procedures with float arguments that must be
|
|
% passed via the regular registers instead of float registers.
|
|
%
|
|
:- pred make_arg_infos(module_info::in, code_model::in,
|
|
list(mer_type)::in, list(mer_mode)::in, list(reg_type)::in,
|
|
list(arg_info)::out) is det.
|
|
|
|
% Return the register type to use for each argument of a generic call.
|
|
%
|
|
:- pred generic_call_arg_reg_types(module_info::in, generic_call::in,
|
|
list(prog_var)::in, arg_reg_type_info::in, list(reg_type)::out) is det.
|
|
|
|
% Divide the given list of arguments into those treated as inputs
|
|
% by the calling convention and those treated as outputs.
|
|
%
|
|
:- pred compute_in_and_out_vars(module_info::in, var_table::in,
|
|
list(prog_var)::in, list(mer_mode)::in,
|
|
list(prog_var)::out, list(prog_var)::out) is det.
|
|
|
|
% Divide the given list of arguments into those treated as inputs
|
|
% by the calling convention and those treated as outputs.
|
|
% Arguments are further divided those passed via regular registers
|
|
% or via float registers.
|
|
%
|
|
:- pred compute_in_and_out_vars_sep_regs(module_info::in, var_table::in,
|
|
list(prog_var)::in, list(mer_mode)::in, list(reg_type)::in,
|
|
list(prog_var)::out, list(prog_var)::out,
|
|
list(prog_var)::out, list(prog_var)::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 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.
|
|
|
|
% 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 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.
|
|
|
|
% 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 partition_proc_args(module_info::in, proc_info::in,
|
|
set(prog_var)::out, set(prog_var)::out, set(prog_var)::out) is det.
|
|
|
|
% Like 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 partition_proc_call_args(module_info::in, proc_info::in,
|
|
var_table::in, list(prog_var)::in,
|
|
set(prog_var)::out, set(prog_var)::out, set(prog_var)::out) is det.
|
|
|
|
% Like 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 partition_generic_call_args(module_info::in,
|
|
list(prog_var)::in, list(mer_type)::in, list(mer_mode)::in,
|
|
set(prog_var)::out, set(prog_var)::out, set(prog_var)::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module hlds.mode_top_functor.
|
|
:- import_module libs.
|
|
:- import_module libs.globals.
|
|
:- import_module libs.options.
|
|
:- import_module parse_tree.builtin_lib_types.
|
|
:- import_module parse_tree.set_of_var.
|
|
|
|
:- import_module bool.
|
|
:- import_module int.
|
|
:- import_module map.
|
|
:- import_module pair.
|
|
:- import_module require.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% This whole section just traverses the module structure
|
|
%
|
|
|
|
generate_arg_info(!ModuleInfo) :-
|
|
module_info_get_globals(!.ModuleInfo, Globals),
|
|
globals.lookup_bool_option(Globals, use_float_registers, UseFloatRegs),
|
|
module_info_get_pred_id_table(!.ModuleInfo, PredIdTable0),
|
|
map.to_sorted_assoc_list(PredIdTable0, PredIdsInfos0),
|
|
generate_arg_infos_for_preds(!.ModuleInfo, UseFloatRegs, PredIdsInfos0,
|
|
[], RevPredIdsInfos),
|
|
map.from_rev_sorted_assoc_list(RevPredIdsInfos, PredIdTable),
|
|
module_info_set_pred_id_table(PredIdTable, !ModuleInfo).
|
|
|
|
% We use an accumulator because the list of predicates can be quite long.
|
|
%
|
|
:- pred generate_arg_infos_for_preds(module_info::in, bool::in,
|
|
assoc_list(pred_id, pred_info)::in,
|
|
assoc_list(pred_id, pred_info)::in,
|
|
assoc_list(pred_id, pred_info)::out) is det.
|
|
|
|
generate_arg_infos_for_preds(_, _, [], !RevPredIdsInfos).
|
|
generate_arg_infos_for_preds(ModuleInfo, UseFloatRegs,
|
|
[PredIdInfo0 | PredIdsInfos0], !RevPredIdsInfos) :-
|
|
PredIdInfo0 = PredId - PredInfo0,
|
|
pred_info_get_markers(PredInfo0, Markers),
|
|
pred_info_get_arg_types(PredInfo0, ArgTypes),
|
|
pred_info_get_proc_table(PredInfo0, ProcTable0),
|
|
map.to_sorted_assoc_list(ProcTable0, ProcIdsInfos0),
|
|
generate_arg_infos_for_procs(ModuleInfo, UseFloatRegs, Markers, ArgTypes,
|
|
ProcIdsInfos0, ProcIdsInfos),
|
|
map.from_sorted_assoc_list(ProcIdsInfos, ProcTable),
|
|
pred_info_set_proc_table(ProcTable, PredInfo0, PredInfo),
|
|
PredIdInfo = PredId - PredInfo,
|
|
!:RevPredIdsInfos = [PredIdInfo | !.RevPredIdsInfos],
|
|
generate_arg_infos_for_preds(ModuleInfo, UseFloatRegs,
|
|
PredIdsInfos0, !RevPredIdsInfos).
|
|
|
|
% We *don't* use an accumulator because in practice,
|
|
% the list of procedures is never too long except in pathological code.
|
|
%
|
|
:- pred generate_arg_infos_for_procs(module_info::in, bool::in,
|
|
pred_markers::in, list(mer_type)::in,
|
|
assoc_list(proc_id, proc_info)::in,
|
|
assoc_list(proc_id, proc_info)::out) is det.
|
|
|
|
generate_arg_infos_for_procs(_, _, _, _, [], []).
|
|
generate_arg_infos_for_procs(ModuleInfo, UseFloatRegs, Markers, ArgTypes,
|
|
[ProcIdInfo0 | ProcIdInfos0], [ProcIdInfo | ProcIdInfos]) :-
|
|
ProcIdInfo0 = ProcId - ProcInfo0,
|
|
generate_arg_infos_for_proc(ModuleInfo, UseFloatRegs, Markers, ArgTypes,
|
|
ProcInfo0, ProcInfo),
|
|
ProcIdInfo = ProcId - ProcInfo,
|
|
generate_arg_infos_for_procs(ModuleInfo, UseFloatRegs, Markers, ArgTypes,
|
|
ProcIdInfos0, ProcIdInfos).
|
|
|
|
generate_proc_arg_info(ModuleInfo, Markers, ArgTypes, !ProcInfo) :-
|
|
module_info_get_globals(ModuleInfo, Globals),
|
|
globals.lookup_bool_option(Globals, use_float_registers, UseFloatRegs),
|
|
generate_arg_infos_for_proc(ModuleInfo, UseFloatRegs, Markers, ArgTypes,
|
|
!ProcInfo).
|
|
|
|
:- pred generate_arg_infos_for_proc(module_info::in, bool::in,
|
|
pred_markers::in, list(mer_type)::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
|
|
generate_arg_infos_for_proc(ModuleInfo, UseFloatRegs, Markers, ArgTypes,
|
|
!ProcInfo) :-
|
|
proc_info_get_headvars(!.ProcInfo, HeadVars),
|
|
proc_info_get_argmodes(!.ProcInfo, ArgModes),
|
|
CodeModel = proc_info_interface_code_model(!.ProcInfo),
|
|
( if
|
|
UseFloatRegs = yes,
|
|
% XXX we don't yet use float registers for class method calls
|
|
not marker_is_present(Markers, marker_class_instance_method)
|
|
then
|
|
proc_info_get_reg_r_headvars(!.ProcInfo, RegR_HeadVars),
|
|
list.map_corresponding(reg_type_for_headvar(RegR_HeadVars),
|
|
HeadVars, ArgTypes, ArgRegTypes),
|
|
make_arg_infos(ModuleInfo, CodeModel, ArgTypes, ArgModes, ArgRegTypes,
|
|
ArgInfos)
|
|
else
|
|
make_reg_r_arg_infos(ModuleInfo, CodeModel, ArgTypes, ArgModes,
|
|
ArgInfos)
|
|
),
|
|
proc_info_set_arg_info(ArgInfos, !ProcInfo).
|
|
|
|
:- pred reg_type_for_headvar(set_of_progvar::in, prog_var::in, mer_type::in,
|
|
reg_type::out) is det.
|
|
|
|
reg_type_for_headvar(RegR_HeadVars, HeadVar, Type, RegType) :-
|
|
( if set_of_var.contains(RegR_HeadVars, HeadVar) then
|
|
RegType = reg_r
|
|
else
|
|
( if Type = float_type then
|
|
RegType = reg_f
|
|
else
|
|
RegType = reg_r
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
make_standard_arg_infos(ModuleInfo, CodeModel, ArgTypes, ArgModes, ArgInfos) :-
|
|
module_info_get_globals(ModuleInfo, Globals),
|
|
globals.lookup_bool_option(Globals, use_float_registers, FloatRegs),
|
|
(
|
|
FloatRegs = yes,
|
|
make_std_arg_infos(ModuleInfo, CodeModel, ArgTypes, ArgModes,
|
|
ArgInfos)
|
|
;
|
|
FloatRegs = no,
|
|
make_reg_r_arg_infos(ModuleInfo, CodeModel, ArgTypes, ArgModes,
|
|
ArgInfos)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% This is the useful part of the code ;-).
|
|
%
|
|
% This code the only place in the compiler where we make assumptions about
|
|
% the calling convention, though there are other places scattered around
|
|
% the runtime and the library that also rely on it.
|
|
%
|
|
% We assume all input arguments always go in sequentially numbered
|
|
% registers starting at registers r1 and f1. We also assume that all output
|
|
% arguments go in sequentially numbered registers starting at r1 and f1,
|
|
% except for model_semi procedures, where r1 is reserved for the result and
|
|
% hence the output arguments start at registers r2 and f1.
|
|
%
|
|
% We allocate unused args as if they were regular (non-floating point)
|
|
% 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.)
|
|
%
|
|
% The next three sections of code define
|
|
%
|
|
% - make_std_arg_infos,
|
|
% - make_reg_r_arg_infos, and
|
|
% - make_arg_infos.
|
|
%
|
|
% These all do variations of the same job, so a change in one may require
|
|
% corresponding changes in the other two as well.
|
|
%
|
|
% make_arg_infos is the most general version, in that it allows the caller
|
|
% to specify the reg_type for every argument individually. However, this
|
|
% also makes it the slowest. The other two are specialized versions that
|
|
% do not take a separate reg_type for every argument. make_reg_r_arg_infos
|
|
% allocates every argument a reg_r register, while make_std_arg_infos
|
|
% allocates every argument whose type is not "float" a reg_r register.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred make_std_arg_infos(module_info::in, code_model::in,
|
|
list(mer_type)::in, list(mer_mode)::in, list(arg_info)::out) is det.
|
|
|
|
make_std_arg_infos(ModuleInfo, CodeModel, ArgTypes, ArgModes, ArgInfos) :-
|
|
initial_r_regs(CodeModel, FirstInRegR, FirstOutRegR),
|
|
FirstInRegF = 1,
|
|
FirstOutRegF = 1,
|
|
make_std_arg_infos_loop(ModuleInfo, ArgTypes, ArgModes,
|
|
FirstInRegR, FirstInRegF, FirstOutRegR, FirstOutRegF, ArgInfos).
|
|
|
|
:- pred make_std_arg_infos_loop(module_info::in,
|
|
list(mer_type)::in, list(mer_mode)::in,
|
|
int::in, int::in, int::in, int::in, list(arg_info)::out) is det.
|
|
|
|
make_std_arg_infos_loop(_, [], [], _, _, _, _, []).
|
|
make_std_arg_infos_loop(_, [], [_ | _], _, _, _, _, _) :-
|
|
unexpected($pred, "length mismatch").
|
|
make_std_arg_infos_loop(_, [_ | _], [], _, _, _, _, _) :-
|
|
unexpected($pred, "length mismatch").
|
|
make_std_arg_infos_loop(ModuleInfo, [Type | Types], [Mode | Modes],
|
|
!.InRegR, !.InRegF, !.OutRegR, !.OutRegF, [ArgInfo | ArgInfos]) :-
|
|
require_det (
|
|
mode_to_top_functor_mode(ModuleInfo, Mode, Type, TopFunctorMode),
|
|
(
|
|
TopFunctorMode = top_in,
|
|
get_std_arg_loc(Type, ArgLoc, !InRegR, !InRegF)
|
|
;
|
|
( TopFunctorMode = top_out
|
|
; TopFunctorMode = top_unused
|
|
),
|
|
get_std_arg_loc(Type, ArgLoc, !OutRegR, !OutRegF)
|
|
),
|
|
ArgInfo = arg_info(ArgLoc, TopFunctorMode)
|
|
),
|
|
make_std_arg_infos_loop(ModuleInfo, Types, Modes,
|
|
!.InRegR, !.InRegF, !.OutRegR, !.OutRegF, ArgInfos).
|
|
|
|
:- pred get_std_arg_loc(mer_type::in, arg_loc::out, int::in, int::out,
|
|
int::in, int::out) is det.
|
|
|
|
get_std_arg_loc(Type, ArgLoc, !RegR, !RegF) :-
|
|
( if Type = float_type then
|
|
ArgLoc = reg(reg_f, !.RegF),
|
|
!:RegF = !.RegF + 1
|
|
else
|
|
ArgLoc = reg(reg_r, !.RegR),
|
|
!:RegR = !.RegR + 1
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
:- pred make_reg_r_arg_infos(module_info::in, code_model::in,
|
|
list(mer_type)::in, list(mer_mode)::in, list(arg_info)::out) is det.
|
|
|
|
make_reg_r_arg_infos(ModuleInfo, CodeModel, ArgTypes, ArgModes, ArgInfos) :-
|
|
initial_r_regs(CodeModel, FirstInRegR, FirstOutRegR),
|
|
make_reg_r_arg_infos_loop(ModuleInfo, ArgTypes, ArgModes,
|
|
FirstInRegR, FirstOutRegR, ArgInfos).
|
|
|
|
:- pred make_reg_r_arg_infos_loop(module_info::in,
|
|
list(mer_type)::in, list(mer_mode)::in,
|
|
int::in, int::in, list(arg_info)::out) is det.
|
|
|
|
make_reg_r_arg_infos_loop(_, [], [], _, _, []).
|
|
make_reg_r_arg_infos_loop(_, [], [_ | _], _, _, _) :-
|
|
unexpected($pred, "length mismatch").
|
|
make_reg_r_arg_infos_loop(_, [_ | _], [], _, _, _) :-
|
|
unexpected($pred, "length mismatch").
|
|
make_reg_r_arg_infos_loop(ModuleInfo, [Type | Types], [Mode | Modes],
|
|
!.InRegR, !.OutRegR, [ArgInfo | ArgInfos]) :-
|
|
mode_to_top_functor_mode(ModuleInfo, Mode, Type, TopFunctorMode),
|
|
(
|
|
TopFunctorMode = top_in,
|
|
get_reg_r_arg_loc(ArgLoc, !InRegR)
|
|
;
|
|
( TopFunctorMode = top_out
|
|
; TopFunctorMode = top_unused
|
|
),
|
|
get_reg_r_arg_loc(ArgLoc, !OutRegR)
|
|
),
|
|
ArgInfo = arg_info(ArgLoc, TopFunctorMode),
|
|
make_reg_r_arg_infos_loop(ModuleInfo, Types, Modes,
|
|
!.InRegR, !.OutRegR, ArgInfos).
|
|
|
|
:- pred get_reg_r_arg_loc(arg_loc::out, int::in, int::out) is det.
|
|
|
|
get_reg_r_arg_loc(ArgLoc, !RegR) :-
|
|
ArgLoc = reg(reg_r, !.RegR),
|
|
!:RegR = !.RegR + 1.
|
|
|
|
%---------------------%
|
|
|
|
make_arg_infos(ModuleInfo, CodeModel, ArgTypes, ArgModes, ArgRegTypes,
|
|
ArgInfos) :-
|
|
initial_r_regs(CodeModel, FirstInRegR, FirstOutRegR),
|
|
FirstInRegF = 1,
|
|
FirstOutRegF = 1,
|
|
( if
|
|
make_arg_infos_loop(ModuleInfo, ArgTypes, ArgModes, ArgRegTypes,
|
|
FirstInRegR, FirstInRegF, FirstOutRegR, FirstOutRegF,
|
|
ArgInfosPrime)
|
|
then
|
|
ArgInfos = ArgInfosPrime
|
|
else
|
|
unexpected($pred, "length mismatch")
|
|
).
|
|
|
|
:- pred make_arg_infos_loop(module_info::in,
|
|
list(mer_type)::in, list(mer_mode)::in, list(reg_type)::in,
|
|
int::in, int::in, int::in, int::in, list(arg_info)::out) is semidet.
|
|
|
|
make_arg_infos_loop(_, [], [], [], _, _, _, _, []).
|
|
make_arg_infos_loop(ModuleInfo,
|
|
[Type | Types], [Mode | Modes], [RegType | RegTypes],
|
|
!.InRegR, !.InRegF, !.OutRegR, !.OutRegF, [ArgInfo | ArgInfos]) :-
|
|
require_det (
|
|
mode_to_top_functor_mode(ModuleInfo, Mode, Type, TopFunctorMode),
|
|
(
|
|
TopFunctorMode = top_in,
|
|
get_arg_loc(RegType, ArgLoc, !InRegR, !InRegF)
|
|
;
|
|
( TopFunctorMode = top_out
|
|
; TopFunctorMode = top_unused
|
|
),
|
|
get_arg_loc(RegType, ArgLoc, !OutRegR, !OutRegF)
|
|
),
|
|
ArgInfo = arg_info(ArgLoc, TopFunctorMode)
|
|
),
|
|
make_arg_infos_loop(ModuleInfo, Types, Modes, RegTypes,
|
|
!.InRegR, !.InRegF, !.OutRegR, !.OutRegF, ArgInfos).
|
|
|
|
:- pred get_arg_loc(reg_type::in, arg_loc::out, int::in, int::out,
|
|
int::in, int::out) is det.
|
|
|
|
get_arg_loc(RegType, ArgLoc, !RegR, !RegF) :-
|
|
(
|
|
RegType = reg_r,
|
|
ArgLoc = reg(reg_r, !.RegR),
|
|
!:RegR = !.RegR + 1
|
|
;
|
|
RegType = reg_f,
|
|
ArgLoc = reg(reg_f, !.RegF),
|
|
!:RegF = !.RegF + 1
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
:- pred initial_r_regs(code_model::in, int::out, int::out) is det.
|
|
:- pragma inline(pred(initial_r_regs/3)).
|
|
|
|
initial_r_regs(CodeModel, FirstInRegR, FirstOutRegR) :-
|
|
FirstInRegR = 1,
|
|
(
|
|
CodeModel = model_semi,
|
|
FirstOutRegR = 2
|
|
;
|
|
( CodeModel = model_det
|
|
; CodeModel = model_non
|
|
),
|
|
FirstOutRegR = 1
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
generic_call_arg_reg_types(ModuleInfo, GenericCall, ArgVars,
|
|
MaybeArgRegs, ArgRegTypes) :-
|
|
(
|
|
GenericCall = higher_order(_, _, _, _, _),
|
|
module_info_get_globals(ModuleInfo, Globals),
|
|
globals.lookup_bool_option(Globals, use_float_registers, UseFloatRegs),
|
|
(
|
|
UseFloatRegs = no,
|
|
list.duplicate(length(ArgVars), reg_r, ArgRegTypes)
|
|
;
|
|
UseFloatRegs = yes,
|
|
MaybeArgRegs = arg_reg_types(ArgRegs),
|
|
ArgRegTypes = list.map(arg_reg_to_reg_type, ArgRegs)
|
|
;
|
|
UseFloatRegs = yes,
|
|
MaybeArgRegs = arg_reg_types_unset,
|
|
% This should have been set by the float register wrapper pass.
|
|
unexpected($pred, "missing ho_arg_regs")
|
|
)
|
|
;
|
|
% We don't yet use float registers for class method calls.
|
|
( GenericCall = class_method(_, _, _, _)
|
|
; GenericCall = event_call(_)
|
|
; GenericCall = cast(_)
|
|
),
|
|
list.duplicate(length(ArgVars), reg_r, ArgRegTypes)
|
|
).
|
|
|
|
:- func arg_reg_to_reg_type(ho_arg_reg) = reg_type.
|
|
|
|
arg_reg_to_reg_type(ho_arg_reg_r) = reg_r.
|
|
arg_reg_to_reg_type(ho_arg_reg_f) = reg_f.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
compute_in_and_out_vars(_, _, [], [], [], []).
|
|
compute_in_and_out_vars(_, _, [], [_ | _], _, _) :-
|
|
unexpected($pred, "length mismatch").
|
|
compute_in_and_out_vars(_, _, [_ | _], [], _, _) :-
|
|
unexpected($pred, "length mismatch").
|
|
compute_in_and_out_vars(ModuleInfo, VarTable,
|
|
[Var | Vars], [Mode | Modes],
|
|
!:InVars, !:OutVars) :-
|
|
compute_in_and_out_vars(ModuleInfo, VarTable, Vars, Modes,
|
|
!:InVars, !:OutVars),
|
|
lookup_var_entry(VarTable, Var, Entry),
|
|
Type = Entry ^ vte_type,
|
|
mode_to_top_functor_mode(ModuleInfo, Mode, Type, TopFunctorMode),
|
|
(
|
|
TopFunctorMode = top_in,
|
|
!:InVars = [Var | !.InVars]
|
|
;
|
|
( TopFunctorMode = top_out
|
|
; TopFunctorMode = top_unused
|
|
),
|
|
!:OutVars = [Var | !.OutVars]
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
compute_in_and_out_vars_sep_regs(ModuleInfo, VarTable,
|
|
Vars, Modes, ArgRegTypes,
|
|
!:InVarsR, !:InVarsF, !:OutVarsR, !:OutVarsF) :-
|
|
( if
|
|
compute_in_and_out_vars_sep_regs_2(ModuleInfo, VarTable,
|
|
Vars, Modes, ArgRegTypes,
|
|
!:InVarsR, !:InVarsF, !:OutVarsR, !:OutVarsF)
|
|
then
|
|
true
|
|
else
|
|
unexpected($pred, "length mismatch")
|
|
).
|
|
|
|
:- pred compute_in_and_out_vars_sep_regs_2(module_info::in,
|
|
var_table::in, list(prog_var)::in, list(mer_mode)::in, list(reg_type)::in,
|
|
list(prog_var)::out, list(prog_var)::out,
|
|
list(prog_var)::out, list(prog_var)::out) is semidet.
|
|
|
|
compute_in_and_out_vars_sep_regs_2(_, _, [], [], [], [], [], [], []).
|
|
compute_in_and_out_vars_sep_regs_2(ModuleInfo, VarTable,
|
|
[Var | Vars], [Mode | Modes], [RegType | RegTypes],
|
|
!:InVarsR, !:InVarsF, !:OutVarsR, !:OutVarsF) :-
|
|
compute_in_and_out_vars_sep_regs_2(ModuleInfo, VarTable,
|
|
Vars, Modes, RegTypes, !:InVarsR, !:InVarsF, !:OutVarsR, !:OutVarsF),
|
|
require_det (
|
|
lookup_var_entry(VarTable, Var, Entry),
|
|
Type = Entry ^ vte_type,
|
|
mode_to_top_functor_mode(ModuleInfo, Mode, Type, TopFunctorMode),
|
|
(
|
|
TopFunctorMode = top_in,
|
|
(
|
|
RegType = reg_r,
|
|
!:InVarsR = [Var | !.InVarsR]
|
|
;
|
|
RegType = reg_f,
|
|
!:InVarsF = [Var | !.InVarsF]
|
|
)
|
|
;
|
|
( TopFunctorMode = top_out
|
|
; TopFunctorMode = top_unused
|
|
),
|
|
(
|
|
RegType = reg_r,
|
|
!:OutVarsR = [Var | !.OutVarsR]
|
|
;
|
|
RegType = reg_f,
|
|
!:OutVarsF = [Var | !.OutVarsF]
|
|
)
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
partition_args(Args, Ins, Outs) :-
|
|
partition_args(Args, Ins, Outs0, Unuseds),
|
|
list.append(Outs0, Unuseds, Outs).
|
|
|
|
partition_args([], [], [], []).
|
|
partition_args([Var - ArgInfo | VarsArgInfos], !:Ins, !:Outs, !:Unuseds) :-
|
|
partition_args(VarsArgInfos, !:Ins, !:Outs, !:Unuseds),
|
|
ArgInfo = arg_info(_, ArgMode),
|
|
(
|
|
ArgMode = top_in,
|
|
!:Ins = [Var - ArgInfo | !.Ins]
|
|
;
|
|
ArgMode = top_out,
|
|
!:Outs = [Var - ArgInfo | !.Outs]
|
|
;
|
|
ArgMode = top_unused,
|
|
!:Unuseds = [Var - ArgInfo | !.Unuseds]
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
partition_proc_args(ModuleInfo, ProcInfo, Inputs, Outputs, Unuseds) :-
|
|
proc_info_get_headvars(ProcInfo, Vars),
|
|
proc_info_get_argmodes(ProcInfo, Modes),
|
|
proc_info_get_var_table(ProcInfo, VarTable),
|
|
lookup_var_types(VarTable, Vars, Types),
|
|
do_partition_proc_args(ModuleInfo, Vars, Types, Modes,
|
|
Inputs, Outputs, Unuseds).
|
|
|
|
partition_proc_call_args(ModuleInfo, ProcInfo, VarTable, Vars,
|
|
Inputs, Outputs, Unuseds) :-
|
|
proc_info_get_argmodes(ProcInfo, Modes),
|
|
lookup_var_types(VarTable, Vars, Types),
|
|
do_partition_proc_args(ModuleInfo, Vars, Types, Modes,
|
|
Inputs, Outputs, Unuseds).
|
|
|
|
partition_generic_call_args(ModuleInfo, Vars, Types, Modes,
|
|
Inputs, Outputs, Unuseds) :-
|
|
do_partition_proc_args(ModuleInfo, Vars, Types, Modes,
|
|
Inputs, Outputs, Unuseds).
|
|
|
|
:- pred do_partition_proc_args(module_info::in, list(prog_var)::in,
|
|
list(mer_type)::in, list(mer_mode)::in, set(prog_var)::out,
|
|
set(prog_var)::out, set(prog_var)::out) is det.
|
|
|
|
do_partition_proc_args(ModuleInfo, Vars, Types, Modes,
|
|
!:Inputs, !:Outputs, !:Unuseds) :-
|
|
( if
|
|
partition_proc_args_2(ModuleInfo, Vars, Types, Modes,
|
|
set.init, !:Inputs, set.init, !:Outputs,
|
|
set.init, !:Unuseds)
|
|
then
|
|
true
|
|
else
|
|
unexpected($pred, "list length mismatch")
|
|
).
|
|
|
|
:- pred partition_proc_args_2(module_info::in, list(prog_var)::in,
|
|
list(mer_type)::in, list(mer_mode)::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.
|
|
|
|
partition_proc_args_2(_ModuleInfo, [], [], [],
|
|
!Inputs, !Outputs, !Unuseds).
|
|
partition_proc_args_2(ModuleInfo, [Var | Vars], [Type | Types], [Mode | Modes],
|
|
!Inputs, !Outputs, !Unuseds) :-
|
|
require_det (
|
|
mode_to_top_functor_mode(ModuleInfo, Mode, Type, TopFunctorMode),
|
|
(
|
|
TopFunctorMode = top_in,
|
|
set.insert(Var, !Inputs)
|
|
;
|
|
TopFunctorMode = top_out,
|
|
set.insert(Var, !Outputs)
|
|
;
|
|
TopFunctorMode = top_unused,
|
|
set.insert(Var, !Unuseds)
|
|
)
|
|
),
|
|
partition_proc_args_2(ModuleInfo, Vars, Types, Modes,
|
|
!Inputs, !Outputs, !Unuseds).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module hlds.arg_info.
|
|
%---------------------------------------------------------------------------%
|