mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 01:13:30 +00:00
compiler/ml_code_util.m:
Move the part of the ml_gen_box_or_unbox_rval predicate that handles
the bp_native_if_possible box policy (the box policy that almost all
of its callers statically specify) into a predicate of its own,
and export this predicate.
Change the moved code from a long if-then-else chain to a shorter
if-then-else chain with embedded switches, whose structure clarifies
the relationships between the special cases that the predicate handles.
compiler/ml_args_util.m:
compiler/ml_call_gen.m:
compiler/ml_unify_gen_construct.m:
compiler/ml_unify_gen_deconstruct.m:
Call the newly exported predicate when appropriate.
1785 lines
68 KiB
Mathematica
1785 lines
68 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1999-2012 The University of Melbourne.
|
|
% Copyright (C) 2013-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: ml_code_util.m.
|
|
% Main author: fjh.
|
|
%
|
|
% This module is part of the MLDS code generator; it contains utility
|
|
% predicates.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module ml_backend.ml_code_util.
|
|
:- interface.
|
|
|
|
:- import_module backend_libs.
|
|
:- import_module backend_libs.builtin_ops.
|
|
:- import_module hlds.
|
|
:- import_module hlds.code_model.
|
|
:- import_module hlds.hlds_data.
|
|
:- import_module hlds.hlds_goal.
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module hlds.hlds_rtti.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module ml_backend.ml_gen_info.
|
|
:- import_module ml_backend.ml_global_data.
|
|
:- import_module ml_backend.mlds.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.prog_data_foreign.
|
|
:- import_module parse_tree.var_table.
|
|
|
|
:- import_module assoc_list.
|
|
:- import_module bool.
|
|
:- import_module list.
|
|
:- import_module maybe.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Various utility routines used for MLDS code generation.
|
|
%
|
|
|
|
% Generate an MLDS assignment statement.
|
|
%
|
|
:- func ml_gen_assign(mlds_lval, mlds_rval, prog_context) = mlds_stmt.
|
|
|
|
% Generate a block statement, i.e. `{ <Decls>; <Stmts>; }'.
|
|
% But if the block consists only of a single statement with no
|
|
% declarations, then just return that statement.
|
|
%
|
|
:- func ml_gen_block(list(mlds_local_var_defn), list(mlds_function_defn),
|
|
list(mlds_stmt), prog_context) = mlds_stmt.
|
|
|
|
:- type gen_pred ==
|
|
pred(list(mlds_local_var_defn), list(mlds_function_defn), list(mlds_stmt),
|
|
ml_gen_info, ml_gen_info).
|
|
:- inst gen_pred == (pred(out, out, out, in, out) is det).
|
|
|
|
% Given closures to generate code for two conjuncts, generate code
|
|
% for their conjunction.
|
|
%
|
|
:- pred ml_combine_conj(code_model::in, prog_context::in,
|
|
gen_pred::in(gen_pred), gen_pred::in(gen_pred),
|
|
list(mlds_local_var_defn)::out, list(mlds_function_defn)::out,
|
|
list(mlds_stmt)::out, ml_gen_info::in, ml_gen_info::out) is det.
|
|
|
|
% Given a function label and the statement which will comprise
|
|
% the function body for that function, generate an mlds_function_defn
|
|
% which defines that function.
|
|
%
|
|
:- pred ml_gen_nondet_label_func(ml_gen_info::in, mlds_maybe_aux_func_id::in,
|
|
mlds_func_source::in, prog_context::in, mlds_stmt::in,
|
|
mlds_function_defn::out) is det.
|
|
|
|
% Given a function label, the function parameters, and the statement
|
|
% which will comprise the function body for that function,
|
|
% generate an mlds_function_defn which defines that function.
|
|
%
|
|
:- pred ml_gen_label_func(ml_gen_info::in, mlds_maybe_aux_func_id::in,
|
|
mlds_func_source::in, mlds_func_params::in, prog_context::in,
|
|
mlds_stmt::in, mlds_function_defn::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Routines for generating expressions.
|
|
%
|
|
|
|
:- func ml_int_tag_to_rval_const(int_tag, mer_type, mlds_type) = mlds_rval.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Routines for generating types.
|
|
%
|
|
|
|
:- func var_table_entry_to_mlds_type(module_info, var_table_entry) = mlds_type.
|
|
|
|
% Convert a Mercury type to an MLDS type.
|
|
%
|
|
:- pred ml_gen_mlds_type(ml_gen_info::in, mer_type::in, mlds_type::out) is det.
|
|
|
|
% Convert the element type for an array_index operator to an MLDS type.
|
|
%
|
|
:- func ml_gen_array_elem_type(array_elem_type) = mlds_type.
|
|
|
|
% Allocate one or several fresh type variables, with kind `star',
|
|
% to use as the Mercury types of boxed objects (e.g. to get the
|
|
% argument types for tuple constructors or closure constructors).
|
|
% Note that this should only be used in cases where the tvarset
|
|
% doesn't matter.
|
|
%
|
|
:- func ml_make_boxed_type = mer_type.
|
|
:- func ml_make_boxed_types(arity) = list(mer_type).
|
|
|
|
% Return the interface id corresponding to the
|
|
% `jmercury.runtime.MercuryType' interface.
|
|
%
|
|
:- func ml_java_mercury_type_interface = mlds_interface_id.
|
|
|
|
% Return the class id corresponding to the
|
|
% `jmercury.runtime.MercuryEnum' class.
|
|
%
|
|
:- func ml_java_mercury_enum_class = mlds_class_id.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Routines for generating labels and entity names.
|
|
%
|
|
|
|
% Generate the mlds_function_name and module name for the entry point
|
|
% function corresponding to a given procedure.
|
|
%
|
|
:- pred ml_gen_proc_label(module_info::in, pred_proc_id::in,
|
|
mlds_module_name::out, mlds_plain_func_name::out) is det.
|
|
|
|
% Generate an mlds_function_name for a continuation function with the
|
|
% given sequence number. The pred_id and proc_id specify the procedure
|
|
% that this continuation function is part of.
|
|
%
|
|
:- func ml_gen_nondet_label(module_info, pred_proc_id,
|
|
mlds_maybe_aux_func_id) = mlds_plain_func_name.
|
|
|
|
% Allocate a new function label and return an rval containing the
|
|
% function's address. If parameters are not given, we assume it is
|
|
% a continuation function, and give it the appropriate arguments
|
|
% (depending on whether we are doing nested functions or not).
|
|
%
|
|
:- pred ml_gen_new_func_label(maybe(mlds_func_params)::in,
|
|
mlds_maybe_aux_func_id::out, mlds_rval::out,
|
|
ml_gen_info::in, ml_gen_info::out) is det.
|
|
|
|
% Generate the mlds_pred_label and module name for a given procedure.
|
|
%
|
|
:- pred ml_gen_pred_label(module_info::in, pred_proc_id::in,
|
|
mlds_pred_label::out, mlds_module_name::out) is det.
|
|
|
|
:- pred ml_gen_pred_label_from_rtti(module_info::in, rtti_proc_label::in,
|
|
mlds_pred_label::out, mlds_module_name::out) is det.
|
|
|
|
% Allocate a new label name, for use in label statements.
|
|
%
|
|
:- pred ml_gen_new_label(mlds_label::out,
|
|
ml_gen_info::in, ml_gen_info::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Routines for dealing with variables.
|
|
%
|
|
|
|
% Generate a list of the mlds_lvals corresponding to a given list
|
|
% of prog_vars.
|
|
%
|
|
:- pred ml_gen_var_direct_list(ml_gen_info::in, list(prog_var)::in,
|
|
list(mlds_lval)::out) is det.
|
|
|
|
% Generate the mlds_lval corresponding to a given prog_var.
|
|
%
|
|
:- pred ml_gen_var_direct(ml_gen_info::in, prog_var::in,
|
|
mlds_lval::out) is det.
|
|
:- pred ml_gen_var(ml_gen_info::in, prog_var::in, var_table_entry::in,
|
|
mlds_lval::out) is det.
|
|
|
|
% Generate the mlds_lval corresponding to a given prog_var,
|
|
% with a given type.
|
|
%
|
|
:- pred ml_gen_var_with_type(ml_gen_info::in, prog_var::in, mer_type::in,
|
|
mlds_lval::out) is det.
|
|
|
|
% Lookup the type of a variable.
|
|
%
|
|
:- pred ml_variable_type_direct(ml_gen_info::in, prog_var::in,
|
|
mer_type::out) is det.
|
|
|
|
% Generate the MLDS variable names for a list of variables.
|
|
%
|
|
:- func ml_gen_local_var_names(var_table::in, list(prog_var)::in)
|
|
= (list(mlds_local_var_name)::out(list_skel(lvn_prog_var))) is det.
|
|
|
|
% Generate the MLDS variable name for a variable.
|
|
%
|
|
:- func ml_gen_local_var_name(prog_var::in, var_table_entry::in)
|
|
= (mlds_local_var_name::out(lvn_prog_var)) is det.
|
|
|
|
% Generate a declaration for an MLDS variable, given its HLDS type.
|
|
%
|
|
:- pred ml_gen_local_var_decl(mlds_local_var_name::in, mer_type::in,
|
|
prog_context::in, mlds_local_var_defn::out,
|
|
ml_gen_info::in, ml_gen_info::out) is det.
|
|
|
|
% Generate a declaration for an MLDS variable, given its MLDS type
|
|
% and the code to trace it for accurate GC (if needed).
|
|
%
|
|
:- func ml_gen_mlds_var_decl(mlds_local_var_name, mlds_type,
|
|
mlds_gc_statement, prog_context) = mlds_local_var_defn.
|
|
|
|
% Generate a declaration for an MLDS variable, given its MLDS type
|
|
% and initializer, and given the code to trace it for accurate GC
|
|
% (if needed).
|
|
%
|
|
:- func ml_gen_mlds_var_decl_init(mlds_local_var_name, mlds_type,
|
|
mlds_initializer, mlds_gc_statement, prog_context) = mlds_local_var_defn.
|
|
|
|
% Return the declaration flags appropriate for a public field
|
|
% in the derived constructor class of a discriminated union.
|
|
%
|
|
:- func ml_gen_public_field_decl_flags = mlds_field_var_decl_flags.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Routines for dealing with fields.
|
|
%
|
|
% ml_gen_hld_field_name(MaybeFieldName, MaybeBaseCtorArg, ArgNum) =
|
|
% FieldName:
|
|
%
|
|
% Generate an MLDS field name for the target language type that represents
|
|
% the function symbol's cell when we are generating code with
|
|
% --high-level-data.
|
|
%
|
|
% MaybeFieldName is the user-specified field name (if any).
|
|
% MaybeBaseCtorArg says whether this is a field in a subtype, and if so,
|
|
% the field name (if any) of the corresponding constructor argument in the
|
|
% base type.
|
|
% ArgNum is the argument number (starting from one).
|
|
%
|
|
:- func ml_gen_hld_field_name(maybe(ctor_field_name), maybe_base_ctor_arg, int)
|
|
= mlds_field_var_name.
|
|
|
|
% Succeed iff the specified type must be boxed when used as a field.
|
|
% XXX Currently we box such types even for the other MLDS based back-ends
|
|
% that don't need it, e.g. the .NET back-end.
|
|
%
|
|
:- pred ml_must_box_field_type(module_info::in, mer_type::in, arg_width::in)
|
|
is semidet.
|
|
|
|
:- pred ml_gen_box_const_rval(module_info::in, prog_context::in,
|
|
mlds_type::in, arg_width::in, mlds_rval::in, mlds_rval::out,
|
|
ml_global_data::in, ml_global_data::out) is det.
|
|
|
|
% Given a source type and a destination type, and given an source rval
|
|
% holding a value of the source type, produce an rval that converts
|
|
% the source rval to the destination type, by boxing or unboxing it,
|
|
% possibly with an additional cast.
|
|
%
|
|
% The second version assumes that the box_policy is bp_native_if_possible.
|
|
% (Only one caller calls the general version; all the others call
|
|
% the second version.)
|
|
%
|
|
:- pred ml_gen_box_or_unbox_rval(module_info::in, mer_type::in, mer_type::in,
|
|
box_policy::in, mlds_rval::in, mlds_rval::out) is det.
|
|
:- pred ml_gen_box_or_unbox_rval_native(module_info::in,
|
|
mer_type::in, mer_type::in, mlds_rval::in, mlds_rval::out) is det.
|
|
|
|
% ml_gen_box_or_unbox_lval(CallerType, CalleeType, VarLval, VarName,
|
|
% Context, ForClosureWrapper, ArgNum,
|
|
% ArgLval, ConvDecls, ConvInputStmts, ConvOutputStmts):
|
|
%
|
|
% This is like `ml_gen_box_or_unbox_rval', except that it works on lvals
|
|
% rather than rvals. Given a source type and a destination type,
|
|
% a source lval holding a value of the source type, and a name to base
|
|
% the name of the local temporary variable on, this procedure produces
|
|
% an lval of the destination type, the declaration for the local temporary
|
|
% used (if any), code to assign from the source lval (suitable converted)
|
|
% to the destination lval, and code to assign from the destination lval
|
|
% (suitable converted) to the source lval.
|
|
%
|
|
% If ForClosureWrapper = yes, then the type_info for type variables
|
|
% in CallerType may not be available in the current procedure, so the GC
|
|
% tracing code for the ConvDecls (if any) should obtain the type_info
|
|
% from the ArgNum-th entry in the `type_params' local.
|
|
% (If ForClosureWrapper = no, then ArgNum is unused.)
|
|
%
|
|
:- pred ml_gen_box_or_unbox_lval(mer_type::in, mer_type::in, box_policy::in,
|
|
mlds_lval::in, mlds_local_var_name::in, prog_context::in, bool::in,
|
|
int::in, mlds_lval::out, list(mlds_local_var_defn)::out,
|
|
list(mlds_stmt)::out, list(mlds_stmt)::out,
|
|
ml_gen_info::in, ml_gen_info::out) is det.
|
|
|
|
% ml_gen_local_for_output_arg(VarName, Type, ArgNum, Context,
|
|
% LocalVarDefn):
|
|
%
|
|
% Generate a declaration for a local variable with the specified
|
|
% VarName and Type. However, don't use the normal GC tracing code;
|
|
% instead, generate GC tracing code that gets the typeinfo from
|
|
% the ArgNum-th entry in `type_params'.
|
|
%
|
|
:- pred ml_gen_local_for_output_arg(mlds_local_var_name::in, mer_type::in,
|
|
int::in, prog_context::in, mlds_local_var_defn::out,
|
|
ml_gen_info::in, ml_gen_info::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Routines for handling success and failure.
|
|
%
|
|
|
|
% Generate code to succeed in the given code_model.
|
|
%
|
|
:- pred ml_gen_success(code_model::in, prog_context::in, list(mlds_stmt)::out,
|
|
ml_gen_info::in, ml_gen_info::out) is det.
|
|
|
|
% Generate code to fail in the given code_model.
|
|
%
|
|
:- pred ml_gen_failure(code_model::in, prog_context::in, list(mlds_stmt)::out,
|
|
ml_gen_info::in, ml_gen_info::out) is det.
|
|
|
|
% Generate the declaration for the built-in `succeeded' flag.
|
|
% (`succeeded' is a boolean variable used to record
|
|
% the success or failure of model_semi procedures.)
|
|
%
|
|
:- func ml_gen_succeeded_var_decl(prog_context) = mlds_local_var_defn.
|
|
|
|
% Return the lval for the `succeeded' flag.
|
|
% (`succeeded' is a boolean variable used to record
|
|
% the success or failure of model_semi procedures.)
|
|
%
|
|
:- pred ml_success_lval(mlds_lval::out,
|
|
ml_gen_info::in, ml_gen_info::out) is det.
|
|
|
|
% Return an rval which will test the value of the `succeeded' flag.
|
|
% (`succeeded' is a boolean variable used to record
|
|
% the success or failure of model_semi procedures.)
|
|
%
|
|
:- pred ml_gen_test_success(mlds_rval::out,
|
|
ml_gen_info::in, ml_gen_info::out) is det.
|
|
|
|
% Generate code to set the `succeeded' flag to the specified truth value.
|
|
%
|
|
:- pred ml_gen_set_success(mlds_rval::in, prog_context::in, mlds_stmt::out,
|
|
ml_gen_info::in, ml_gen_info::out) is det.
|
|
|
|
% Generate the declaration for the specified `cond' variable.
|
|
% (`cond' variables are boolean variables used to record
|
|
% the success or failure of model_non conditions of if-then-elses.)
|
|
%
|
|
:- func ml_gen_cond_var_decl(cond_seq, prog_context) = mlds_local_var_defn.
|
|
|
|
% Return the lval for the specified `cond' flag.
|
|
% (`cond' variables are boolean variables used to record
|
|
% the success or failure of model_non conditions of if-then-elses.)
|
|
%
|
|
:- pred ml_cond_var_lval(cond_seq::in, mlds_lval::out) is det.
|
|
|
|
% Return an rval which will test the value of the specified `cond'
|
|
% variable. (`cond' variables are boolean variables used to record
|
|
% the success or failure of model_non conditions of if-then-elses.)
|
|
%
|
|
:- pred ml_gen_test_cond_var(cond_seq::in, mlds_rval::out) is det.
|
|
|
|
% Generate code to set the specified `cond' variable to the
|
|
% specified truth value.
|
|
%
|
|
:- pred ml_gen_set_cond_var(cond_seq::in, mlds_rval::in, prog_context::in,
|
|
mlds_stmt::out) is det.
|
|
|
|
% Return the success continuation that was passed as the current function's
|
|
% argument(s). The success continuation consists of two parts, the `cont'
|
|
% argument, and the `cont_env' argument. The `cont' argument is a
|
|
% continuation function that will be called when a model_non goal succeeds.
|
|
% The `cont_env' argument is a pointer to the environment (set of local
|
|
% variables in the containing procedure) for the continuation function.
|
|
% (If we are using gcc nested function, the `cont_env' is not used.)
|
|
% The output variable lvals and types need to be supplied when generating
|
|
% a continuation using --nondet-copy-out, otherwise they should be empty.
|
|
%
|
|
:- pred ml_initial_cont(ml_gen_info::in, assoc_list(mlds_lval, mer_type)::in,
|
|
success_cont::out) is det.
|
|
|
|
% Generate code to call the current success continuation.
|
|
% This is used for generating success when in a model_non context.
|
|
%
|
|
:- pred ml_gen_call_current_success_cont(ml_gen_info::in, prog_context::in,
|
|
mlds_stmt::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Routines for dealing with the environment pointer used for nested functions.
|
|
%
|
|
|
|
% Return an rval for a pointer to the current environment (the set of local
|
|
% variables in the containing procedure). Note that we generate this
|
|
% as a dangling reference. The ml_elim_nested pass will insert the
|
|
% declaration of the env_ptr variable. At this point, the type of these
|
|
% rvals is `mlds_unknown_type'.
|
|
%
|
|
:- pred ml_get_env_ptr(mlds_rval::out) is det.
|
|
|
|
% Return an mlds_argument for a pointer to the current environment
|
|
% (the set of local variables in the containing procedure).
|
|
%
|
|
:- pred ml_declare_env_ptr_arg(mlds_argument::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Magic numbers relating to the representation of
|
|
% typeclass_infos, base_typeclass_infos, and closures.
|
|
%
|
|
|
|
% This function returns the offset to add to the argument number
|
|
% of a closure arg to get its field number.
|
|
%
|
|
:- func ml_closure_arg_offset = int.
|
|
|
|
% This function returns the offset to add to the argument number
|
|
% of a typeclass_info arg to get its field number.
|
|
%
|
|
:- func ml_typeclass_info_arg_offset = int.
|
|
|
|
% This function returns the offset to add to the method number for a type
|
|
% class method to get its field number within the base_typeclass_info.
|
|
%
|
|
:- func ml_base_typeclass_info_method_offset = int.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Routines for dealing with lookup tables.
|
|
%
|
|
|
|
:- pred ml_generate_constants_for_arms(list(prog_var)::in, list(hlds_goal)::in,
|
|
list(list(mlds_rval))::out, ml_gen_info::in, ml_gen_info::out) is semidet.
|
|
|
|
:- pred ml_generate_constants_for_arm(list(prog_var)::in, hlds_goal::in,
|
|
list(mlds_rval)::out, ml_gen_info::in, ml_gen_info::out) is semidet.
|
|
|
|
:- pred ml_generate_field_assign(mlds_lval::in, mlds_type::in,
|
|
mlds_field_id::in, mlds_vector_common::in, mlds_type::in,
|
|
mlds_rval::in, prog_context::in, mlds_stmt::out) is det.
|
|
|
|
:- pred ml_generate_field_assigns(list(prog_var)::in, list(mlds_type)::in,
|
|
list(mlds_field_id)::in, mlds_vector_common::in, mlds_type::in,
|
|
mlds_rval::in, prog_context::in, list(mlds_stmt)::out,
|
|
ml_gen_info::in, ml_gen_info::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Miscellaneous routines.
|
|
%
|
|
|
|
% Add the qualifier `builtin' to any unqualified name.
|
|
% Although the builtin types `int', `float', etc. are treated as part
|
|
% of the `builtin' module, for historical reasons they don't have
|
|
% any qualifiers in the HLDS, so we need to add the `builtin'
|
|
% qualifier before converting such names to MLDS.
|
|
%
|
|
:- func fixup_builtin_module(module_name) = module_name.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module hlds.pred_name.
|
|
:- import_module hlds.type_util.
|
|
:- import_module libs.
|
|
:- import_module libs.globals.
|
|
:- import_module libs.options.
|
|
:- import_module mdbcomp.builtin_modules.
|
|
:- import_module mdbcomp.prim_data.
|
|
:- import_module ml_backend.ml_accurate_gc.
|
|
:- import_module ml_backend.ml_code_gen.
|
|
:- import_module parse_tree.builtin_lib_types.
|
|
:- import_module parse_tree.java_names.
|
|
:- import_module parse_tree.prog_type.
|
|
:- import_module parse_tree.prog_type_test.
|
|
:- import_module parse_tree.prog_type_unify.
|
|
:- import_module parse_tree.set_of_var.
|
|
|
|
:- import_module map.
|
|
:- import_module pair.
|
|
:- import_module require.
|
|
:- import_module set.
|
|
:- import_module string.
|
|
:- import_module term.
|
|
:- import_module varset.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code for various utility routines.
|
|
%
|
|
|
|
ml_gen_assign(Lval, Rval, Context) = Stmt :-
|
|
Assign = assign(Lval, Rval),
|
|
Stmt = ml_stmt_atomic(Assign, Context).
|
|
|
|
ml_gen_block(LocalVarDefns, FuncDefns, Stmts, Context) = Block :-
|
|
( if
|
|
LocalVarDefns = [],
|
|
FuncDefns = [],
|
|
Stmts = [SingleStmt]
|
|
then
|
|
Block = SingleStmt
|
|
else
|
|
Block = ml_stmt_block(LocalVarDefns, FuncDefns, Stmts, Context)
|
|
).
|
|
|
|
ml_combine_conj(FirstCodeModel, Context, DoGenFirst, DoGenRest,
|
|
LocalVarDefns, FuncDefns, Stmts, !Info) :-
|
|
(
|
|
% model_det goal:
|
|
% <First, Rest>
|
|
% ===>
|
|
% <do First>
|
|
% <Rest>
|
|
%
|
|
FirstCodeModel = model_det,
|
|
DoGenFirst(FirstLocalVarDefns, FirstFuncDefns, FirstStmts, !Info),
|
|
DoGenRest(RestLocalVarDefns, RestFuncDefns, RestStmts, !Info),
|
|
LocalVarDefns = FirstLocalVarDefns ++ RestLocalVarDefns,
|
|
FuncDefns = FirstFuncDefns ++ RestFuncDefns,
|
|
Stmts = FirstStmts ++ RestStmts
|
|
;
|
|
% model_semi goal:
|
|
% <Goal, Goals>
|
|
% ===>
|
|
% MR_bool succeeded;
|
|
%
|
|
% <succeeded = Goal>;
|
|
% if (succeeded) {
|
|
% <Goals>;
|
|
% }
|
|
% except that we hoist any declarations generated for <Goals>
|
|
% to the outer scope, rather than inside the `if', so that they remain
|
|
% in scope for any later goals which follow this (this is needed for
|
|
% declarations of static consts).
|
|
% XXX We haven't put static consts into blocks for a long time;
|
|
% they are now in the global data field in !Info.
|
|
|
|
FirstCodeModel = model_semi,
|
|
DoGenFirst(FirstLocalVarDefns, FirstFuncDefns, FirstStmts, !Info),
|
|
ml_gen_test_success(Succeeded, !Info),
|
|
DoGenRest(RestLocalVarDefns, RestFuncDefns, RestStmts, !Info),
|
|
ThenStmt = ml_gen_block([], [], RestStmts, Context),
|
|
ITEStmt = ml_stmt_if_then_else(Succeeded, ThenStmt, no, Context),
|
|
LocalVarDefns = FirstLocalVarDefns ++ RestLocalVarDefns,
|
|
FuncDefns = FirstFuncDefns ++ RestFuncDefns,
|
|
Stmts = FirstStmts ++ [ITEStmt]
|
|
;
|
|
% model_non goal:
|
|
% <First, Rest>
|
|
% ===>
|
|
% succ_func() {
|
|
% <Rest && SUCCEED()>;
|
|
% }
|
|
%
|
|
% <First && succ_func()>;
|
|
%
|
|
% except that we hoist any declarations generated for <First>
|
|
% to the top of the scope, rather than inside or after the
|
|
% succ_func(), so that they remain in scope for any code
|
|
% following them.
|
|
%
|
|
% XXX The pattern above leads to deep nesting for long conjunctions;
|
|
% we should avoid that.
|
|
%
|
|
|
|
FirstCodeModel = model_non,
|
|
|
|
% Allocate a name for the `succ_func'.
|
|
ml_gen_new_func_label(no, RestFuncLabel, RestFuncLabelRval, !Info),
|
|
|
|
% Generate <First && succ_func()>.
|
|
ml_get_env_ptr(EnvPtrRval),
|
|
SuccessCont = success_cont(RestFuncLabelRval, EnvPtrRval, []),
|
|
ml_gen_info_push_success_cont(SuccessCont, !Info),
|
|
DoGenFirst(FirstLocalVarDefns, FirstFuncDefns, FirstStmts, !Info),
|
|
ml_gen_info_pop_success_cont(!Info),
|
|
|
|
% Generate the `succ_func'.
|
|
% Do not take any information about packed args into the new function
|
|
% depth, since that may cause dangling cross-function references
|
|
% when the new function depth is flattened out.
|
|
ml_gen_info_set_packed_word_map(map.init, !Info),
|
|
ml_gen_info_increment_func_nest_depth(!Info),
|
|
DoGenRest(RestLocalVarDefns, RestFuncDefns, RestStmts, !Info),
|
|
ml_gen_info_decrement_func_nest_depth(!Info),
|
|
% Do not take any information about packed args out of the new function
|
|
% depth, for the same reason.
|
|
ml_gen_info_set_packed_word_map(map.init, !Info),
|
|
|
|
RestStmt = ml_gen_block(RestLocalVarDefns, RestFuncDefns, RestStmts,
|
|
Context),
|
|
ml_gen_nondet_label_func(!.Info, RestFuncLabel,
|
|
mlds_func_source_continuation, Context, RestStmt, RestFunc),
|
|
|
|
LocalVarDefns = FirstLocalVarDefns,
|
|
FuncDefns = FirstFuncDefns ++ [RestFunc],
|
|
Stmts = FirstStmts
|
|
).
|
|
|
|
ml_gen_nondet_label_func(Info, MaybeAux, Source, Context, Stmt, Func) :-
|
|
ml_declare_env_ptr_arg(EnvPtrArg),
|
|
FuncParams = mlds_func_params([EnvPtrArg], []),
|
|
ml_gen_label_func(Info, MaybeAux, Source, FuncParams, Context, Stmt, Func).
|
|
|
|
ml_gen_label_func(Info, MaybeAux, Source, FuncParams, Context, Stmt, Func) :-
|
|
% Compute the function name.
|
|
ml_gen_info_get_module_info(Info, ModuleInfo),
|
|
ml_gen_info_get_pred_proc_id(Info, PredProcId),
|
|
FuncName = ml_gen_nondet_label(ModuleInfo, PredProcId, MaybeAux),
|
|
|
|
% Compute the function definition.
|
|
DeclFlags = mlds_function_decl_flags(func_private, per_instance),
|
|
Body = body_defined_here(Stmt),
|
|
EnvVarNames = set.init,
|
|
Func = mlds_function_defn(mlds_function_name(FuncName), Context,
|
|
DeclFlags, Source, FuncParams, Body, EnvVarNames, no).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code for generating expressions.
|
|
%
|
|
|
|
ml_int_tag_to_rval_const(IntTag, MerType, MLDS_Type) = Rval :-
|
|
% Keep this code in sync with ml_generate_test_rval_is_int_tag
|
|
% in ml_unify_gen_test.m.
|
|
(
|
|
IntTag = int_tag_int(Int),
|
|
( if MerType = int_type then
|
|
Const = mlconst_int(Int)
|
|
else if MerType = char_type then
|
|
Const = mlconst_char(Int)
|
|
else
|
|
Const = mlconst_enum(Int, MLDS_Type)
|
|
)
|
|
;
|
|
IntTag = int_tag_uint(UInt),
|
|
Const = mlconst_uint(UInt)
|
|
;
|
|
IntTag = int_tag_int8(Int8),
|
|
Const = mlconst_int8(Int8)
|
|
;
|
|
IntTag = int_tag_uint8(UInt8),
|
|
Const = mlconst_uint8(UInt8)
|
|
;
|
|
IntTag = int_tag_int16(Int16),
|
|
Const = mlconst_int16(Int16)
|
|
;
|
|
IntTag = int_tag_uint16(UInt16),
|
|
Const = mlconst_uint16(UInt16)
|
|
;
|
|
IntTag = int_tag_int32(Int32),
|
|
Const = mlconst_int32(Int32)
|
|
;
|
|
IntTag = int_tag_uint32(UInt32),
|
|
Const = mlconst_uint32(UInt32)
|
|
;
|
|
IntTag = int_tag_int64(Int64),
|
|
Const = mlconst_int64(Int64)
|
|
;
|
|
IntTag = int_tag_uint64(UInt64),
|
|
Const = mlconst_uint64(UInt64)
|
|
),
|
|
Rval = ml_const(Const).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code for generating types.
|
|
%
|
|
|
|
var_table_entry_to_mlds_type(ModuleInfo, Entry) = MLDSType :-
|
|
MLDSType = mercury_type_to_mlds_type(ModuleInfo, Entry ^ vte_type).
|
|
|
|
ml_gen_mlds_type(Info, Type, MLDS_Type) :-
|
|
ml_gen_info_get_module_info(Info, ModuleInfo),
|
|
MLDS_Type = mercury_type_to_mlds_type(ModuleInfo, Type).
|
|
|
|
ml_gen_array_elem_type(ElemType) = MLDS_Type :-
|
|
(
|
|
ElemType = array_elem_scalar(ScalarElem),
|
|
MLDS_Type = ml_gen_scalar_array_elem_type(ScalarElem)
|
|
;
|
|
ElemType = array_elem_struct(_ScalarElems),
|
|
unexpected($pred, "struct")
|
|
).
|
|
|
|
:- func ml_gen_scalar_array_elem_type(scalar_array_elem_type) = mlds_type.
|
|
|
|
ml_gen_scalar_array_elem_type(scalar_elem_string) = mlds_builtin_type_string.
|
|
ml_gen_scalar_array_elem_type(scalar_elem_int) =
|
|
mlds_builtin_type_int(int_type_int).
|
|
ml_gen_scalar_array_elem_type(scalar_elem_generic) = mlds_generic_type.
|
|
|
|
ml_make_boxed_type = BoxedType :-
|
|
varset.init(TypeVarSet0),
|
|
varset.new_var(BoxedTypeVar, TypeVarSet0, _TypeVarSet),
|
|
prog_type.var_to_type(map.init, BoxedTypeVar, BoxedType).
|
|
|
|
ml_make_boxed_types(Arity) = BoxedTypes :-
|
|
varset.init(TypeVarSet0),
|
|
varset.new_vars(Arity, BoxedTypeVars, TypeVarSet0, _TypeVarSet),
|
|
prog_type.var_list_to_type_list(map.init, BoxedTypeVars, BoxedTypes).
|
|
|
|
ml_java_mercury_type_interface = TypeInterfaceDefn :-
|
|
InterfaceModuleName =
|
|
mercury_module_name_to_mlds(java_mercury_runtime_package_name),
|
|
TypeInterfaceDefn = mlds_interface_id(InterfaceModuleName, "MercuryType").
|
|
|
|
ml_java_mercury_enum_class = EnumClassId :-
|
|
InterfaceModuleName =
|
|
mercury_module_name_to_mlds(java_mercury_runtime_package_name),
|
|
EnumClass =
|
|
qual_class_name(InterfaceModuleName, module_qual, "MercuryEnum"),
|
|
EnumClassId = mlds_class_id(EnumClass, 0).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code for generating mlds_function_names.
|
|
%
|
|
|
|
ml_gen_proc_label(ModuleInfo, PredProcId, MLDS_ModuleName, MLDS_Name) :-
|
|
ml_gen_func_label(ModuleInfo, PredProcId, proc_func, MLDS_ModuleName,
|
|
MLDS_Name).
|
|
|
|
ml_gen_nondet_label(ModuleInfo, PredProcId, MaybeAux) = MLDS_Name :-
|
|
ml_gen_func_label(ModuleInfo, PredProcId, MaybeAux,
|
|
_MLDS_ModuleName, MLDS_Name).
|
|
|
|
:- pred ml_gen_func_label(module_info::in, pred_proc_id::in,
|
|
mlds_maybe_aux_func_id::in,
|
|
mlds_module_name::out, mlds_plain_func_name::out) is det.
|
|
|
|
ml_gen_func_label(ModuleInfo, PredProcId, MaybeAux, ModuleName, FuncName) :-
|
|
ml_gen_pred_label(ModuleInfo, PredProcId, PredLabel, ModuleName),
|
|
PredProcId = proc(PredId, ProcId),
|
|
ProcLabel = mlds_proc_label(PredLabel, ProcId),
|
|
FuncLabel = mlds_func_label(ProcLabel, MaybeAux),
|
|
FuncName = mlds_plain_func_name(FuncLabel, PredId).
|
|
|
|
ml_gen_new_func_label(MaybeParams, MaybeAux, FuncLabelRval, !Info) :-
|
|
ml_gen_info_new_aux_func_id(MaybeAux, !Info),
|
|
ml_gen_info_get_module_info(!.Info, ModuleInfo),
|
|
ml_gen_info_get_pred_proc_id(!.Info, PredProcId),
|
|
ml_gen_pred_label(ModuleInfo, PredProcId, PredLabel, PredModule),
|
|
(
|
|
MaybeParams = yes(Params),
|
|
Signature = mlds_get_func_signature(Params)
|
|
;
|
|
MaybeParams = no,
|
|
ArgTypes = [mlds_generic_env_ptr_type],
|
|
Signature = mlds_func_signature(ArgTypes, [])
|
|
),
|
|
PredProcId = proc(_PredId, ProcId),
|
|
ProcLabel = mlds_proc_label(PredLabel, ProcId),
|
|
FuncLabel = mlds_func_label(ProcLabel, MaybeAux),
|
|
QualFuncLabel = qual_func_label(PredModule, FuncLabel),
|
|
FuncLabelRval = ml_const(mlconst_code_addr(
|
|
mlds_code_addr(QualFuncLabel, Signature))).
|
|
|
|
ml_gen_pred_label(ModuleInfo, PredProcId, MLDS_PredLabel, MLDS_Module) :-
|
|
PredProcId = proc(PredId, ProcId),
|
|
RttiProcLabel = make_rtti_proc_label(ModuleInfo, PredId, ProcId),
|
|
ml_gen_pred_label_from_rtti(ModuleInfo, RttiProcLabel,
|
|
MLDS_PredLabel, MLDS_Module).
|
|
|
|
ml_gen_pred_label_from_rtti(_ModuleInfo, RttiProcLabel, MLDS_PredLabel,
|
|
MLDS_Module) :-
|
|
RttiProcLabel = rtti_proc_label(PredOrFunc, ThisModule, PredModule,
|
|
PredName, PredFormArity, _ArgTypes, _PredId, ProcId,
|
|
_HeadVarsWithNames, _TopFunctorModes, _Detism,
|
|
PredIsImported, _PredIsPseudoImported,
|
|
Origin, _ProcIsExported, _ProcIsImported),
|
|
( if Origin = origin_compiler(made_for_uci(SpecialPred, TypeCtor)) then
|
|
( if
|
|
% All type_ctors other than tuples here should be module qualified,
|
|
% since builtin types are handled separately in polymorphism.m.
|
|
TypeCtor = type_ctor(TypeCtorSymName, TypeArity),
|
|
(
|
|
TypeCtorSymName = unqualified(TypeName),
|
|
type_ctor_is_tuple(TypeCtor),
|
|
TypeModule = mercury_public_builtin_module
|
|
;
|
|
TypeCtorSymName = qualified(TypeModule, TypeName)
|
|
)
|
|
then
|
|
( if
|
|
ThisModule \= TypeModule,
|
|
SpecialPred = spec_pred_unify,
|
|
not hlds_pred.in_in_unification_proc_id(ProcId)
|
|
then
|
|
% This is a locally-defined instance of a unification procedure
|
|
% for a type defined in some other module.
|
|
DefiningModule = ThisModule,
|
|
MaybeDeclaringModule = yes(TypeModule)
|
|
else
|
|
% The module declaring the type is the same as the module
|
|
% defining this special pred.
|
|
DefiningModule = TypeModule,
|
|
MaybeDeclaringModule = no
|
|
),
|
|
MLDS_PredLabel = mlds_special_pred_label(PredName,
|
|
MaybeDeclaringModule, TypeName, TypeArity)
|
|
else
|
|
unexpected($pred,
|
|
"cannot make label for special pred `" ++ PredName ++ "'")
|
|
)
|
|
else
|
|
( if
|
|
% Work out which module supplies the code for the predicate.
|
|
ThisModule \= PredModule,
|
|
PredIsImported = no
|
|
then
|
|
% This predicate is a specialized version of a pred from a
|
|
% `.opt' file.
|
|
DefiningModule = ThisModule,
|
|
MaybeDeclaringModule = yes(PredModule)
|
|
else
|
|
% The predicate was declared in the same module that it is
|
|
% defined in
|
|
DefiningModule = PredModule,
|
|
MaybeDeclaringModule = no
|
|
),
|
|
MLDS_PredLabel = mlds_user_pred_label(PredOrFunc, MaybeDeclaringModule,
|
|
PredName, PredFormArity)
|
|
),
|
|
MLDS_Module = mercury_module_name_to_mlds(DefiningModule).
|
|
|
|
ml_gen_new_label(Label, !Info) :-
|
|
ml_gen_info_new_label(LabelNum, !Info),
|
|
Label = mlds_label("label_" ++ string.int_to_string(LabelNum)).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code for dealing with variables.
|
|
%
|
|
|
|
ml_gen_var_direct_list(_Info, [], []).
|
|
ml_gen_var_direct_list(Info, [Var | Vars], [Lval | Lvals]) :-
|
|
ml_gen_var_direct(Info, Var, Lval),
|
|
ml_gen_var_direct_list(Info, Vars, Lvals).
|
|
|
|
ml_gen_var_direct(Info, Var, Lval) :-
|
|
% First check the var_lvals override mapping; if an lval has been set
|
|
% for this variable, use it.
|
|
ml_gen_info_get_var_lvals(Info, VarLvals),
|
|
( if map.search(VarLvals, Var, VarLval) then
|
|
Lval = VarLval
|
|
else
|
|
% Otherwise just look up the variable's type and generate an lval
|
|
% for it using the ordinary algorithm.
|
|
ml_gen_info_get_var_table(Info, VarTable),
|
|
lookup_var_entry(VarTable, Var, Entry),
|
|
do_gen_var(Info, Var, Entry, Lval)
|
|
).
|
|
|
|
ml_gen_var(Info, Var, Entry, Lval) :-
|
|
% First check the var_lvals override mapping; if an lval has been set
|
|
% for this variable, use it.
|
|
ml_gen_info_get_var_lvals(Info, VarLvals),
|
|
( if map.search(VarLvals, Var, VarLval) then
|
|
Lval = VarLval
|
|
else
|
|
% Otherwise just look up the variable's type and generate an lval
|
|
% for it using the ordinary algorithm.
|
|
do_gen_var(Info, Var, Entry, Lval)
|
|
).
|
|
|
|
:- pred do_gen_var(ml_gen_info::in, prog_var::in, var_table_entry::in,
|
|
mlds_lval::out) is det.
|
|
|
|
do_gen_var(Info, Var, Entry, Lval) :-
|
|
Entry = vte(_, Type, IsDummy),
|
|
ml_gen_mlds_type(Info, Type, MLDS_Type),
|
|
(
|
|
IsDummy = is_dummy_type,
|
|
% The variable won't have been declared, so we need to generate
|
|
% a dummy lval for this variable.
|
|
Lval = ml_global_var(global_dummy_var, MLDS_Type)
|
|
;
|
|
IsDummy = is_not_dummy_type,
|
|
VarName = ml_gen_local_var_name(Var, Entry),
|
|
VarLval = ml_local_var(VarName, MLDS_Type),
|
|
% Output variables may be passed by reference...
|
|
ml_gen_info_get_byref_output_vars(Info, ByRefOutputVars),
|
|
( if set_of_var.member(ByRefOutputVars, Var) then
|
|
Lval = ml_mem_ref(ml_lval(VarLval), MLDS_Type)
|
|
else
|
|
Lval = VarLval
|
|
)
|
|
).
|
|
|
|
ml_gen_var_with_type(Info, Var, Type, Lval) :-
|
|
% NOTE The value of Type here may *differ* from the type recorded
|
|
% for Var in the var_table field of !.Info. Out of an abundance of caution,
|
|
% we recompute IsDummy for it as well.
|
|
ml_gen_info_get_module_info(Info, ModuleInfo),
|
|
IsDummy = is_type_a_dummy(ModuleInfo, Type),
|
|
ml_gen_mlds_type(Info, Type, MLDS_Type),
|
|
(
|
|
IsDummy = is_dummy_type,
|
|
% The variable won't have been declared, so we need to generate
|
|
% a dummy lval for this variable.
|
|
Lval = ml_global_var(global_dummy_var, MLDS_Type)
|
|
;
|
|
IsDummy = is_not_dummy_type,
|
|
% The name part of the var table entry for var does not depend
|
|
% on which form of the var's type we are after.
|
|
ml_gen_info_get_var_table(Info, VarTable),
|
|
lookup_var_entry(VarTable, Var, Entry),
|
|
VarName = ml_gen_local_var_name(Var, Entry),
|
|
VarLval = ml_local_var(VarName, MLDS_Type),
|
|
|
|
% Output variables may be passed by reference...
|
|
ml_gen_info_get_byref_output_vars(Info, ByRefOutputVars),
|
|
( if set_of_var.member(ByRefOutputVars, Var) then
|
|
Lval = ml_mem_ref(ml_lval(VarLval), MLDS_Type)
|
|
else
|
|
Lval = VarLval
|
|
)
|
|
).
|
|
|
|
ml_variable_type_direct(Info, Var, Type) :-
|
|
ml_gen_info_get_var_table(Info, VarTable),
|
|
lookup_var_entry(VarTable, Var, Entry),
|
|
Type = Entry ^ vte_type.
|
|
|
|
ml_gen_local_var_names(_, []) = [].
|
|
ml_gen_local_var_names(VarTable, [Var | Vars])
|
|
= [MLDSVarName | MLDSVarNames] :-
|
|
lookup_var_entry(VarTable, Var, VarEntry),
|
|
MLDSVarName = ml_gen_local_var_name(Var, VarEntry),
|
|
MLDSVarNames = ml_gen_local_var_names(VarTable, Vars).
|
|
|
|
ml_gen_local_var_name(Var, Entry) = MLDSVarName :-
|
|
VarName = Entry ^ vte_name,
|
|
term.var_to_int(Var, VarNumber),
|
|
MLDSVarName = lvn_prog_var(VarName, VarNumber).
|
|
|
|
ml_gen_local_var_decl(VarName, Type, Context, Defn, !Info) :-
|
|
ml_gen_info_get_module_info(!.Info, ModuleInfo),
|
|
ml_gen_gc_statement(VarName, Type, Context, GCStmt, !Info),
|
|
Defn = ml_gen_mlds_var_decl(VarName,
|
|
mercury_type_to_mlds_type(ModuleInfo, Type), GCStmt, Context).
|
|
|
|
ml_gen_mlds_var_decl(DataName, MLDS_Type, GCStmt, Context) =
|
|
ml_gen_mlds_var_decl_init(DataName, MLDS_Type, no_initializer, GCStmt,
|
|
Context).
|
|
|
|
ml_gen_mlds_var_decl_init(DataName, MLDS_Type, Initializer, GCStmt, Context) =
|
|
mlds_local_var_defn(DataName, Context, MLDS_Type, Initializer, GCStmt).
|
|
|
|
ml_gen_public_field_decl_flags =
|
|
mlds_field_var_decl_flags(per_instance, modifiable).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code for dealing with fields.
|
|
%
|
|
|
|
ml_gen_hld_field_name(MaybeFieldName, MaybeBaseCtorArg, ArgNum) =
|
|
FieldVarName :-
|
|
% Subtypes share the data representation with their base types.
|
|
% If this is the field of a subtype, we must translate the reference to the
|
|
% corresponding constructor arg in the base type (which may or may not
|
|
% have a field name).
|
|
(
|
|
MaybeBaseCtorArg = no_base_ctor_arg,
|
|
FieldNameToUse = MaybeFieldName
|
|
;
|
|
MaybeBaseCtorArg = base_ctor_arg(MaybeBaseFieldName),
|
|
FieldNameToUse = MaybeBaseFieldName
|
|
),
|
|
% Use the field name if we have one, otherwise we just use `F' followed by
|
|
% the field number.
|
|
(
|
|
FieldNameToUse = yes(ctor_field_name(QualifiedFieldName,
|
|
_FieldNameCtxt)),
|
|
FieldName = unqualify_name(QualifiedFieldName)
|
|
;
|
|
FieldNameToUse = no,
|
|
FieldName = "F" ++ string.int_to_string(ArgNum)
|
|
),
|
|
FieldVarName = fvn_du_ctor_field_hld(FieldName).
|
|
|
|
ml_must_box_field_type(ModuleInfo, Type, Width) :-
|
|
module_info_get_globals(ModuleInfo, Globals),
|
|
globals.get_target(Globals, Target),
|
|
(
|
|
( Target = target_c
|
|
; Target = target_csharp
|
|
),
|
|
classify_type(ModuleInfo, Type) = Category,
|
|
globals.lookup_bool_option(Globals, unboxed_float, UnboxedFloat),
|
|
globals.lookup_bool_option(Globals, unboxed_int64s, UnboxedInt64s),
|
|
MustBox = ml_must_box_field_type_category(Category, UnboxedFloat,
|
|
UnboxedInt64s, Width)
|
|
;
|
|
Target = target_java,
|
|
MustBox = no
|
|
),
|
|
MustBox = yes.
|
|
|
|
:- func ml_must_box_field_type_category(type_ctor_category, bool, bool,
|
|
arg_width) = bool.
|
|
|
|
ml_must_box_field_type_category(CtorCat, UnboxedFloat, UnboxedInt64s, Width)
|
|
= MustBox :-
|
|
(
|
|
CtorCat = ctor_cat_builtin(cat_builtin_int(IntType)),
|
|
(
|
|
( IntType = int_type_int
|
|
; IntType = int_type_uint
|
|
; IntType = int_type_int8
|
|
; IntType = int_type_uint8
|
|
; IntType = int_type_int16
|
|
; IntType = int_type_uint16
|
|
; IntType = int_type_int32
|
|
; IntType = int_type_uint32
|
|
),
|
|
MustBox = no
|
|
;
|
|
( IntType = int_type_int64
|
|
; IntType = int_type_uint64
|
|
),
|
|
(
|
|
UnboxedInt64s = yes,
|
|
MustBox = no
|
|
;
|
|
UnboxedInt64s = no,
|
|
(
|
|
Width = aw_full_word,
|
|
MustBox = yes
|
|
;
|
|
Width = aw_double_word,
|
|
unexpected($pred, "double word for 64-bit integer")
|
|
;
|
|
Width = aw_partial_word,
|
|
unexpected($pred, "partial word for 64-bit integer")
|
|
;
|
|
Width = aw_none,
|
|
unexpected($pred, "none for 64-bit integer")
|
|
)
|
|
)
|
|
)
|
|
;
|
|
( CtorCat = ctor_cat_builtin(cat_builtin_string)
|
|
; CtorCat = ctor_cat_builtin_dummy
|
|
; CtorCat = ctor_cat_higher_order
|
|
; CtorCat = ctor_cat_tuple
|
|
; CtorCat = ctor_cat_enum(_)
|
|
; CtorCat = ctor_cat_system(_)
|
|
; CtorCat = ctor_cat_variable
|
|
; CtorCat = ctor_cat_void
|
|
; CtorCat = ctor_cat_user(_)
|
|
),
|
|
MustBox = no
|
|
;
|
|
CtorCat = ctor_cat_builtin(cat_builtin_char),
|
|
MustBox = yes
|
|
;
|
|
CtorCat = ctor_cat_builtin(cat_builtin_float),
|
|
(
|
|
UnboxedFloat = yes,
|
|
MustBox = no
|
|
;
|
|
UnboxedFloat = no,
|
|
(
|
|
Width = aw_full_word,
|
|
MustBox = yes
|
|
;
|
|
Width = aw_double_word,
|
|
MustBox = no
|
|
;
|
|
Width = aw_partial_word,
|
|
unexpected($pred, "partial word for float")
|
|
;
|
|
Width = aw_none,
|
|
unexpected($pred, "none for float")
|
|
)
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
ml_gen_box_const_rval(ModuleInfo, Context, MLDS_Type, Width, Rval, BoxedRval,
|
|
!GlobalData) :-
|
|
( if
|
|
( MLDS_Type = mercury_nb_type(type_variable(_, _), _)
|
|
; MLDS_Type = mlds_generic_type
|
|
)
|
|
then
|
|
BoxedRval = Rval
|
|
else if
|
|
% For the MLDS->C back-end, we need to handle constant floats,
|
|
% int64s and uint64s specially. Boxed floats, int64s and uint64s
|
|
% normally get heap allocated, whereas for other types boxing
|
|
% is just a cast (casts are OK in static initializers, but calls
|
|
% to malloc() are not).
|
|
(
|
|
MLDS_Type = mlds_builtin_type_float,
|
|
ConstVarKind = mgcv_float
|
|
;
|
|
MLDS_Type = mlds_builtin_type_int(IntType),
|
|
( IntType = int_type_int64, ConstVarKind = mgcv_int64
|
|
; IntType = int_type_uint64, ConstVarKind = mgcv_uint64
|
|
)
|
|
),
|
|
ml_global_data_get_target(!.GlobalData, ml_target_c)
|
|
then
|
|
( if
|
|
(
|
|
ConstVarKind = mgcv_float,
|
|
ml_global_data_have_unboxed_floats(!.GlobalData,
|
|
do_not_have_unboxed_floats)
|
|
;
|
|
( ConstVarKind = mgcv_int64
|
|
; ConstVarKind = mgcv_uint64
|
|
),
|
|
ml_global_data_have_unboxed_int64s(!.GlobalData,
|
|
do_not_have_unboxed_int64s)
|
|
),
|
|
arg_width_is_double(Width, no)
|
|
then
|
|
% Generate a local static constant for this float, int64 or uint64.
|
|
module_info_get_name(ModuleInfo, ModuleName),
|
|
MLDS_ModuleName = mercury_module_name_to_mlds(ModuleName),
|
|
Initializer = init_obj(Rval),
|
|
ml_gen_static_scalar_const_addr(MLDS_ModuleName, ConstVarKind,
|
|
MLDS_Type, Initializer, Context, ConstAddrRval, !GlobalData),
|
|
|
|
% Return as the boxed rval the address of that constant,
|
|
% cast to mlds_generic_type.
|
|
BoxedRval = ml_cast(mlds_generic_type, ConstAddrRval)
|
|
else
|
|
% This is not a real box, but a cast. The "box" is required as it
|
|
% may be further cast to pointer types.
|
|
BoxedRval = ml_box(MLDS_Type, Rval)
|
|
)
|
|
else
|
|
BoxedRval = ml_box(MLDS_Type, Rval)
|
|
).
|
|
|
|
:- pred arg_width_is_double(arg_width::in, bool::out) is det.
|
|
|
|
arg_width_is_double(ArgWidth, DoubleWidth) :-
|
|
(
|
|
ArgWidth = aw_double_word,
|
|
DoubleWidth = yes
|
|
;
|
|
( ArgWidth = aw_full_word
|
|
; ArgWidth = aw_partial_word
|
|
; ArgWidth = aw_none
|
|
),
|
|
DoubleWidth = no
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
ml_gen_box_or_unbox_rval(ModuleInfo, SourceType, DestType, BoxPolicy, VarRval,
|
|
ArgRval) :-
|
|
% Convert VarRval, of type SourceType, to ArgRval, of type DestType.
|
|
(
|
|
BoxPolicy = bp_always_boxed,
|
|
ArgRval = VarRval
|
|
;
|
|
BoxPolicy = bp_native_if_possible,
|
|
ml_gen_box_or_unbox_rval_native(ModuleInfo, SourceType, DestType,
|
|
VarRval, ArgRval)
|
|
).
|
|
|
|
ml_gen_box_or_unbox_rval_native(ModuleInfo, SourceType, DestType,
|
|
VarRval, ArgRval) :-
|
|
% We have special box/unbox rules for 2x2=4 situations:
|
|
%
|
|
% 1a convert from a type variable to something else
|
|
% 1b convert to a type variable from something else
|
|
% 2a convert from int64/uint64/float to something else
|
|
% 2b convert to int64/uint64/float from something else
|
|
%
|
|
% By the definition of "something else", it is not possible for
|
|
% the SourceType/DestType combination to match both 1a and 1b.
|
|
%
|
|
% It is possible for the SourceType/DestType combination to match
|
|
% both 1a and 2b, or 1b and 2a. In these cases, the 1a or 2a rule has
|
|
% precedence. This is the reason for the second test of DestType
|
|
% in the code handling 2a below.
|
|
%
|
|
% It is not possible for the SourceType/DestType combination to match
|
|
% both 2a and 2b, because any such change of type is beyond the scope
|
|
% of a box or unbox operation.
|
|
( if
|
|
(
|
|
SourceType = type_variable(_, _),
|
|
DestType \= type_variable(_, _),
|
|
% Converting from polymorphic type to concrete type: unbox.
|
|
MLDS_DestType = mercury_type_to_mlds_type(ModuleInfo, DestType),
|
|
ArgRvalPrime = ml_unbox(MLDS_DestType, VarRval)
|
|
;
|
|
SourceType = builtin_type(SourceBuiltinType),
|
|
(
|
|
SourceBuiltinType = builtin_type_int(IntType),
|
|
( IntType = int_type_int64
|
|
; IntType = int_type_uint64
|
|
)
|
|
;
|
|
SourceBuiltinType = builtin_type_float
|
|
),
|
|
DestType \= builtin_type(SourceBuiltinType),
|
|
% Leave this to the DestType = type_variable(_, _) code below.
|
|
DestType \= type_variable(_, _),
|
|
% Converting from int64/uint64/float: box, then cast the result.
|
|
MLDS_SourceType =
|
|
mercury_type_to_mlds_type(ModuleInfo, SourceType),
|
|
MLDS_DestType = mercury_type_to_mlds_type(ModuleInfo, DestType),
|
|
ArgRvalPrime = ml_cast(MLDS_DestType,
|
|
ml_box(MLDS_SourceType, VarRval))
|
|
)
|
|
then
|
|
ArgRvalPrime = ArgRval
|
|
else if
|
|
(
|
|
DestType = type_variable(_, _),
|
|
SourceType \= type_variable(_, _),
|
|
% Converting from concrete type to polymorphic type: box.
|
|
MLDS_SourceType =
|
|
mercury_type_to_mlds_type(ModuleInfo, SourceType),
|
|
ArgRvalPrime = ml_box(MLDS_SourceType, VarRval)
|
|
;
|
|
DestType = builtin_type(DestBuiltinType),
|
|
(
|
|
DestBuiltinType = builtin_type_int(IntType),
|
|
( IntType = int_type_int64
|
|
; IntType = int_type_uint64
|
|
)
|
|
;
|
|
DestBuiltinType = builtin_type_float
|
|
),
|
|
SourceType \= builtin_type(DestBuiltinType),
|
|
% We have already tested for SourceType = type_variable(_, _).
|
|
% Converting to int64/uint64/float: cast to mlds_generic_type,
|
|
% and then unbox.
|
|
MLDS_DestType = mercury_type_to_mlds_type(ModuleInfo, DestType),
|
|
ArgRvalPrime = ml_unbox(MLDS_DestType,
|
|
ml_cast(mlds_generic_type, VarRval))
|
|
)
|
|
then
|
|
ArgRvalPrime = ArgRval
|
|
else
|
|
ml_gen_box_or_unbox_rval_native_std(ModuleInfo, SourceType, DestType,
|
|
VarRval, ArgRval)
|
|
).
|
|
|
|
:- pred ml_gen_box_or_unbox_rval_native_std(module_info::in,
|
|
mer_type::in, mer_type::in, mlds_rval::in, mlds_rval::out) is det.
|
|
:- pragma inline(pred(ml_gen_box_or_unbox_rval_native_std/5)).
|
|
|
|
ml_gen_box_or_unbox_rval_native_std(ModuleInfo, SourceType, DestType,
|
|
VarRval, ArgRval) :-
|
|
( if
|
|
type_unify(SourceType, DestType, [], map.init, _),
|
|
not unifiable_types_still_need_cast(SourceType, DestType)
|
|
then
|
|
% If converting from one concrete type to the same type,
|
|
% leave the rval unchanged.
|
|
ArgRval = VarRval
|
|
else
|
|
% If converting from one concrete type to a different one, then cast.
|
|
% This is needed to handle construction/deconstruction unifications
|
|
% for no_tag types.
|
|
MLDS_DestType = mercury_type_to_mlds_type(ModuleInfo, DestType),
|
|
ArgRval = ml_cast(MLDS_DestType, VarRval)
|
|
).
|
|
|
|
:- pred unifiable_types_still_need_cast(mer_type::in, mer_type::in) is semidet.
|
|
:- pragma inline(pred(unifiable_types_still_need_cast/2)).
|
|
|
|
unifiable_types_still_need_cast(SourceType, DestType) :-
|
|
% XXX This exception from the "unifiable types do not need a cast"
|
|
% path above was part of the implementation of arrays for .NET
|
|
% added by trd in commit d4965acd721e480a31d618dadc95818cb4516df7.
|
|
% A bootcheck in hlc.gc works just fine without this exception,
|
|
% but the exception is still needed in java and csharp grades.
|
|
%
|
|
% Tyson's original comment, which was probably talking only about
|
|
% the .NET backend, was:
|
|
% If converting from an array(T) to array(X) where X is a concrete
|
|
% instance, we should insert a cast to the concrete instance.
|
|
% Also when converting to array(T) from array(X) we should cast
|
|
% to array(T).
|
|
type_to_ctor_and_args(SourceType, SourceTypeCtor, SourceTypeArgs),
|
|
type_to_ctor_and_args(DestType, DestTypeCtor, DestTypeArgs),
|
|
(
|
|
type_ctor_is_array(SourceTypeCtor),
|
|
SourceTypeArgs = [type_variable(_, _)]
|
|
;
|
|
type_ctor_is_array(DestTypeCtor),
|
|
DestTypeArgs = [type_variable(_, _)]
|
|
),
|
|
% Don't insert redundant casts if the types are the same, since
|
|
% the extra assignments introduced can inhibit tail call
|
|
% optimisation.
|
|
SourceType \= DestType.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
ml_gen_box_or_unbox_lval(CallerType, CalleeType, BoxPolicy, VarLval, VarName,
|
|
Context, ForClosureWrapper, ArgNum, ArgLval, ConvDecls,
|
|
ConvInputStmts, ConvOutputStmts, !Info) :-
|
|
% First see if we can just convert the lval as an rval;
|
|
% if no boxing/unboxing is required, then ml_box_or_unbox_rval
|
|
% will return its argument unchanged, and so we are done.
|
|
ml_gen_info_get_module_info(!.Info, ModuleInfo),
|
|
ml_gen_box_or_unbox_rval(ModuleInfo, CalleeType, CallerType, BoxPolicy,
|
|
ml_lval(VarLval), BoxedRval),
|
|
( if BoxedRval = ml_lval(VarLval) then
|
|
ArgLval = VarLval,
|
|
ConvDecls = [],
|
|
ConvInputStmts = [],
|
|
ConvOutputStmts = []
|
|
else
|
|
% If that didn't work, then we need to declare a fresh variable
|
|
% to use as the arg, and to generate statements to box/unbox
|
|
% that fresh arg variable and assign it to/from the output
|
|
% argument whose address we were passed.
|
|
|
|
% Generate a declaration for the fresh variable.
|
|
%
|
|
% Note that generating accurate GC tracing code for this variable
|
|
% requires some care, because CalleeType might be a type variable
|
|
% from the callee, not from the caller, and we can't generate
|
|
% type_infos for type variables from the callee. Hence we need to call
|
|
% the version of ml_gen_gc_statement which takes two types.
|
|
% The CalleeType is used to determine the type for the temporary
|
|
% variable declaration, but the CallerType is used to construct
|
|
% the type_info.
|
|
|
|
ml_gen_info_new_conv_var(ConvVarSeq, !Info),
|
|
ConvVarSeq = conv_seq(ConvVarNum),
|
|
( if VarName = lvn_prog_var(ProgVarName, ProgVarNum) then
|
|
ArgVarName =
|
|
lvn_prog_var_conv(ConvVarNum, ProgVarName, ProgVarNum)
|
|
else
|
|
VarNameStr = ml_local_var_name_to_string(VarName),
|
|
ArgVarName =
|
|
lvn_comp_var(lvnc_non_prog_var_conv(ConvVarNum, VarNameStr))
|
|
),
|
|
ml_gen_mlds_type(!.Info, CalleeType, MLDS_CalleeType),
|
|
(
|
|
ForClosureWrapper = yes,
|
|
% For closure wrappers, the argument type_infos are stored in
|
|
% the `type_params' local, so we need to handle the GC tracing
|
|
% code specially.
|
|
( if CallerType = type_variable(_, _) then
|
|
ml_gen_local_for_output_arg(ArgVarName, CalleeType, ArgNum,
|
|
Context, ArgVarDecl, !Info)
|
|
else
|
|
unexpected($pred,
|
|
"invalid CalleeType for closure wrapper")
|
|
)
|
|
;
|
|
ForClosureWrapper = no,
|
|
ml_gen_gc_statement_poly(ArgVarName, CalleeType, CallerType,
|
|
Context, GC_Stmts, !Info),
|
|
ArgVarDecl = ml_gen_mlds_var_decl(ArgVarName, MLDS_CalleeType,
|
|
GC_Stmts, Context)
|
|
),
|
|
ConvDecls = [ArgVarDecl],
|
|
|
|
% Create the lval for the variable and use it for the argument lval.
|
|
ArgLval = ml_local_var(ArgVarName, MLDS_CalleeType),
|
|
|
|
CallerIsDummy = is_type_a_dummy(ModuleInfo, CallerType),
|
|
(
|
|
CallerIsDummy = is_dummy_type,
|
|
% If it is a dummy argument type (e.g. io.state),
|
|
% then we don't need to bother assigning it.
|
|
ConvInputStmts = [],
|
|
ConvOutputStmts = []
|
|
;
|
|
CallerIsDummy = is_not_dummy_type,
|
|
% Generate statements to box/unbox the fresh variable and assign it
|
|
% to/from the output argument whose address we were passed.
|
|
|
|
% Assign to the freshly generated arg variable.
|
|
ml_gen_box_or_unbox_rval(ModuleInfo, CallerType, CalleeType,
|
|
BoxPolicy, ml_lval(VarLval), ConvertedVarRval),
|
|
AssignInputStmt = ml_gen_assign(ArgLval, ConvertedVarRval,
|
|
Context),
|
|
ConvInputStmts = [AssignInputStmt],
|
|
|
|
% Assign from the freshly generated arg variable.
|
|
ml_gen_box_or_unbox_rval(ModuleInfo, CalleeType, CallerType,
|
|
BoxPolicy, ml_lval(ArgLval), ConvertedArgRval),
|
|
AssignOutputStmt = ml_gen_assign(VarLval, ConvertedArgRval,
|
|
Context),
|
|
ConvOutputStmts = [AssignOutputStmt]
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
ml_gen_local_for_output_arg(VarName, Type, ArgNum, Context, LocalVarDefn,
|
|
!Info) :-
|
|
% Generate a declaration for a corresponding local variable.
|
|
% However, don't use the normal GC tracing code; instead, we need to get
|
|
% the typeinfo from `type_params', using the following code:
|
|
%
|
|
% MR_TypeInfo type_info;
|
|
% MR_MemoryList allocated_memory_cells = NULL;
|
|
% type_info = MR_make_type_info_maybe_existq(type_params,
|
|
% closure_layout->MR_closure_arg_pseudo_type_info[<ArgNum> - 1],
|
|
% NULL, NULL, &allocated_memory_cells);
|
|
%
|
|
% private_builtin__gc_trace_1_0(type_info, &<VarName>);
|
|
%
|
|
% MR_deallocate(allocated_memory_cells);
|
|
%
|
|
|
|
ClosureLayoutPtrName = lvn_comp_var(lvnc_closure_layout_ptr),
|
|
% This type is really `const MR_Closure_Layout *', but there is no easy
|
|
% way to represent that in the MLDS; using MR_Box instead works fine.
|
|
ClosureLayoutPtrType = mlds_generic_type,
|
|
ClosureLayoutPtrLval =
|
|
ml_local_var(ClosureLayoutPtrName, ClosureLayoutPtrType),
|
|
|
|
TypeParamsName = lvn_comp_var(lvnc_type_params),
|
|
% This type is really MR_TypeInfoParams, but there is no easy way to
|
|
% represent that in the MLDS; using MR_Box instead works fine.
|
|
TypeParamsType = mlds_generic_type,
|
|
TypeParamsLval = ml_local_var(TypeParamsName, TypeParamsType),
|
|
|
|
TypeInfoName = lvn_comp_var(lvnc_type_info),
|
|
% The type for this should match the type of the first argument
|
|
% of private_builtin.gc_trace/1, i.e. `mutvar(T)', which is a no_tag type
|
|
% whose representation is c_pointer.
|
|
ml_gen_info_get_module_info(!.Info, ModuleInfo),
|
|
TypeInfoMercuryType = c_pointer_type,
|
|
TypeInfoType = mercury_type_to_mlds_type(ModuleInfo, TypeInfoMercuryType),
|
|
TypeInfoLval = ml_local_var(TypeInfoName, TypeInfoType),
|
|
TypeInfoDecl = ml_gen_mlds_var_decl(TypeInfoName, TypeInfoType,
|
|
gc_no_stmt, Context),
|
|
|
|
ml_gen_gc_statement_with_typeinfo(VarName, Type, ml_lval(TypeInfoLval),
|
|
Context, GCStmt0, !Info),
|
|
|
|
(
|
|
( GCStmt0 = gc_trace_code(CallTraceFuncCode)
|
|
; GCStmt0 = gc_initialiser(CallTraceFuncCode)
|
|
),
|
|
MakeTypeInfoCodeC = inline_target_code(ml_target_c, [
|
|
raw_target_code("{\n"),
|
|
raw_target_code("MR_MemoryList allocated_mem = NULL;\n"),
|
|
target_code_output(TypeInfoLval),
|
|
raw_target_code(" = (MR_C_Pointer) " ++
|
|
"MR_make_type_info_maybe_existq(\n\t"),
|
|
target_code_input(ml_lval(TypeParamsLval)),
|
|
raw_target_code(", ((MR_Closure_Layout *)\n\t"),
|
|
target_code_input(ml_lval(ClosureLayoutPtrLval)),
|
|
raw_target_code(string.format(")->" ++
|
|
"MR_closure_arg_pseudo_type_info[%d - 1],\n\t" ++
|
|
"NULL, NULL, &allocated_mem);\n",
|
|
[i(ArgNum)]))
|
|
]),
|
|
MakeTypeInfoCode = ml_stmt_atomic(MakeTypeInfoCodeC, Context),
|
|
DeallocateCodeC = inline_target_code(ml_target_c, [
|
|
raw_target_code("MR_deallocate(allocated_mem);\n"),
|
|
raw_target_code("}\n")
|
|
]),
|
|
DeallocateCode = ml_stmt_atomic(DeallocateCodeC, Context),
|
|
% XXX MLDS_DEFN
|
|
GCTraceCode = ml_stmt_block([TypeInfoDecl], [],
|
|
[MakeTypeInfoCode, CallTraceFuncCode, DeallocateCode], Context),
|
|
GCStmt = gc_trace_code(GCTraceCode)
|
|
;
|
|
GCStmt0 = gc_no_stmt,
|
|
GCStmt = GCStmt0
|
|
),
|
|
LocalVarDefn = ml_gen_mlds_var_decl(VarName,
|
|
mercury_type_to_mlds_type(ModuleInfo, Type), GCStmt, Context).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code for handling success and failure.
|
|
%
|
|
|
|
ml_gen_success(CodeModel, Context, Stmts, !Info) :-
|
|
(
|
|
CodeModel = model_det,
|
|
%
|
|
% det succeed:
|
|
% <do true>
|
|
% ===>
|
|
% /* just fall through */
|
|
%
|
|
Stmts = []
|
|
;
|
|
CodeModel = model_semi,
|
|
%
|
|
% semidet succeed:
|
|
% <do true>
|
|
% ===>
|
|
% succeeded = MR_TRUE;
|
|
%
|
|
ml_gen_set_success(ml_const(mlconst_true), Context, SetSuccessTrue,
|
|
!Info),
|
|
Stmts = [SetSuccessTrue]
|
|
;
|
|
CodeModel = model_non,
|
|
%
|
|
% nondet succeed:
|
|
% <true && SUCCEED()>
|
|
% ===>
|
|
% SUCCEED()
|
|
%
|
|
ml_gen_call_current_success_cont(!.Info, Context, CallCont),
|
|
Stmts = [CallCont]
|
|
).
|
|
|
|
ml_gen_failure(CodeModel, Context, Stmts, !Info) :-
|
|
(
|
|
CodeModel = model_det,
|
|
unexpected($pred, "`fail' has determinism `det'")
|
|
;
|
|
CodeModel = model_semi,
|
|
%
|
|
% semidet fail:
|
|
% <do fail>
|
|
% ===>
|
|
% succeeded = MR_FALSE;
|
|
%
|
|
ml_gen_set_success(ml_const(mlconst_false), Context, SetSuccessFalse,
|
|
!Info),
|
|
Stmts = [SetSuccessFalse]
|
|
;
|
|
CodeModel = model_non,
|
|
%
|
|
% nondet fail:
|
|
% <fail && SUCCEED()>
|
|
% ===>
|
|
% /* just fall through */
|
|
%
|
|
Stmts = []
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
ml_gen_succeeded_var_decl(Context) =
|
|
ml_gen_mlds_var_decl(lvn_comp_var(lvnc_succeeded), mlds_native_bool_type,
|
|
gc_no_stmt, Context).
|
|
|
|
ml_success_lval(SucceededLval, !Info) :-
|
|
SucceededLval =
|
|
ml_local_var(lvn_comp_var(lvnc_succeeded), mlds_native_bool_type),
|
|
ml_gen_info_set_used_succeeded_var(yes, !Info).
|
|
|
|
ml_gen_test_success(SucceededRval, !Info) :-
|
|
ml_success_lval(SucceededLval, !Info),
|
|
SucceededRval = ml_lval(SucceededLval).
|
|
|
|
ml_gen_set_success(Value, Context, Stmt, !Info) :-
|
|
ml_success_lval(Succeeded, !Info),
|
|
Stmt = ml_gen_assign(Succeeded, Value, Context).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Generate the name for the specified `cond_<N>' variable.
|
|
%
|
|
:- func ml_gen_cond_var_name(cond_seq) = mlds_local_var_name.
|
|
|
|
ml_gen_cond_var_name(CondSeq) = VarName :-
|
|
CondSeq = cond_seq(CondNum),
|
|
VarName = lvn_comp_var(lvnc_cond(CondNum)).
|
|
|
|
ml_gen_cond_var_decl(CondSeq, Context) =
|
|
ml_gen_mlds_var_decl(ml_gen_cond_var_name(CondSeq), mlds_native_bool_type,
|
|
gc_no_stmt, Context).
|
|
|
|
ml_cond_var_lval(CondSeq, CondVarLval) :-
|
|
CondVarLval =
|
|
ml_local_var(ml_gen_cond_var_name(CondSeq), mlds_native_bool_type).
|
|
|
|
ml_gen_test_cond_var(CondVar, CondVarRval) :-
|
|
ml_cond_var_lval(CondVar, CondVarLval),
|
|
CondVarRval = ml_lval(CondVarLval).
|
|
|
|
ml_gen_set_cond_var(CondVar, Value, Context, Stmt) :-
|
|
ml_cond_var_lval(CondVar, CondVarLval),
|
|
Stmt = ml_gen_assign(CondVarLval, Value, Context).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
ml_initial_cont(Info, OutputVarLvalsTypes, Cont) :-
|
|
% We expect OutputVarLvalsTypes to be empty if `--nondet-copy-out'
|
|
% is not enabled.
|
|
ml_gen_info_get_module_info(Info, ModuleInfo),
|
|
ml_skip_dummy_argument_types(ModuleInfo,
|
|
OutputVarLvalsTypes, OutputVarLvalsMLDSTypes),
|
|
|
|
assoc_list.values(OutputVarLvalsMLDSTypes, OutputVarMLDSTypes),
|
|
ContLval = ml_local_var(lvn_comp_var(lvnc_cont),
|
|
mlds_cont_type(OutputVarMLDSTypes)),
|
|
ContEnvLval = ml_local_var(lvn_comp_var(lvnc_cont_env_ptr),
|
|
mlds_generic_env_ptr_type),
|
|
Cont = success_cont(ml_lval(ContLval), ml_lval(ContEnvLval),
|
|
OutputVarLvalsMLDSTypes).
|
|
|
|
:- pred ml_skip_dummy_argument_types(module_info::in,
|
|
assoc_list(mlds_lval, mer_type)::in,
|
|
assoc_list(mlds_lval, mlds_type)::out) is det.
|
|
|
|
ml_skip_dummy_argument_types(_, [], []).
|
|
ml_skip_dummy_argument_types(ModuleInfo, [Lval - Type | LvalsTypes],
|
|
LvalsMLDSTypes) :-
|
|
ml_skip_dummy_argument_types(ModuleInfo, LvalsTypes, TailLvalsMLDSTypes),
|
|
IsDummy = is_type_a_dummy(ModuleInfo, Type),
|
|
(
|
|
IsDummy = is_dummy_type,
|
|
LvalsMLDSTypes = TailLvalsMLDSTypes
|
|
;
|
|
IsDummy = is_not_dummy_type,
|
|
MLDSType = mercury_type_to_mlds_type(ModuleInfo, Type),
|
|
LvalsMLDSTypes = [Lval - MLDSType | TailLvalsMLDSTypes]
|
|
).
|
|
|
|
ml_gen_call_current_success_cont(Info, Context, Stmt) :-
|
|
ml_gen_info_current_success_cont(Info, SuccCont),
|
|
SuccCont = success_cont(FuncRval, EnvPtrRval, ArgTypesLvals0),
|
|
|
|
assoc_list.keys_and_values(ArgTypesLvals0, ArgLvals0, ArgTypes0),
|
|
ArgRvals0 = list.map(func(Lval) = ml_lval(Lval), ArgLvals0),
|
|
ArgRvals = ArgRvals0 ++ [EnvPtrRval],
|
|
RetLvals = [],
|
|
|
|
ArgTypes = ArgTypes0 ++ [mlds_generic_env_ptr_type],
|
|
RetTypes = [],
|
|
Signature = mlds_func_signature(ArgTypes, RetTypes),
|
|
|
|
CallKind = ordinary_call,
|
|
Stmt = ml_stmt_call(Signature, FuncRval, ArgRvals, RetLvals,
|
|
CallKind, Context).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Routines for dealing with the environment pointer used for nested functions.
|
|
%
|
|
|
|
ml_get_env_ptr(ml_lval(EnvPtrLval)) :-
|
|
EnvPtrLval = ml_local_var(lvn_comp_var(lvnc_env_ptr), mlds_unknown_type).
|
|
|
|
ml_declare_env_ptr_arg(Arg) :-
|
|
VarName = lvn_comp_var(lvnc_env_ptr_arg),
|
|
Type = mlds_generic_env_ptr_type,
|
|
% When targeting C, we always allocate continuation environments
|
|
% on the stack, where our accurage GC does not need to trace it.
|
|
% When targeting C# or Java, we use the target's builtin GC,
|
|
% so again, there is no need for any info meant for our own
|
|
% accurate GC system.
|
|
GCStatement = gc_no_stmt,
|
|
Arg = mlds_argument(VarName, Type, GCStatement).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% This function returns the offset to add to the argument
|
|
% number of a closure arg to get its field number.
|
|
% field 0 is the closure layout
|
|
% field 1 is the closure address
|
|
% field 2 is the number of arguments
|
|
% field 3 is the 1st argument field
|
|
% field 4 is the 2nd argument field,
|
|
% etc.
|
|
% Hence the offset to add to the argument number
|
|
% to get the field number is 2.
|
|
%
|
|
ml_closure_arg_offset = 2.
|
|
|
|
% This function returns the offset to add to the argument
|
|
% number of a typeclass_info arg to get its field number.
|
|
% The Nth extra argument to pass to the method is
|
|
% in field N of the typeclass_info, so the offset is zero.
|
|
%
|
|
ml_typeclass_info_arg_offset = 0.
|
|
|
|
% This function returns the offset to add to the method number
|
|
% for a type class method to get its field number within the
|
|
% base_typeclass_info.
|
|
% field 0 is num_extra
|
|
% field 1 is num_constraints
|
|
% field 2 is num_superclasses
|
|
% field 3 is class_arity
|
|
% field 4 is num_methods
|
|
% field 5 is the 1st method
|
|
% field 6 is the 2nd method
|
|
% etc.
|
|
% (See the base_typeclass_info type in rtti.m or the
|
|
% description in notes/type_class_transformation.html for
|
|
% more information about the layout of base_typeclass_infos.)
|
|
% Hence the offset is 4.
|
|
%
|
|
ml_base_typeclass_info_method_offset = 4.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Routines for dealing with lookup tables.
|
|
%
|
|
|
|
ml_generate_constants_for_arms(_Vars, [], [], !Info).
|
|
ml_generate_constants_for_arms(Vars, [Goal | Goals], [Soln | Solns], !Info) :-
|
|
ml_generate_constants_for_arm(Vars, Goal, Soln, !Info),
|
|
ml_generate_constants_for_arms(Vars, Goals, Solns, !Info).
|
|
|
|
ml_generate_constants_for_arm(Vars, Goal, Soln, !Info) :-
|
|
ml_gen_info_get_const_var_map(!.Info, InitConstVarMap),
|
|
ml_gen_goal(model_det, Goal, _LocalVarDefns, _FuncDefns, _Stmts, !Info),
|
|
ml_gen_info_get_const_var_map(!.Info, FinalConstVarMap),
|
|
list.map(search_ground_rval(FinalConstVarMap), Vars, Soln),
|
|
ml_gen_info_set_const_var_map(InitConstVarMap, !Info).
|
|
|
|
:- pred search_ground_rval(ml_ground_term_map::in, prog_var::in,
|
|
mlds_rval::out) is semidet.
|
|
|
|
search_ground_rval(FinalConstVarMap, Var, Rval) :-
|
|
map.search(FinalConstVarMap, Var, GroundTerm),
|
|
GroundTerm = ml_ground_term(Rval, _, _).
|
|
|
|
ml_generate_field_assign(OutVarLval, FieldType, FieldId, VectorCommon,
|
|
StructType, IndexRval, Context, Stmt) :-
|
|
BaseRval = ml_vector_common_row_addr(VectorCommon, IndexRval),
|
|
FieldLval = ml_field(yes(ptag(0u8)), BaseRval, StructType,
|
|
FieldId, FieldType),
|
|
AtomicStmt = assign(OutVarLval, ml_lval(FieldLval)),
|
|
Stmt = ml_stmt_atomic(AtomicStmt, Context).
|
|
|
|
ml_generate_field_assigns(OutVars, FieldTypes, FieldIds, VectorCommon,
|
|
StructType, IndexRval, Context, Stmts, !Info) :-
|
|
( if
|
|
OutVars = [],
|
|
FieldTypes = [],
|
|
FieldIds = []
|
|
then
|
|
Stmts = []
|
|
else if
|
|
OutVars = [HeadOutVar | TailOutVars],
|
|
FieldTypes = [HeadFieldType | TailFieldTypes],
|
|
FieldIds = [HeadFieldId | TailFieldIds]
|
|
then
|
|
ml_gen_var_direct(!.Info, HeadOutVar, HeadOutVarLval),
|
|
ml_generate_field_assign(HeadOutVarLval, HeadFieldType, HeadFieldId,
|
|
VectorCommon, StructType, IndexRval, Context, HeadStmt),
|
|
ml_generate_field_assigns(TailOutVars, TailFieldTypes, TailFieldIds,
|
|
VectorCommon, StructType, IndexRval, Context, TailStmts,
|
|
!Info),
|
|
Stmts = [HeadStmt | TailStmts]
|
|
else
|
|
unexpected($pred, "mismatched lists")
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Miscellaneous routines.
|
|
%
|
|
|
|
fixup_builtin_module(ModuleName0) = ModuleName :-
|
|
( if ModuleName0 = unqualified("") then
|
|
ModuleName = mercury_public_builtin_module
|
|
else
|
|
ModuleName = ModuleName0
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module ml_backend.ml_code_util.
|
|
%---------------------------------------------------------------------------%
|