Files
mercury/compiler/ml_args_util.m
Zoltan Somogyi 955a69efff Give better names to some functions.
compiler/type_util.m:
    Rename the "check_dummy_type" function to "is_type_a_dummy", since this
    expresses its job more clearly.

    Make the implementation of "is_type_a_dummy" slightly more efficient,
    by avoiding some redundant actions.

    Provide a new function "is_either_type_a_dummy" that does
    what its name says, and which is somewhat more efficient than
    two separate calls to "is_type_a_dummy".

compiler/prog_type.m:
    Rename the "check_builtin_dummy_type_ctor" function to
    "is_type_ctor_a_builtin_dummy", since this expresses its job
    more clearly.

compiler/ml_unify_gen.m:
    Conform to the name changes.

    Use the new function where relevant to simplify some code.

    Fix some comments.

compiler/code_info.m:
compiler/code_loc_dep.m:
compiler/continuation_info.m:
compiler/erl_call_gen.m:
compiler/erl_code_gen.m:
compiler/erl_code_util.m:
compiler/erl_unify_gen.m:
compiler/export.m:
compiler/higher_order.m:
compiler/hlds_pred.m:
compiler/live_vars.m:
compiler/llds_out_instr.m:
compiler/mark_tail_calls.m:
compiler/ml_args_util.m:
compiler/ml_call_gen.m:
compiler/ml_closure_gen.m:
compiler/ml_code_gen.m:
compiler/ml_code_util.m:
compiler/ml_commit_gen.m:
compiler/ml_foreign_proc_gen.m:
compiler/pragma_c_gen.m:
compiler/stack_layout.m:
compiler/term_constr_util.m:
compiler/trace_gen.m:
compiler/unify_gen.m:
compiler/unify_proc.m:
compiler/var_locn.m:
compiler/write_module_interface_files.m:
    Use the new function where relevant.
2018-02-28 13:48:44 +11:00

1194 lines
52 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 2017 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: ml_args_util.m.
%
% This module contains utility predicates that classify and process
% predicate arguments.
%
%---------------------------------------------------------------------------%
:- module ml_backend.ml_args_util.
:- interface.
:- import_module hlds.
:- import_module hlds.code_model.
:- import_module hlds.hlds_module.
:- import_module hlds.hlds_pred.
:- import_module hlds.hlds_rtti.
:- import_module mdbcomp.
:- import_module mdbcomp.prim_data.
:- import_module ml_backend.ml_gen_info.
:- import_module ml_backend.mlds.
:- import_module parse_tree.
:- import_module parse_tree.prog_data.
:- import_module assoc_list.
:- import_module bool.
:- import_module list.
:- import_module map.
%---------------------------------------------------------------------------%
%
% Various utility routines used for MLDS code generation.
%
% Append an appropriate `return' statement for the given code_model
% and returning the given lvals, if needed.
%
:- pred ml_append_return_statement(code_model::in, prog_context::in,
list(mlds_rval)::in, list(mlds_stmt)::in, list(mlds_stmt)::out) is det.
%---------------------------------------------------------------------------%
%
% Routines for generating function declarations (i.e. mlds_func_params).
%
% Note that when generating function *definitions*, the versions that take
% an ml_gen_info pair should be used, since those are the only ones that will
% generate the correct GC tracing code for the parameters.
:- type copy_out_when
---> copy_out_never
; copy_out_only_last_arg
; copy_out_always.
% Decide how the interface of a procedure should handle output arguments.
%
% One way we can handle an output argument is to return it
% via a return statement. The MLDS code generator calls this
% a "copy out" output argument.
%
% The other way is to have the caller pass a pointer for the output arg,
% and have the callee return the value by assigning through that pointer.
% The MLDS code generator calls this a "byref" output argument.
%
% This function tells its caller for which set of a procedure's output
% arguments it should use the first approach: for none (copy_out_never),
% for the last one only (copy_out_only_last_arg), or for all of them
% (copy_out_always).
%
:- func compute_when_to_copy_out(bool, code_model, pred_or_func)
= copy_out_when.
% A tuple containing the information about a procedure argument
% that most code that processes such arguments needs to know.
%
:- type var_mvar_type_mode
---> var_mvar_type_mode(
% The argument in the HLDS.
prog_var,
% The argument in the MLDS.
mlds_local_var_name,
% The type of the (formal) argument from the procedure
% declaration. (Note that the type of the *actual* argument
% inside the body of the caller may be more specific.)
mer_type,
% Is the arg input, output, or neither?
top_functor_mode
).
% Generate the function prototype for the given procedure
% without filling in the gc statement field of the input parameters.
%
:- pred ml_gen_proc_params_no_gc_stmts(module_info::in, pred_proc_id::in,
list(var_mvar_type_mode)::out, mlds_func_params::out) is det.
% Generate the function prototype for the given procedure, filling in
% the gc statement slots, and return
%
% (a) the list of nondummy by-ref output arguments, and
% (b) the list of nondummy copied output arguments.
%
:- pred ml_gen_info_proc_params(pred_proc_id::in,
list(var_mvar_type_mode)::out, mlds_func_params::out,
list(prog_var)::out, list(prog_var)::out,
ml_gen_info::in, ml_gen_info::out) is det.
% Generate the function prototype for *only the input arguments*
% of the given procedure.
%
:- func ml_gen_proc_params_inputs_only_no_gc_stmts(module_info, pred_proc_id)
= list(mlds_argument).
% As above, but from the rtti_proc_id rather than from the module_info,
% pred_id, and proc_id.
%
:- func ml_gen_proc_params_from_rtti_no_gc_stmts(module_info, rtti_proc_label)
= mlds_func_params.
% Generate the function prototype for a procedure with the
% given argument names, types, modes, and code model.
%
:- pred ml_gen_params_no_gc_stmts(module_info::in, pred_or_func::in,
code_model::in, list(prog_var)::in, list(mlds_local_var_name)::in,
list(mer_type)::in, list(mer_mode)::in,
list(var_mvar_type_mode)::out, mlds_func_params::out) is det.
% ml_gen_tscc_arg_params(ModuleInfo, PredOrFunc, CodeModel, Context,
% ProcIdInTscc, VarSet, Vars, Types, Modes, ArgTuples, !OutArgNames,
% TsccInArgs, FuncParams, ReturnRvalsTypes, OutVarsTypes,
% OwnLocalVarDefns, TsccInLocalVarDefns, TsccOutLocalVarDefns,
% CopyTsccInToOwnStmts, CopyOwnToTsccOutStmts,
% CopyOutValThroughPtrStmts) :-
%
% For background and terminology used in this predicate and its
% description, see notes/mlds_tail_recursion.html.
%
% The inputs of this predicate describe a procedure in a TSCC
% (PredOrFunc, CodeModel, Context, ProcIdInTscc, VarSet) and its argument
% list (Vars, Types, and Modes). The outputs return information about the
% arguments in a more conveniently packaged form (ArgTuples), as well as
% the information the code generator needs to generate parameter passing
% code both for the wrapped procedures and the container procedures.
% Specifically, we return information that is needed
%
% - to generate code for tail calls to this procedure, from other
% procedures in the TSCC as well from itself,
% - to generate the signature of container procedures,
% - to generate the declarations at the start of container procedures,
% - to generate code at the start of the wrapped procedure for copying
% input arguments from the tscc variables in which the TSCC gets them
% to the procedure's own variables,
% - to generate code at the end of the wrapped procedure for copying
% output arguments from the procedure's own variables to the variables
% in which the TSCC expects them, and
% - to generate code at the end of the container procedure to return
% the output arguments to the caller.
%
% The info about tail calls is needed before we can start generating code
% for *any* of the procedures in the TSCC.
%
% (Arguments whose type is a dummy type or whose mode is "unused"
% don't participate in parameter passing, so this predicate ignores them.
% All the discussion below uses "arguments" as shorthand for "arguments
% of non-dummy types whose modes are not unused.)
%
% For each input argument, this predicate creates a corresponding
% lvn_tscc_proc_input_var, while for each output argument, it creates
% a corresponding lvn_tscc_output_var. Model semi procedures have
% a success indication as an extra output, and for such procedures
% we create a corresponding lvn_tscc_output_var_succeeded variable.
% We call the MLDS variables representing the procedure's input and
% output HLDS variables the procedure's own variables, while we call
% the lvn_tscc_proc_input_vars and lvn_tscc_output_vars (including
% lvn_tscc_output_var_succeededs) the TSCC in and out variables
% respectively.
%
% Wrapped procedures always get their inputs in TSCC in variables
% (both from the caller and from each other at tail calls), and they
% always put their results in the TSCC out variables. For output
% arguments passed by reference, this predicate will create an
% lvn_tscc_output_var_ptr variable (the argument's TSCC out ptr variable)
% to hold the address of the memory location where the value of the
% argument should be put on return.
%
% Both lvn_tscc_proc_input_vars and lvn_tscc_output_vars include
% an argument sequence number, with separate sequences for input and
% output arguments, with both sequences starting at 1. These variables
% also have names (to make the code easier to read). The input variables
% are specific to a procedure, so they can (and do) take their name
% from the name of the corresponding head variable. The output variables
% are shared between all the procedures, so they take their names
% from the name of the corresponding head variable in the first procedure
% in the TSCC. These names are stored in !OutArgNames across calls to
% ml_gen_tscc_arg_params.
%
% The value we return in TsccInArgs will be a list of the
% lvn_tscc_proc_input_vars of the input arguments only. Every tail call
% will assign a value to every lvn_tscc_proc_input_var of the callee.
%
% The next three parameters, FuncParams, ReturnRvalsTypes and OutArgNames,
% describe the signature of the container functions. FuncParams is intended
% to be put directly into the func_params slot in the container
% procedure's mlds_function: it lists the names and types of the arguments
% (which will be the procedure's TSCC in variables, and the TSCC out ptr
% variables of the output arguments returned by reference) in declaration
% order, and the types of the output arguments that are returned by value
% (including the success indicator for model semi procedures).
% ReturnRvalsTypes is intended to be put almost directly into the return
% statements of container functions. It gives the rvals and types of the
% output args returned by value, with the rvals being just the values of
% their TSCC out variables. The value in OutVarsTypes just lists the names
% of all the TSCC out variables together with their types. It is not meant
% to be used in the construction of any MLDS construct; it is meant purely
% to be used in a sanity check. Every procedure in a TSCC should get
% the exact same OutVarsTypes value; any mismatch indicates a compiler bug.
% The reason why OutVarsTypes is separate from FuncParams is that it is
% possible for two procedures in the TSCC to return the exact same vector
% of arguments (so that they can tail call each other), but not return
% those arguments the same way. This can happen when one procedure comes
% from a predicate (which in C returns all its outputs via reference),
% while another comes from a function (which in C returns its last
% argument, the result argument, via the return value).
%
% When generating code for a procedure that is *not* in a TSCC,
% the declaration of its MLDS function would define the MLDS variables
% of the some of the procedure's arguments (specifically, the inputs).
% The signatures of MLDS container functions defining a procedure in a TSCC
% never define any of the procedure's own variables of the arguments;
% they all need to be defined at the top of the container function.
% OwnLocalVarDefns will contain these definitions.
%
% The values of TsccInLocalVarDefns and TsccOutLocalVarDefns are also
% destined for the top of container functions; they will contain
% the local variable definitions of the TSCC in and out variables
% respectively.
%
% For container function's argument list will define the TSCC in variables
% of the procedure that the container function is for, but the top of
% that container function must define the TSCC in variables of all the
% *other* procedures in the TSCC. (This is how we ensure that each
% lvn_tscc_proc_input_var of each TSCC procedure will be defined by
% exactly one of TsccInLocalVarDefns and FuncParams in each container
% function.)
%
% The TSCC out variables (which are *not* specific to a given procedure
% in the TSCC) are never defined in container function signatures.
% If an output argument is returned by reference, the argument list
% contain the TSCC out ptr variable, not the TSCC out variable, while
% if the argument is returned by value, then only its type will be listed
% in the return types part of the signature. This is why the top of the
% container function must include the contents of TsccOutLocalVarDefns.
%
% Each wrapped procedure starts by copying the values of its TSCC in
% variables to their corresponding own variables; CopyTsccInToOwnStmts
% contains this code. Each wrapped procedure ends by copying the values
% of its own variables (including the success indicator, if present)
% to the corresponding TSCC out variables; CopyOwnToTsccOutStmts
% contains this code. If any output arguments are to be returned
% via reference, then the epilogue of the container function must copy
% the values of those arguments from their TSCC out variables to the
% address pointed to by their TSCC out ptr variables;
% CopyOutValThroughPtrStmts contains this code.
%
:- pred ml_gen_tscc_arg_params(module_info::in, pred_or_func::in,
code_model::in, prog_context::in, proc_id_in_tscc::in, prog_varset::in,
list(prog_var)::in, list(mer_type)::in, list(mer_mode)::in,
list(var_mvar_type_mode)::out,
map(int, string)::in, map(int, string)::out,
list(mlds_argument)::out, mlds_func_params::out,
assoc_list(mlds_rval, mlds_type)::out,
assoc_list(mlds_local_var_name, mlds_type)::out,
list(mlds_local_var_defn)::out, list(mlds_local_var_defn)::out,
list(mlds_local_var_defn)::out,
list(mlds_stmt)::out, list(mlds_stmt)::out, list(mlds_stmt)::out) is det.
%---------------------------------------------------------------------------%
%
% Generate code for parameter passing.
%
% The ml_gen_args predicate allows the argument being passed to a callee
% procedure may be specified in one of two ways.
%
% The usual way is to simply specify the HLDS variable being passed.
%
% When creating closure wrappers, not all variables being passed
% come for the HLDS; some come from the closure. In such cases,
% we specify the MLDS local variable being passed, its lval, and its type.
%
% The ml_gen_args predicate and its subcontractors all require that
%
% - either all arguments are arg_not_for_closure_wrapper,
% - or all arguments are arg_for_closure_wrapper.
%
:- type ml_call_arg
---> arg_not_for_closure_wrapper(prog_var)
; arg_for_closure_wrapper(mlds_local_var_name, mlds_lval, mer_type).
:- inst not_fcw for ml_call_arg/0
---> arg_not_for_closure_wrapper(ground).
:- inst fcw for ml_call_arg/0
---> arg_for_closure_wrapper(ground, ground, ground).
:- func wrap_plain_not_fcw_arg(prog_var::in)
= (ml_call_arg::out(not_fcw)) is det.
:- func wrap_plain_not_fcw_args(list(prog_var)::in)
= (list(ml_call_arg)::out(list_skel(not_fcw))) is det.
:- type what_params
---> input_params_only
; input_and_output_params.
% Generate rvals and lvals for the arguments of a procedure call.
%
:- pred ml_gen_args(pred_or_func, code_model, prog_context, what_params,
list(mer_type), list(mer_mode), list(ml_call_arg),
list(mlds_rval), assoc_list(mlds_lval, mlds_type),
list(mlds_local_var_defn), list(mlds_stmt), ml_gen_info, ml_gen_info).
:- mode ml_gen_args(in, in, in, in, in, in, in(list_skel(not_fcw)),
out, out, out, out, in, out) is det.
:- mode ml_gen_args(in, in, in, in, in, in, in(list_skel(fcw)),
out, out, out, out, in, out) is det.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
:- import_module check_hlds.
:- import_module check_hlds.mode_util.
:- import_module check_hlds.type_util.
:- import_module libs.
:- import_module libs.globals.
:- import_module libs.options.
:- import_module mdbcomp.program_representation.
:- import_module ml_backend.ml_accurate_gc.
:- import_module ml_backend.ml_code_util.
:- import_module parse_tree.prog_data_foreign.
:- import_module int.
:- import_module maybe.
:- import_module pair.
:- import_module require.
:- import_module term.
:- import_module varset.
%---------------------------------------------------------------------------%
%
% Code for various utility routines.
%
ml_append_return_statement(CodeModel, Context, CopiedOutputVarRvals, !Stmts) :-
(
CodeModel = model_semi,
SucceededVar = lvn_comp_var(lvnc_succeeded),
SucceededLval = ml_local_var(SucceededVar, mlds_native_bool_type),
SucceededRval = ml_lval(SucceededLval),
ReturnedRvals = [SucceededRval | CopiedOutputVarRvals],
ReturnStmt = ml_stmt_return(ReturnedRvals, Context),
!:Stmts = !.Stmts ++ [ReturnStmt]
;
CodeModel = model_det,
(
CopiedOutputVarRvals = [_ | _],
ReturnStmt = ml_stmt_return(CopiedOutputVarRvals, Context),
!:Stmts = !.Stmts ++ [ReturnStmt]
;
CopiedOutputVarRvals = []
% This return statement is not needed when we generate code
% for a standalone HLDS procedure, since the end of the MLDS
% function acts as an implicit return. It *is* needed when the
% MLDS function also contains the code of other HLDS procedures
% in the same TSCC, but that case is handled in ml_proc_gen.m.
%
% Note that adding a return statement after the body of a procedure
% that throws an exception may, if this fact is visible to the
% target language compiler, cause that compiler to generate an
% error. The Java compiler does this when the body of a HLDS
% procedure is defined by Java code that does a throw.
)
;
CodeModel = model_non
).
%---------------------------------------------------------------------------%
compute_when_to_copy_out(CopyOut, CodeModel, PredOrFunc) = CopyOutWhen :-
(
CopyOut = yes,
CopyOutWhen = copy_out_always
;
CopyOut = no,
( if
CodeModel = model_det,
PredOrFunc = pf_function
then
% Return the result argument (i.e. the last argument)
% of a procedure if that procedure is a det function.
CopyOutWhen = copy_out_only_last_arg
else
CopyOutWhen = copy_out_never
)
).
%---------------------------------------------------------------------------%
%
% Code for generating function declarations (i.e. mlds_func_params).
%
:- pred get_raw_data_for_proc_params(module_info::in, pred_proc_id::in,
pred_info::out, pred_or_func::out, code_model::out,
list(var_mvar_type_mode)::out) is det.
% Some of our callers don't need all our outputs.
:- pragma inline(get_raw_data_for_proc_params/6).
get_raw_data_for_proc_params(ModuleInfo, PredProcId, PredInfo,
PredOrFunc, CodeModel, ArgTuples) :-
module_info_pred_proc_info(ModuleInfo, PredProcId, PredInfo, ProcInfo),
PredOrFunc = pred_info_is_pred_or_func(PredInfo),
CodeModel = proc_info_interface_code_model(ProcInfo),
proc_info_get_varset(ProcInfo, VarSet),
proc_info_get_headvars(ProcInfo, HeadVars),
pred_info_get_arg_types(PredInfo, HeadTypes),
proc_info_get_argmodes(ProcInfo, HeadModes),
package_vars_types_modes(ModuleInfo, VarSet,
HeadVars, HeadTypes, HeadModes, ArgTuples).
:- pred package_vars_types_modes(module_info::in, prog_varset::in,
list(prog_var)::in, list(mer_type)::in, list(mer_mode)::in,
list(var_mvar_type_mode)::out) is det.
package_vars_types_modes(ModuleInfo, VarSet, Vars, Types, Modes, ArgTuples) :-
( if
Vars = [],
Types = [],
Modes = []
then
ArgTuples = []
else if
Vars = [HeadVar | TailVars],
Types = [HeadType | TailTypes],
Modes = [HeadMode | TailModes]
then
package_vars_types_modes(ModuleInfo, VarSet,
TailVars, TailTypes, TailModes, TailArgTuples),
mode_to_top_functor_mode(ModuleInfo, HeadMode, HeadType,
HeadTopFunctorMode),
HeadMLDSVarName = ml_gen_local_var_name(VarSet, HeadVar),
HeadArgTuple = var_mvar_type_mode(HeadVar, HeadMLDSVarName, HeadType,
HeadTopFunctorMode),
ArgTuples = [HeadArgTuple | TailArgTuples]
else
unexpected($pred, "length mismatch")
).
:- pred package_vars_mvars_types_modes(module_info::in, list(prog_var)::in,
list(mlds_local_var_name)::in, list(mer_type)::in, list(mer_mode)::in,
list(var_mvar_type_mode)::out) is det.
package_vars_mvars_types_modes(ModuleInfo,
Vars, MLDSVarNames, Types, Modes, ArgTuples) :-
( if
Vars = [],
MLDSVarNames = [],
Types = [],
Modes = []
then
ArgTuples = []
else if
Vars = [HeadVar | TailVars],
MLDSVarNames = [HeadMLDSVarName | TailMLDSVarNames],
Types = [HeadType | TailTypes],
Modes = [HeadMode | TailModes]
then
package_vars_mvars_types_modes(ModuleInfo, TailVars, TailMLDSVarNames,
TailTypes, TailModes, TailArgTuples),
mode_to_top_functor_mode(ModuleInfo, HeadMode, HeadType,
HeadTopFunctorMode),
HeadArgTuple = var_mvar_type_mode(HeadVar, HeadMLDSVarName, HeadType,
HeadTopFunctorMode),
ArgTuples = [HeadArgTuple | TailArgTuples]
else
unexpected($pred, "length mismatch")
).
:- pred package_rtti_vars_types_topmodes(
assoc_list(prog_var, prog_var_name)::in,
list(mer_type)::in, list(top_functor_mode)::in,
list(var_mvar_type_mode)::out) is det.
package_rtti_vars_types_topmodes(VarPairs, Types, TopFunctorModes,
ArgTuples) :-
( if
VarPairs = [],
Types = [],
TopFunctorModes = []
then
ArgTuples = []
else if
VarPairs = [HeadVarPair | TailVarPairs],
Types = [HeadType | TailTypes],
TopFunctorModes = [HeadTopFunctorMode | TailTopFunctorModes]
then
package_rtti_vars_types_topmodes(TailVarPairs, TailTypes,
TailTopFunctorModes, TailArgTuples),
HeadVarPair = HeadVar - HeadVarName,
term.var_to_int(HeadVar, HeadVarNum),
HeadMLDSVarName = lvn_prog_var(HeadVarName, HeadVarNum),
HeadArgTuple = var_mvar_type_mode(HeadVar, HeadMLDSVarName, HeadType,
HeadTopFunctorMode),
ArgTuples = [HeadArgTuple | TailArgTuples]
else
unexpected($pred, "length mismatch")
).
%---------------------%
ml_gen_proc_params_no_gc_stmts(ModuleInfo, PredProcId,
ArgTuples, FuncParams) :-
get_raw_data_for_proc_params(ModuleInfo, PredProcId, _PredInfo,
PredOrFunc, CodeModel, ArgTuples),
ml_gen_params_base(ModuleInfo, PredOrFunc, CodeModel,
input_and_output_params, ArgTuples, FuncParams, _ByRef, _Copied,
no, _).
ml_gen_info_proc_params(PredProcId, ArgTuples, FuncParams,
ByRefOutputVars, CopiedOutputVars, !Info) :-
ml_gen_info_get_module_info(!.Info, ModuleInfo),
get_raw_data_for_proc_params(ModuleInfo, PredProcId, PredInfo,
PredOrFunc, CodeModel, ArgTuples),
% We must not generate GC tracing code for no_type_info_builtin procedures,
% because the generated GC tracing code would refer to type_infos
% that don't get passed.
PredModule = pred_info_module(PredInfo),
PredName = pred_info_name(PredInfo),
PredArity = pred_info_orig_arity(PredInfo),
( if no_type_info_builtin(PredModule, PredName, PredArity) then
ml_gen_params_base(ModuleInfo, PredOrFunc, CodeModel,
input_and_output_params, ArgTuples, FuncParams,
ByRefOutputVars, CopiedOutputVars, no, _)
else
ml_gen_params_base(ModuleInfo, PredOrFunc, CodeModel,
input_and_output_params, ArgTuples, FuncParams,
ByRefOutputVars, CopiedOutputVars, yes(!.Info), yes(!:Info))
).
ml_gen_proc_params_inputs_only_no_gc_stmts(ModuleInfo, PredProcId)
= FuncArgs :-
get_raw_data_for_proc_params(ModuleInfo, PredProcId, _PredInfo,
_PredOrFunc, _CodeModel, ArgTuples),
ml_gen_arg_decls(ModuleInfo, copy_out_never, input_params_only, ArgTuples,
FuncArgs, RetTypes, _ByRef, _Copied, no, _),
expect(unify(RetTypes, []), $pred, "RetTypes != []").
ml_gen_proc_params_from_rtti_no_gc_stmts(ModuleInfo, RttiProcId)
= FuncParams :-
PredOrFunc = RttiProcId ^ rpl_pred_or_func,
Detism = RttiProcId ^ rpl_proc_interface_detism,
determinism_to_code_model(Detism, CodeModel),
HeadVars = RttiProcId ^ rpl_proc_headvars,
ArgTypes = RttiProcId ^ rpl_proc_arg_types,
TopFunctorModes = RttiProcId ^ rpl_proc_top_modes,
package_rtti_vars_types_topmodes(HeadVars, ArgTypes, TopFunctorModes,
ArgTuples),
ml_gen_params_base(ModuleInfo, PredOrFunc, CodeModel,
input_and_output_params, ArgTuples, FuncParams, _ByRef, _Copied,
no, _).
ml_gen_params_no_gc_stmts(ModuleInfo, PredOrFunc, CodeModel,
HeadVars, HeadMLDSVarNames, HeadTypes, HeadModes,
ArgTuples, FuncParams) :-
package_vars_mvars_types_modes(ModuleInfo, HeadVars, HeadMLDSVarNames,
HeadTypes, HeadModes, ArgTuples),
ml_gen_params_base(ModuleInfo, PredOrFunc, CodeModel,
input_and_output_params, ArgTuples, FuncParams, _ByRef, _Copied,
no, _).
:- inst is_in for what_params/0
---> input_params_only.
:- inst is_inout for what_params/0
---> input_and_output_params.
:- inst is_no for maybe/1
---> no.
:- inst is_yes for maybe/1
---> yes(ground).
% The mlds_arguments in the generated parameters have the gc stmt field
% filled in only if !.MaybeInfo is yes(_).
%
:- pred ml_gen_params_base(module_info, pred_or_func, code_model, what_params,
list(var_mvar_type_mode), mlds_func_params,
list(prog_var), list(prog_var), maybe(ml_gen_info), maybe(ml_gen_info)).
:- mode ml_gen_params_base(in, in, in, in(is_in), in, out, out, out,
in(is_no), out(is_no)) is det.
:- mode ml_gen_params_base(in, in, in, in(is_inout), in, out, out, out,
in(is_no), out(is_no)) is det.
:- mode ml_gen_params_base(in, in, in, in(is_inout), in, out, out, out,
in(is_yes), out(is_yes)) is det.
ml_gen_params_base(ModuleInfo, PredOrFunc, CodeModel, WhatParams, ArgTuples,
FuncParams, ByRefOutputVars, CopiedOutputVars, !MaybeInfo) :-
module_info_get_globals(ModuleInfo, Globals),
CopyOut = get_copy_out_option(Globals, CodeModel),
CopyOutWhen = compute_when_to_copy_out(CopyOut, CodeModel, PredOrFunc),
ml_gen_arg_decls(ModuleInfo, CopyOutWhen, WhatParams, ArgTuples,
FuncArgs0, RetTypes0, ByRefOutputVars, CopiedOutputVars, !MaybeInfo),
(
CodeModel = model_det,
FuncArgs = FuncArgs0,
RetTypes = RetTypes0
;
CodeModel = model_semi,
% For model_semi procedures, return a bool.
FuncArgs = FuncArgs0,
RetTypes = [mlds_native_bool_type | RetTypes0]
;
CodeModel = model_non,
% For model_non procedures, we return values by passing them
% to the continuation.
(
CopyOut = yes,
ContType = mlds_cont_type(RetTypes0),
RetTypes = []
;
CopyOut = no,
ContType = mlds_cont_type([]),
RetTypes = RetTypes0
),
ContVarName = lvn_comp_var(lvnc_cont),
% The cont variable always points to code, not to the heap,
% so the GC never needs to trace it.
ContArg = mlds_argument(ContVarName, ContType, gc_no_stmt),
ContEnvType = mlds_generic_env_ptr_type,
ContEnvVarName = lvn_comp_var(lvnc_cont_env_ptr),
% The cont_env_ptr always points to the stack, since continuation
% environments are always allocated on the stack (unless
% put_nondet_env_on_heap is true, which won't be the case when doing
% our own GC -- this is enforced in handle_options.m).
% So the GC doesn't need to trace it.
ContEnvArg = mlds_argument(ContEnvVarName, ContEnvType, gc_no_stmt),
FuncArgs = FuncArgs0 ++ [ContArg, ContEnvArg]
),
FuncParams = mlds_func_params(FuncArgs, RetTypes).
% Given the argument variable names, and corresponding lists of their
% types and modes, generate the MLDS argument declarations
% and return types.
%
% The generated mlds_arguments have the gc stmt field filled in
% only if !.MaybeInfo is yes(_).
%
:- pred ml_gen_arg_decls(module_info, copy_out_when, what_params,
list(var_mvar_type_mode), list(mlds_argument), mlds_return_types,
list(prog_var), list(prog_var), maybe(ml_gen_info), maybe(ml_gen_info)).
:- mode ml_gen_arg_decls(in, in, in(is_in), in, out, out, out, out,
in(is_no), out(is_no)) is det.
:- mode ml_gen_arg_decls(in, in, in(is_inout), in, out, out, out, out,
in(is_no), out(is_no)) is det.
:- mode ml_gen_arg_decls(in, in, in(is_inout), in, out, out, out, out,
in(is_yes), out(is_yes)) is det.
ml_gen_arg_decls(_, _, _, [], [], [], [], [], !MaybeInfo).
ml_gen_arg_decls(ModuleInfo, CopyOutWhen, WhatParams, [HeadTuple | TailTuples],
FuncArgs, RetTypes, ByRefOutputVars, CopiedOutputVars, !MaybeInfo) :-
ml_gen_arg_decls(ModuleInfo, CopyOutWhen, WhatParams, TailTuples,
TailFuncArgs, TailRetTypes, TailByRefOutputVars, TailCopiedOutputVars,
!MaybeInfo),
HeadTuple = var_mvar_type_mode(HeadVar, HeadMLDSVar, HeadType, HeadMode),
HeadIsDummy = is_type_a_dummy(ModuleInfo, HeadType),
(
HeadIsDummy = is_dummy_type,
% Exclude types such as io.state, etc.
FuncArgs = TailFuncArgs,
RetTypes = TailRetTypes,
ByRefOutputVars = TailByRefOutputVars,
CopiedOutputVars = TailCopiedOutputVars
;
HeadIsDummy = is_not_dummy_type,
HeadMLDS_Type = mercury_type_to_mlds_type(ModuleInfo, HeadType),
(
HeadMode = top_unused,
% Also exclude values with arg_mode `top_unused'.
FuncArgs = TailFuncArgs,
RetTypes = TailRetTypes,
ByRefOutputVars = TailByRefOutputVars,
CopiedOutputVars = TailCopiedOutputVars
;
HeadMode = top_in,
% For inputs, generate an argument.
HeadMLDS_ArgType = HeadMLDS_Type,
ml_gen_arg_decl(HeadMLDSVar, HeadType, HeadMLDS_ArgType,
HeadFuncArg, !MaybeInfo),
FuncArgs = [HeadFuncArg | TailFuncArgs],
RetTypes = TailRetTypes,
ByRefOutputVars = TailByRefOutputVars,
CopiedOutputVars = TailCopiedOutputVars
;
HeadMode = top_out,
(
WhatParams = input_params_only,
FuncArgs = TailFuncArgs,
RetTypes = TailRetTypes,
ByRefOutputVars = TailByRefOutputVars,
CopiedOutputVars = TailCopiedOutputVars
;
WhatParams = input_and_output_params,
( if
(
CopyOutWhen = copy_out_only_last_arg,
TailTuples = []
;
CopyOutWhen = copy_out_always
)
then
% For by-value outputs, generate a return type.
FuncArgs = TailFuncArgs,
RetTypes = [HeadMLDS_Type | TailRetTypes],
ByRefOutputVars = TailByRefOutputVars,
CopiedOutputVars = [HeadVar | TailCopiedOutputVars]
else
% For by-reference outputs, generate an argument.
HeadMLDS_ArgType = mlds_ptr_type(HeadMLDS_Type),
ml_gen_arg_decl(HeadMLDSVar, HeadType, HeadMLDS_ArgType,
HeadFuncArg, !MaybeInfo),
FuncArgs = [HeadFuncArg | TailFuncArgs],
RetTypes = TailRetTypes,
ByRefOutputVars = [HeadVar | TailByRefOutputVars],
CopiedOutputVars = TailCopiedOutputVars
)
)
)
).
% Given an argument variable, its actual type and its arg type,
% generate an MLDS argument declaration for it.
%
% The generated mlds_argument has the gc stmt field filled in
% only if !.MaybeInfo is yes(_).
%
:- pred ml_gen_arg_decl(mlds_local_var_name, mer_type, mlds_type,
mlds_argument, maybe(ml_gen_info), maybe(ml_gen_info)).
:- mode ml_gen_arg_decl(in, in, in, out, in(is_no), out(is_no)) is det.
:- mode ml_gen_arg_decl(in, in, in, out, in(is_yes), out(is_yes)) is det.
ml_gen_arg_decl(Var, Type, MLDS_ArgType, FuncArg, !MaybeInfo) :-
(
!.MaybeInfo = yes(Info0),
% XXX We should fill in this Context properly.
term.context_init(Context),
ml_gen_gc_statement(Var, Type, Context, GCStmt, Info0, Info),
!:MaybeInfo = yes(Info)
;
!.MaybeInfo = no,
GCStmt = gc_no_stmt,
!:MaybeInfo = no
),
FuncArg = mlds_argument(Var, MLDS_ArgType, GCStmt).
%---------------------%
ml_gen_tscc_arg_params(ModuleInfo, PredOrFunc, CodeModel, Context,
ProcIdInTscc, VarSet, Vars, Types, Modes, ArgTuples, !OutArgNames,
TsccInArgs, FuncParams, ReturnRvalsTypes, OutVarsTypes,
OwnLocalVarDefns, TsccInLocalVarDefns, TsccOutLocalVarDefns,
CopyTsccInToOwnStmts, CopyOwnToTsccOutStmts,
CopyOutValThroughPtrStmts) :-
module_info_get_globals(ModuleInfo, Globals),
CopyOut = get_copy_out_option(Globals, CodeModel),
CopyOutWhen = compute_when_to_copy_out(CopyOut, CodeModel, PredOrFunc),
package_vars_types_modes(ModuleInfo, VarSet, Vars, Types, Modes,
ArgTuples),
NextInArgNum0 = 1,
NextOutArgNum0 = 1,
ml_gen_tscc_arg_decls(ModuleInfo, CopyOutWhen, Context,
ProcIdInTscc, ArgTuples, NextInArgNum0, NextOutArgNum0,
!OutArgNames, TsccInArgs, TsccArgs, ReturnRvalsTypes0, OutVarsTypes0,
OwnLocalVarDefns, TsccInLocalVarDefns, TsccOutLocalVarDefns0,
CopyTsccInToOwnStmts,
CopyOwnToTsccOutStmts0, CopyOutValThroughPtrStmts),
(
CodeModel = model_det,
ReturnRvalsTypes = ReturnRvalsTypes0,
OutVarsTypes = OutVarsTypes0,
TsccOutLocalVarDefns = TsccOutLocalVarDefns0,
CopyOwnToTsccOutStmts = CopyOwnToTsccOutStmts0
;
CodeModel = model_semi,
SucceededType = mlds_native_bool_type,
SucceededOwnVar = lvn_comp_var(lvnc_succeeded),
SucceededOwnLval = ml_local_var(SucceededOwnVar, SucceededType),
SucceededOwnRval = ml_lval(SucceededOwnLval),
SucceededTsccOutVar = lvn_tscc_output_var_succeeded,
SucceededTsccOutLval =
ml_local_var(SucceededTsccOutVar, SucceededType),
SucceededTsccOutRval = ml_lval(SucceededTsccOutLval),
SucceededTsccOutVarDefn = mlds_local_var_defn(SucceededTsccOutVar,
Context, SucceededType, no_initializer, gc_no_stmt),
CopySucceededStmt = ml_stmt_atomic(
assign(SucceededTsccOutLval, SucceededOwnRval),
Context),
ReturnRvalsTypes =
[SucceededTsccOutRval - SucceededType | ReturnRvalsTypes0],
OutVarsTypes = [SucceededTsccOutVar - SucceededType | OutVarsTypes0],
TsccOutLocalVarDefns =
[SucceededTsccOutVarDefn | TsccOutLocalVarDefns0],
CopyOwnToTsccOutStmts = [CopySucceededStmt | CopyOwnToTsccOutStmts0]
;
CodeModel = model_non,
unexpected($pred, "model_non")
),
assoc_list.values(ReturnRvalsTypes, ReturnTypes),
FuncParams = mlds_func_params(TsccArgs, ReturnTypes).
:- pred ml_gen_tscc_arg_decls(module_info::in, copy_out_when::in,
prog_context::in, proc_id_in_tscc::in, list(var_mvar_type_mode)::in,
int::in, int::in, map(int, string)::in, map(int, string)::out,
list(mlds_argument)::out, list(mlds_argument)::out,
assoc_list(mlds_rval, mlds_type)::out,
assoc_list(mlds_local_var_name, mlds_type)::out,
list(mlds_local_var_defn)::out, list(mlds_local_var_defn)::out,
list(mlds_local_var_defn)::out,
list(mlds_stmt)::out, list(mlds_stmt)::out, list(mlds_stmt)::out) is det.
ml_gen_tscc_arg_decls(_ModuleInfo, _CopyOutWhen, _Context, _ProcIdInTscc, [],
_NextInArgNum0, _NextOutArgNum0, !OutArgNames,
[], [], [], [], [], [], [], [], [], []).
ml_gen_tscc_arg_decls(ModuleInfo, CopyOutWhen, Context, ProcIdInTscc,
[HeadTuple | TailTuples], NextInArgNum0, NextOutArgNum0,
!OutArgNames, TsccInArgs, TsccArgs, ReturnRvalsTypes, OutVarsTypes,
OwnLocalVarDefns, TsccInLocalVarDefns, TsccOutLocalVarDefns,
CopyTsccInToOwnStmts,
CopyOwnToTsccOutStmts, CopyOutValThroughPtrStmts) :-
HeadTuple =
var_mvar_type_mode(_HeadVar, HeadMLDSVarName, HeadType, HeadMode),
HeadIsDummy = is_type_a_dummy(ModuleInfo, HeadType),
(
HeadIsDummy = is_dummy_type,
% Exclude types such as io.state, etc.
ml_gen_tscc_arg_decls(ModuleInfo, CopyOutWhen, Context,
ProcIdInTscc, TailTuples,
NextInArgNum0, NextOutArgNum0, !OutArgNames,
TsccInArgs, TsccArgs, ReturnRvalsTypes, OutVarsTypes,
OwnLocalVarDefns, TsccInLocalVarDefns, TsccOutLocalVarDefns,
CopyTsccInToOwnStmts,
CopyOwnToTsccOutStmts, CopyOutValThroughPtrStmts)
;
HeadIsDummy = is_not_dummy_type,
HeadVarNameStr = ml_local_var_name_to_string(HeadMLDSVarName),
HeadMLDS_Type = mercury_type_to_mlds_type(ModuleInfo, HeadType),
(
HeadMode = top_unused,
% Also exclude values with arg_mode `top_unused'.
ml_gen_tscc_arg_decls(ModuleInfo, CopyOutWhen, Context,
ProcIdInTscc, TailTuples,
NextInArgNum0, NextOutArgNum0, !OutArgNames,
TsccInArgs, TsccArgs, ReturnRvalsTypes, OutVarsTypes,
OwnLocalVarDefns, TsccInLocalVarDefns,
TsccOutLocalVarDefns, CopyTsccInToOwnStmts,
CopyOwnToTsccOutStmts, CopyOutValThroughPtrStmts)
;
(
HeadMode = top_in,
InArgNum = NextInArgNum0,
NextInArgNum = NextInArgNum0 + 1,
NextOutArgNum = NextOutArgNum0,
HeadTsccInVar = lvn_tscc_proc_input_var(ProcIdInTscc,
InArgNum, HeadVarNameStr),
HeadMLDSVarLval =
ml_local_var(HeadMLDSVarName, HeadMLDS_Type),
HeadTsccInVarLval =
ml_local_var(HeadTsccInVar, HeadMLDS_Type),
HeadTsccInArg = mlds_argument(HeadTsccInVar, HeadMLDS_Type,
gc_no_stmt),
HeadTsccInArgs = [HeadTsccInArg],
HeadTsccArgs = [HeadTsccInArg],
HeadReturnRvalsTypes = [],
HeadOutVarsTypes = [],
HeadOwnLocalVarDefn = mlds_local_var_defn(HeadMLDSVarName,
Context, HeadMLDS_Type, no_initializer, gc_no_stmt),
HeadTsccInLocalVarDefns = [mlds_local_var_defn(HeadTsccInVar,
Context, HeadMLDS_Type, no_initializer, gc_no_stmt)],
HeadTsccOutLocalVarDefns = [],
HeadCopyTsccInToOwnStmts = [ml_stmt_atomic(
assign(HeadMLDSVarLval, ml_lval(HeadTsccInVarLval)),
Context)],
HeadCopyOwnToTsccOutStmts = [],
HeadCopyOutValThroughPtrStmts = []
;
HeadMode = top_out,
OutArgNum = NextOutArgNum0,
NextInArgNum = NextInArgNum0,
NextOutArgNum = NextOutArgNum0 + 1,
( if map.search(!.OutArgNames, OutArgNum, OldOutArgName) then
OutArgName = OldOutArgName
else
OutArgName = HeadVarNameStr,
map.det_insert(OutArgNum, OutArgName, !OutArgNames)
),
HeadMLDSVarLval = ml_local_var(HeadMLDSVarName, HeadMLDS_Type),
HeadTsccOutVarValue =
lvn_tscc_output_var(OutArgNum, OutArgName),
HeadTsccOutVarValueLval =
ml_local_var(HeadTsccOutVarValue, HeadMLDS_Type),
HeadTsccInArgs = [],
% HeadTsccArgs in if-then-else below
% HeadReturnRvalsTypes in if-then-else below
HeadOutVarsTypes = [HeadTsccOutVarValue - HeadMLDS_Type],
HeadOwnLocalVarDefn = mlds_local_var_defn(HeadMLDSVarName,
Context, HeadMLDS_Type, no_initializer, gc_no_stmt),
HeadTsccInLocalVarDefns = [],
HeadTsccOutLocalVarDefns =
[mlds_local_var_defn(HeadTsccOutVarValue,
Context, HeadMLDS_Type, no_initializer, gc_no_stmt)],
HeadCopyTsccInToOwnStmts = [],
HeadCopyOwnToTsccOutStmts = [ml_stmt_atomic(
assign(HeadTsccOutVarValueLval, ml_lval(HeadMLDSVarLval)),
Context)],
% HeadCopyOutValThroughPtrStmts in if-then-else below
( if
(
CopyOutWhen = copy_out_only_last_arg,
TailTuples = []
;
CopyOutWhen = copy_out_always
)
then
% This is a by-value output.
HeadReturnRval = ml_lval(HeadTsccOutVarValueLval),
HeadTsccArgs = [],
HeadReturnRvalsTypes = [HeadReturnRval - HeadMLDS_Type],
HeadCopyOutValThroughPtrStmts = []
else
% This is a by-reference output.
HeadMLDS_PtrType = mlds_ptr_type(HeadMLDS_Type),
HeadTsccOutVarPtr =
lvn_tscc_output_var_ptr(OutArgNum, OutArgName),
HeadTsccOutVarPtrLval =
ml_local_var(HeadTsccOutVarPtr, HeadMLDS_PtrType),
HeadTsccPtrArg = mlds_argument(HeadTsccOutVarPtr,
HeadMLDS_PtrType, gc_no_stmt),
HeadTsccArgs = [HeadTsccPtrArg],
HeadReturnRvalsTypes = [],
HeadCopyOutValThroughPtrStmts = [ml_stmt_atomic(
assign(ml_mem_ref(
ml_lval(HeadTsccOutVarPtrLval), HeadMLDS_Type),
ml_lval(HeadTsccOutVarValueLval)),
Context)]
)
),
ml_gen_tscc_arg_decls(ModuleInfo, CopyOutWhen, Context,
ProcIdInTscc, TailTuples,
NextInArgNum, NextOutArgNum, !OutArgNames,
TailTsccInArgs, TailTsccArgs,
TailReturnRvalsTypes, TailOutVarsTypes,
TailOwnLocalVarDefns, TailTsccInLocalVarDefns,
TailTsccOutLocalVarDefns,
TailCopyTsccInToOwnStmts, TailCopyOwnToTsccOutStmts,
TailCopyOutValThroughPtrStmts),
TsccInArgs = HeadTsccInArgs ++ TailTsccInArgs,
TsccArgs = HeadTsccArgs ++ TailTsccArgs,
ReturnRvalsTypes = HeadReturnRvalsTypes ++ TailReturnRvalsTypes,
OutVarsTypes = HeadOutVarsTypes ++ TailOutVarsTypes,
OwnLocalVarDefns = [HeadOwnLocalVarDefn | TailOwnLocalVarDefns],
TsccInLocalVarDefns =
HeadTsccInLocalVarDefns ++ TailTsccInLocalVarDefns,
TsccOutLocalVarDefns =
HeadTsccOutLocalVarDefns ++ TailTsccOutLocalVarDefns,
CopyTsccInToOwnStmts =
HeadCopyTsccInToOwnStmts ++ TailCopyTsccInToOwnStmts,
CopyOwnToTsccOutStmts =
HeadCopyOwnToTsccOutStmts ++ TailCopyOwnToTsccOutStmts,
CopyOutValThroughPtrStmts =
HeadCopyOutValThroughPtrStmts ++ TailCopyOutValThroughPtrStmts
)
).
%---------------------------------------------------------------------------%
%
% Generate code for parameter passing.
%
wrap_plain_not_fcw_arg(Var) = arg_not_for_closure_wrapper(Var).
wrap_plain_not_fcw_args([]) = [].
wrap_plain_not_fcw_args([Var | Vars]) =
[arg_not_for_closure_wrapper(Var) | wrap_plain_not_fcw_args(Vars)].
ml_gen_args(PredOrFunc, CodeModel, Context, WhatParams,
CalleeTypes, CalleeModes, CallerArgs, !:InputRvals, !:OutputLvalsTypes,
!:ConvOutputDefns, !:ConvOutputStmts, !Info) :-
ml_gen_info_get_copy_out(!.Info, CodeModel, CopyOut),
CopyOutWhen = compute_when_to_copy_out(CopyOut, CodeModel, PredOrFunc),
ml_gen_args_loop(CopyOutWhen, Context, WhatParams, 1,
CalleeTypes, CalleeModes, CallerArgs, !:InputRvals, !:OutputLvalsTypes,
!:ConvOutputDefns, !:ConvOutputStmts, !Info).
:- pred ml_gen_args_loop(copy_out_when, prog_context, what_params, int,
list(mer_type), list(mer_mode), list(ml_call_arg),
list(mlds_rval), assoc_list(mlds_lval, mlds_type),
list(mlds_local_var_defn), list(mlds_stmt), ml_gen_info, ml_gen_info).
:- mode ml_gen_args_loop(in, in, in, in, in, in, in(list_skel(not_fcw)),
out, out, out, out, in, out) is det.
:- mode ml_gen_args_loop(in, in, in, in, in, in, in(list_skel(fcw)),
out, out, out, out, in, out) is det.
ml_gen_args_loop(CopyOutWhen, Context, WhatParams, ArgNum,
CalleeTypes, CalleeModes, CallerArgs, !:InputRvals, !:OutputLvalsTypes,
!:ConvOutputDefns, !:ConvOutputStmts, !Info) :-
( if
CalleeTypes = [],
CalleeModes = [],
CallerArgs = []
then
!:InputRvals = [],
!:OutputLvalsTypes = [],
!:ConvOutputDefns = [],
!:ConvOutputStmts = []
else if
CalleeTypes = [CalleeType | CalleeTypesTail],
CalleeModes = [CalleeMode | CalleeModesTail],
CallerArgs = [CallerArg | CallerArgsTail]
then
ml_gen_args_loop(CopyOutWhen, Context, WhatParams, ArgNum + 1,
CalleeTypesTail, CalleeModesTail, CallerArgsTail,
!:InputRvals, !:OutputLvalsTypes,
!:ConvOutputDefns, !:ConvOutputStmts, !Info),
ml_gen_arg(CopyOutWhen, Context, WhatParams, ArgNum,
CalleeType, CalleeMode, CallerArg, CallerArgsTail,
!InputRvals, !OutputLvalsTypes,
!ConvOutputDefns, !ConvOutputStmts, !Info)
else
unexpected($pred, "length mismatch")
).
:- pred ml_gen_arg(copy_out_when, prog_context, what_params, int,
mer_type, mer_mode, ml_call_arg, list(ml_call_arg),
list(mlds_rval), list(mlds_rval),
assoc_list(mlds_lval, mlds_type), assoc_list(mlds_lval, mlds_type),
list(mlds_local_var_defn), list(mlds_local_var_defn),
list(mlds_stmt), list(mlds_stmt), ml_gen_info, ml_gen_info).
:- mode ml_gen_arg(in, in, in, in, in, in, in(not_fcw),
in, in, out, in, out, in, out, in, out, in, out) is det.
:- mode ml_gen_arg(in, in, in, in, in, in, in(fcw),
in, in, out, in, out, in, out, in, out, in, out) is det.
:- pragma inline(ml_gen_arg/18).
ml_gen_arg(CopyOutWhen, Context, WhatParams, ArgNum,
CalleeType, CalleeMode, CallerArg,
CallerArgsTail, !InputRvals, !OutputLvalsTypes,
!ConvOutputDefns, !ConvOutputStmts, !Info) :-
ml_gen_info_get_module_info(!.Info, ModuleInfo),
mode_to_top_functor_mode(ModuleInfo, CalleeMode, CalleeType,
CalleeArgTopFunctorMode),
CalleeIsDummy = is_type_a_dummy(ModuleInfo, CalleeType),
(
CalleeIsDummy = is_dummy_type
% Exclude arguments of type io.state etc.
;
CalleeIsDummy = is_not_dummy_type,
(
CallerArg = arg_not_for_closure_wrapper(CallerArgVar),
ml_gen_info_get_varset(!.Info, VarSet),
CallerMLDSVarName = ml_gen_local_var_name(VarSet, CallerArgVar),
ml_gen_var(!.Info, CallerArgVar, CallerVarLval),
ml_variable_type(!.Info, CallerArgVar, CallerType),
ForClosureWrapper = no
;
CallerArg = arg_for_closure_wrapper(CallerMLDSVarName,
CallerVarLval, CallerType),
ForClosureWrapper = yes
),
(
CalleeArgTopFunctorMode = top_unused
% Also exclude those with arg_mode `top_unused'.
;
CalleeArgTopFunctorMode = top_in,
% It is an input argument.
CallerIsDummy = is_type_a_dummy(ModuleInfo, CallerType),
(
CallerIsDummy = is_dummy_type,
% The variable may not have been declared, so we need to
% generate a dummy value for it. Using `0' here is more
% efficient than using private_builtin.dummy_var, which is
% what ml_gen_var will have generated for this variable.
CallerVarRval = ml_const(mlconst_int(0))
;
CallerIsDummy = is_not_dummy_type,
CallerVarRval = ml_lval(CallerVarLval)
),
ml_gen_box_or_unbox_rval(ModuleInfo, CallerType, CalleeType,
bp_native_if_possible, CallerVarRval, ArgRval),
!:InputRvals = [ArgRval | !.InputRvals]
;
CalleeArgTopFunctorMode = top_out,
% It is an output argument.
(
WhatParams = input_and_output_params,
ml_gen_box_or_unbox_lval(CallerType, CalleeType,
bp_native_if_possible, CallerVarLval, CallerMLDSVarName,
Context, ForClosureWrapper, ArgNum, ArgLval,
ThisArgConvDecls, _ThisArgConvInput, ThisArgConvOutput,
!Info),
!:ConvOutputDefns = ThisArgConvDecls ++ !.ConvOutputDefns,
!:ConvOutputStmts = ThisArgConvOutput ++ !.ConvOutputStmts,
( if
(
CopyOutWhen = copy_out_only_last_arg,
CallerArgsTail = []
;
CopyOutWhen = copy_out_always
)
then
ml_gen_type(!.Info, CalleeType, OutputType),
!:OutputLvalsTypes =
[ArgLval - OutputType | !.OutputLvalsTypes]
else
% Otherwise use the traditional C style of passing
% the address where the output value should be put.
!:InputRvals = [ml_gen_mem_addr(ArgLval) | !.InputRvals]
)
;
WhatParams = input_params_only
% For tail calls, we ignore the output arguments.
% The callee's output arguments are known to be exactly
% the same as the caller's output arguments, and will be
% set by the non-recursive paths through the procedure body.
%
% The reason why our caller cannot just ignore the value of
% !:OutputLvals and !:OutputTypes, and why we need the
% WhatParams argument, is the addition of the address
% of ArgLval to !:InputRvals above.
)
)
).
% ml_gen_mem_addr(Lval) returns a value equal to &Lval. For the case
% where Lval = *Rval for some Rval, we optimize &*Rval to just Rval.
%
:- func ml_gen_mem_addr(mlds_lval) = mlds_rval.
ml_gen_mem_addr(Lval) =
(if Lval = ml_mem_ref(Rval, _) then Rval else ml_mem_addr(Lval)).
%---------------------------------------------------------------------------%
%
% Miscellaneous routines.
%
% Get the value of the appropriate --det-copy-out or --nondet-copy-out
% option, depending on the code model.
%
:- func get_copy_out_option(globals, code_model) = bool.
get_copy_out_option(Globals, CodeModel) = CopyOut :-
(
CodeModel = model_non,
globals.lookup_bool_option(Globals, nondet_copy_out, CopyOut)
;
( CodeModel = model_det
; CodeModel = model_semi
),
globals.lookup_bool_option(Globals, det_copy_out, CopyOut)
).
%---------------------------------------------------------------------------%
:- end_module ml_backend.ml_args_util.
%---------------------------------------------------------------------------%