Files
mercury/compiler/ml_unify_gen_deconstruct.m
Zoltan Somogyi ea4f95a7ed Use var_tables in lco.m, and when dumping goals.
Since this is the first converted module that dumps out goals when
debugging trace flags are enabled, this required generalizing the code
that does that, to take either varsets or var_tables as a means of
specifying the names of variables. We do this via a new type,
var_name_source, which contains either a varset or a var_table.

Almost all of this diff is there to implement this generalization.
A large part of it affects code in the parse_tree package that we use
to write out the parts of HLDS goals that are defined by types defined
in that package. Since we want to avoid making any part of the parse_tree
package dependent on the hlds package, this required defining the
var_name_source type in the parse_tree package, which in turn requires
var_table.m to be in that same package.

compiler/lco.m:
    Convert this module to use var_tables instead of varsets and vartypes.

compiler/var_table.m:
    Move this module from the hlds package to the parse_tree package.

    To make this, possible, move the parts that required access to the HLDS
    to hlds_pred.m, from where it was usually invoked.

    Export some utility predicates to allow the moved code to work
    in hlds_pred.m without access to the actual definition of the
    var_table type.

    Define the var_name_source type.

    Add some utility functions for use by code writing out variable names.

compiler/hlds_pred.m:
    Add the code moved from var_table.m.

compiler/vartypes.m:
    Move this module from the hlds package to the parse_tree package,
    for symmetry with var_table.m. It did not depend on being in hlds
    in any way.

compiler/hlds.m:
compiler/parse_tree.m:
    Move vartypes.m and var_table.m from the hlds package
    to the parse_tree package.

compiler/hlds_out_goal.m:
    Change all the predicates in this module to take a var_name_source
    instead of a prog_varset.

    Fix some comments.

compiler/hlds_out_util.m:
    Change some of the predicates in this module (those called from
    hlds_out_goal.m) to take a var_name_source instead of a prog_varset.

compiler/parse_tree_out_term.m:
    Provide variants of some existing predicates and functions that take
    var_name_sources instead of varsets. The code of the copies
    duplicates the logic of the originals, though I hope that this
    duplication can be done away with at the end of the transition.
    (The best solution would be to use a typeclass with methods
    that convert vars to their names, but we would want to ensure
    that the compiler can specialize all the affected predicates
    and functions to the two instances of this typeclass, which is
    something that we cannot do yet. In the meantime, the lack of
    any generalization in the old versions preserves their performance.)

tools/sort_imports:
tools/filter_sort_imports:
    A new tool that automatically sorts any occurrences of consecutive
    ":- import_module" declarations in the named files. The sorting is done
    in filter_sort_imports; sort_imports loops over the named files.

    After automatically replacing all occurrences of hlds.{vartypes,var_table}
    in import_module declarations with their parse_tree versions, the updated
    import_module declarations were usually out of order with respect to
    their neighbours. I used this script to fix that, and some earlier
    out-of-order imports.

compiler/accumulator.m:
compiler/add_class.m:
compiler/add_clause.m:
compiler/add_foreign_proc.m:
compiler/add_heap_ops.m:
compiler/add_pragma_type_spec.m:
compiler/add_pred.m:
compiler/add_trail_ops.m:
compiler/analysis.m:
compiler/arg_info.m:
compiler/build_mode_constraints.m:
compiler/bytecode_gen.m:
compiler/call_gen.m:
compiler/check_promise.m:
compiler/closure_analysis.m:
compiler/closure_gen.m:
compiler/code_info.m:
compiler/code_loc_dep.m:
compiler/common.m:
compiler/compile_target_code.m:
compiler/complexity.m:
compiler/const_prop.m:
compiler/constraint.m:
compiler/continuation_info.m:
compiler/convert_parse_tree.m:
compiler/coverage_profiling.m:
compiler/cse_detection.m:
compiler/ctgc.datastruct.m:
compiler/ctgc.util.m:
compiler/dead_proc_elim.m:
compiler/deep_profiling.m:
compiler/deforest.m:
compiler/delay_construct.m:
compiler/delay_partial_inst.m:
compiler/dep_par_conj.m:
compiler/det_analysis.m:
compiler/det_report.m:
compiler/det_util.m:
compiler/direct_arg_in_out.m:
compiler/disj_gen.m:
compiler/distance_granularity.m:
compiler/equiv_type_hlds.m:
compiler/exception_analysis.m:
compiler/file_names.m:
compiler/float_regs.m:
compiler/follow_vars.m:
compiler/format_call.m:
compiler/generate_dep_d_files.m:
compiler/get_dependencies.m:
compiler/goal_expr_to_goal.m:
compiler/goal_mode.m:
compiler/goal_path.m:
compiler/goal_store.m:
compiler/goal_util.m:
compiler/granularity.m:
compiler/hhf.m:
compiler/higher_order.m:
compiler/hlds_clauses.m:
compiler/hlds_code_util.m:
compiler/hlds_error_util.m:
compiler/hlds_goal.m:
compiler/hlds_llds.m:
compiler/hlds_out_pred.m:
compiler/hlds_rtti.m:
compiler/hlds_statistics.m:
compiler/inlining.m:
compiler/inst_check.m:
compiler/inst_test.m:
compiler/inst_user.m:
compiler/instance_method_clauses.m:
compiler/instmap.m:
compiler/intermod.m:
compiler/intermod_analysis.m:
compiler/interval.m:
compiler/introduce_exists_casts.m:
compiler/introduce_parallelism.m:
compiler/item_util.m:
compiler/lambda.m:
compiler/live_vars.m:
compiler/liveness.m:
compiler/llds.m:
compiler/llds_out_data.m:
compiler/llds_out_file.m:
compiler/llds_out_util.m:
compiler/lookup_switch.m:
compiler/loop_inv.m:
compiler/make.module_target.m:
compiler/make.util.m:
compiler/make_goal.m:
compiler/make_hlds_separate_items.m:
compiler/make_hlds_types.m:
compiler/mark_tail_calls.m:
compiler/mercury_compile_mlds_back_end.m:
compiler/middle_rec.m:
compiler/ml_accurate_gc.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_disj_gen.m:
compiler/ml_foreign_proc_gen.m:
compiler/ml_gen_info.m:
compiler/ml_lookup_switch.m:
compiler/ml_proc_gen.m:
compiler/ml_simplify_switch.m:
compiler/ml_switch_gen.m:
compiler/ml_tag_switch.m:
compiler/ml_unify_gen.m:
compiler/ml_unify_gen_construct.m:
compiler/ml_unify_gen_deconstruct.m:
compiler/ml_unify_gen_test.m:
compiler/ml_unify_gen_util.m:
compiler/mlds_to_c_data.m:
compiler/mlds_to_c_func.m:
compiler/mlds_to_c_global.m:
compiler/mlds_to_cs_class.m:
compiler/mlds_to_cs_file.m:
compiler/mlds_to_java_data.m:
compiler/mlds_to_java_file.m:
compiler/mlds_to_java_stmt.m:
compiler/mlds_to_java_type.m:
compiler/mmc_analysis.m:
compiler/mode_comparison.m:
compiler/mode_constraints.m:
compiler/mode_debug.m:
compiler/mode_errors.m:
compiler/mode_info.m:
compiler/mode_ordering.m:
compiler/modecheck_call.m:
compiler/modecheck_coerce.m:
compiler/modecheck_goal.m:
compiler/modecheck_unify.m:
compiler/modecheck_util.m:
compiler/modes.m:
compiler/module_cmds.m:
compiler/old_type_constraints.m:
compiler/opt_debug.m:
compiler/optimize.m:
compiler/options_file.m:
compiler/ordering_mode_constraints.m:
compiler/par_loop_control.m:
compiler/parse_item.m:
compiler/parse_string_format.m:
compiler/parse_tree_out_inst.m:
compiler/parse_tree_to_term.m:
compiler/parse_util.m:
compiler/pd_debug.m:
compiler/pd_info.m:
compiler/pd_util.m:
compiler/peephole.m:
compiler/polymorphism.m:
compiler/polymorphism_info.m:
compiler/polymorphism_lambda.m:
compiler/polymorphism_type_class_info.m:
compiler/polymorphism_type_info.m:
compiler/post_typecheck.m:
compiler/pragma_c_gen.m:
compiler/pred_name.m:
compiler/pred_table.m:
compiler/prog_item.m:
compiler/prog_rep.m:
compiler/prop_mode_constraints.m:
compiler/purity.m:
compiler/push_goals_together.m:
compiler/qual_info.m:
compiler/quantification.m:
compiler/rbmm.execution_path.m:
compiler/rbmm.m:
compiler/rbmm.points_to_analysis.m:
compiler/rbmm.points_to_graph.m:
compiler/rbmm.points_to_info.m:
compiler/rbmm.region_resurrection_renaming.m:
compiler/rbmm.region_transformation.m:
compiler/recompilation.used_file.m:
compiler/recompilation.version.m:
compiler/recompute_instmap_deltas.m:
compiler/resolve_unify_functor.m:
compiler/rtti.m:
compiler/rtti_out.m:
compiler/rtti_to_mlds.m:
compiler/saved_vars.m:
compiler/set_of_var.m:
compiler/simplify_goal_call.m:
compiler/simplify_goal_conj.m:
compiler/simplify_goal_disj.m:
compiler/simplify_goal_ite.m:
compiler/simplify_goal_scope.m:
compiler/simplify_goal_switch.m:
compiler/simplify_goal_unify.m:
compiler/simplify_info.m:
compiler/simplify_proc.m:
compiler/size_prof.m:
compiler/smm_common.m:
compiler/ssdebug.m:
compiler/stack_alloc.m:
compiler/stack_layout.m:
compiler/stack_opt.m:
compiler/stm_expand.m:
compiler/store_alloc.m:
compiler/structure_reuse.analysis.m:
compiler/structure_reuse.direct.choose_reuse.m:
compiler/structure_reuse.direct.detect_garbage.m:
compiler/structure_reuse.domain.m:
compiler/structure_reuse.indirect.m:
compiler/structure_reuse.lbu.m:
compiler/structure_reuse.lfu.m:
compiler/structure_sharing.analysis.m:
compiler/structure_sharing.domain.m:
compiler/superhomogeneous.m:
compiler/switch_detection.m:
compiler/switch_gen.m:
compiler/switch_util.m:
compiler/table_gen.m:
compiler/tabling_analysis.m:
compiler/term_constr_build.m:
compiler/term_constr_data.m:
compiler/term_constr_initial.m:
compiler/term_constr_main.m:
compiler/term_constr_main_types.m:
compiler/term_constr_util.m:
compiler/term_pass1.m:
compiler/term_traversal.m:
compiler/term_util.m:
compiler/trace_gen.m:
compiler/trailing_analysis.m:
compiler/transform_llds.m:
compiler/try_expand.m:
compiler/tupling.m:
compiler/type_assign.m:
compiler/type_ctor_info.m:
compiler/type_util.m:
compiler/typecheck.m:
compiler/typecheck_debug.m:
compiler/typecheck_errors.m:
compiler/typecheck_info.m:
compiler/unify_gen_construct.m:
compiler/unify_gen_deconstruct.m:
compiler/unify_proc.m:
compiler/unique_modes.m:
compiler/unneeded_code.m:
compiler/untupling.m:
compiler/unused_args.m:
compiler/unused_imports.m:
compiler/var_locn.m:
compiler/write_deps_file.m:
compiler/write_module_interface_files.m:
    Conform to the changes above.
2022-04-18 02:00:38 +10:00

1139 lines
48 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 1999-2012, 2014 The University of Melbourne.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%---------------------------------------------------------------------------%
:- module ml_backend.ml_unify_gen_deconstruct.
:- interface.
:- import_module hlds.
:- import_module hlds.code_model.
:- import_module hlds.hlds_data.
:- import_module hlds.hlds_goal.
:- import_module ml_backend.ml_gen_info.
:- import_module ml_backend.ml_unify_gen_util.
:- import_module ml_backend.mlds.
:- import_module parse_tree.
:- import_module parse_tree.prog_data.
:- import_module assoc_list.
:- import_module list.
%---------------------------------------------------------------------------%
:- pred ml_generate_deconstruction_unification(prog_var::in, cons_id::in,
list(prog_var)::in, list(unify_mode)::in, can_fail::in, can_cgc::in,
code_model::in, prog_context::in,
list(mlds_local_var_defn)::out, list(mlds_stmt)::out,
ml_gen_info::in, ml_gen_info::out) is det.
%---------------------------------------------------------------------------%
%
% We export ml_gen_dynamic_deconstruct_args for use by ml_unify_gen_construct.m
% when handling reused cells.
%
% While deconstruct unifications cannot take the addresses of any arguments,
% construction unifications with reuse can.
%
:- type take_addr_info
---> take_addr_info(
% The variable we record the address in.
tai_address_var :: prog_var,
% The offset of the field. This must take into account
% extra arguments and argument packing.
tai_offset :: cell_offset,
% The type of the field variable.
tai_field_var_type :: mlds_type,
% The type of the field, possibly after boxing.
tai_maybe_boxed_field_type :: mlds_type
).
:- pred ml_gen_dynamic_deconstruct_args(field_gen,
assoc_list(prog_var, constructor_arg_repn), list(unify_mode),
int, prog_context, list(int), list(take_addr_info),
list(mlds_local_var_defn), list(mlds_stmt), ml_gen_info, ml_gen_info).
:- mode ml_gen_dynamic_deconstruct_args(in, in, in, in, in,
in(bound([])), out, out, out, in, out) is det.
:- mode ml_gen_dynamic_deconstruct_args(in, in, in, in, in,
in, out, out, out, in, out) is det.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
:- import_module backend_libs.
:- import_module backend_libs.builtin_ops.
:- import_module check_hlds.
:- import_module check_hlds.type_util.
:- import_module hlds.goal_form.
:- import_module hlds.hlds_module.
:- import_module hlds.hlds_pred.
:- import_module libs.
:- import_module libs.globals.
:- import_module mdbcomp.
:- import_module mdbcomp.sym_name.
:- import_module ml_backend.ml_code_gen.
:- import_module ml_backend.ml_code_util.
:- import_module ml_backend.ml_unify_gen_test.
:- import_module parse_tree.builtin_lib_types.
:- import_module parse_tree.prog_data_foreign.
:- import_module parse_tree.var_table.
:- import_module bool.
:- import_module int.
:- import_module map.
:- import_module maybe.
:- import_module one_or_more.
:- import_module pair.
:- import_module require.
:- import_module term.
:- import_module uint.
:- import_module uint8.
%---------------------------------------------------------------------------%
ml_generate_deconstruction_unification(LHSVar, ConsId, RHSVars, ArgModes,
CanFail, CanCGC, CodeModel, Context, Defns, Stmts, !Info) :-
(
CanFail = can_fail,
ExpectedCodeModel = model_semi,
ml_generate_semi_deconstruction(LHSVar, ConsId, RHSVars, ArgModes,
Context, Defns, UnifyStmts, !Info)
;
CanFail = cannot_fail,
ExpectedCodeModel = model_det,
ml_generate_det_deconstruction(LHSVar, ConsId, RHSVars, ArgModes,
Context, Defns, UnifyStmts, !Info)
),
(
% Note that we can deallocate a cell even if the unification fails;
% it is the responsibility of the structure reuse phase to ensure
% that this is safe.
CanCGC = can_cgc,
ml_gen_info_get_var_table(!.Info, VarTable),
lookup_var_entry(VarTable, LHSVar, LHSVarEntry),
ml_gen_var(!.Info, LHSVar, LHSVarEntry, LHSVarLval),
% XXX Avoid strip_tag when we know what tag it will have.
Delete = delete_object(ml_unop(strip_tag, ml_lval(LHSVarLval))),
CGCStmt = ml_stmt_atomic(Delete, Context),
Stmts0 = UnifyStmts ++ [CGCStmt]
;
CanCGC = cannot_cgc,
Stmts0 = UnifyStmts
),
% We used to require that CodeModel = ExpectedCodeModel. But the
% determinism field in the goal_info is allowed to be a conservative
% approximation, so we need to handle the case were CodeModel is less
% precise than ExpectedCodeModel.
ml_gen_maybe_convert_goal_code_model(CodeModel, ExpectedCodeModel,
Context, Stmts0, Stmts, !Info).
%---------------------------------------------------------------------------%
% Generate a semidet deconstruction. A semidet deconstruction unification
% is a tag test, followed by a deterministic deconstruction which is
% executed only if the tag test succeeds.
%
% semidet (can_fail) deconstruction:
% <succeeded = (X => f(A1, A2, ...))>
% ===>
% <succeeded = (X => f(_, _, _, _))> % tag test
% if (succeeded) {
% A1 = arg(X, f, 1); % extract arguments
% A2 = arg(X, f, 2);
% ...
% }
%
:- pred ml_generate_semi_deconstruction(prog_var::in, cons_id::in,
list(prog_var)::in, list(unify_mode)::in, prog_context::in,
list(mlds_local_var_defn)::out, list(mlds_stmt)::out,
ml_gen_info::in, ml_gen_info::out) is det.
ml_generate_semi_deconstruction(LHSVar, ConsId, RHSVars, ArgModes, Context,
Defns, Stmts, !Info) :-
ml_generate_test_var_has_cons_id(LHSVar, ConsId, TestRval, !Info),
ml_gen_set_success(TestRval, Context, SetTestResultStmt, !Info),
ml_gen_test_success(SucceededRval, !Info),
ml_generate_det_deconstruction(LHSVar, ConsId, RHSVars, ArgModes, Context,
Defns, DetDeconstructStmts, !Info),
(
DetDeconstructStmts = [],
Stmts = [SetTestResultStmt]
;
(
DetDeconstructStmts = [DetDeconstructStmt]
;
DetDeconstructStmts = [_, _ | _],
DetDeconstructStmt =
ml_gen_block([], [], DetDeconstructStmts, Context)
),
IfStmt = ml_stmt_if_then_else(SucceededRval, DetDeconstructStmt,
no, Context),
Stmts = [SetTestResultStmt, IfStmt]
).
%---------------------------------------------------------------------------%
% Generate a deterministic deconstruction. In a deterministic
% deconstruction, we know the value of the cons_id that X is bound to,
% so we do not need to generate a test for it.
%
% det (cannot_fail) deconstruction:
% <do (X => f(A1, A2, ...))>
% ===>
% A1 = arg(X, f, 1); % extract arguments
% A2 = arg(X, f, 2);
% ...
%
:- pred ml_generate_det_deconstruction(prog_var::in, cons_id::in,
list(prog_var)::in, list(unify_mode)::in, prog_context::in,
list(mlds_local_var_defn)::out, list(mlds_stmt)::out,
ml_gen_info::in, ml_gen_info::out) is det.
ml_generate_det_deconstruction(LHSVar, ConsId, RHSVars, ArgModes, Context,
Defns, Stmts, !Info) :-
ml_cons_id_to_tag(!.Info, ConsId, ConsTag),
(
( ConsTag = int_tag(_)
; ConsTag = float_tag(_)
; ConsTag = string_tag(_)
; ConsTag = foreign_tag(_, _)
; ConsTag = dummy_tag
; ConsTag = shared_local_tag_no_args(_, _, _)
),
% For constants, if the deconstruction is det, then we already know
% the value of the constant, so Stmts = [].
Defns = [],
Stmts = []
;
( ConsTag = ground_term_const_tag(_, _)
; ConsTag = type_ctor_info_tag(_, _, _)
; ConsTag = base_typeclass_info_tag(_, _, _)
; ConsTag = type_info_const_tag(_)
; ConsTag = typeclass_info_const_tag(_)
; ConsTag = deep_profiling_proc_layout_tag(_, _)
; ConsTag = tabling_info_tag(_, _)
; ConsTag = table_io_entry_tag(_, _)
; ConsTag = closure_tag(_, _, _)
),
unexpected($pred, "unexpected tag")
;
ConsTag = no_tag,
get_notag_or_direct_arg_arg_mode(RHSVars, ArgModes, RHSVar, ArgMode),
ml_gen_dynamic_deconstruct_no_tag(!.Info, LHSVar, RHSVar, ArgMode,
Context, Stmts),
Defns = []
;
ConsTag = direct_arg_tag(Ptag),
get_notag_or_direct_arg_arg_mode(RHSVars, ArgModes, RHSVar, ArgMode),
ml_gen_dynamic_deconstruct_direct_arg(!.Info, Ptag, LHSVar, RHSVar,
ArgMode, Context, Stmts),
Defns = []
;
ConsTag = remote_args_tag(RemoteArgsTagInfo),
(
(
RemoteArgsTagInfo = remote_args_only_functor,
Ptag = ptag(0u8)
;
RemoteArgsTagInfo = remote_args_unshared(Ptag)
;
RemoteArgsTagInfo = remote_args_ctor(_Data),
Ptag = ptag(0u8)
),
TagwordArgs = no,
InitOffset = cell_offset(0)
;
RemoteArgsTagInfo = remote_args_shared(Ptag, RemoteSectag),
RemoteSectag = remote_sectag(SectagUint, SectagSize),
(
SectagSize = rsectag_word,
TagwordArgs = no,
InitOffset = cell_offset(1)
;
SectagSize = rsectag_subword(SectagBits),
remote_sectag_filled_bitfield(SectagUint, SectagBits,
TagFilledBitfield0),
TagwordArgs = yes(TagFilledBitfield0),
% The value of InitOffset is used only for tuples and
% extra type_info/typeclass_info args. If a function
% symbols has a sub-word-sized sectag, it cannot be
% a tuple constructor, and it cannot have any extra args,
% so this (obviously wrong) value won't be used.
InitOffset = cell_offset(-42)
)
),
ml_gen_info_get_var_table(!.Info, VarTable),
lookup_var_entry(VarTable, LHSVar, LHSVarEntry),
ml_gen_var(!.Info, LHSVar, LHSVarEntry, LHSVarLval),
LHSVarType = LHSVarEntry ^ vte_type,
decide_field_gen(!.Info, LHSVarLval, LHSVarType, ConsId, ConsTag, Ptag,
FieldGen),
ml_field_names_and_types(!.Info, LHSVarType, ConsId, InitOffset,
RHSVars, RHSVarRepns),
(
TagwordArgs = yes(TagFilledBitfield),
ml_take_tagword_args(RHSVarRepns, ArgModes,
TagwordRHSVarRepns, TagwordArgModes,
NonTagwordRHSVarRepns, NonTagwordArgModes,
1, FirstNonTagwordArgNum),
FieldGen = field_gen(MaybePtag, AddrRval, AddrType, FieldVia),
expect(unify(FieldVia, field_via_offset), $pred,
"not field_via_offset for tagword"),
TagwordFieldId = ml_field_offset(ml_const(mlconst_int(0))),
TagwordLval = ml_field(MaybePtag, AddrRval, AddrType,
TagwordFieldId, mlds_generic_type),
UintType = mlds_builtin_type_int(int_type_uint),
CastTagwordRval = ml_cast(UintType, ml_lval(TagwordLval)),
ml_gen_deconstruct_tagword_args(TagwordLval, CastTagwordRval,
mlds_generic_type, TagFilledBitfield,
TagwordRHSVarRepns, TagwordArgModes, Context,
TagwordDefns, TagwordStmts, !Info),
ml_gen_dynamic_deconstruct_args(FieldGen,
NonTagwordRHSVarRepns, NonTagwordArgModes,
FirstNonTagwordArgNum, Context, [], _,
NonTagwordDefns, NonTagwordStmts, !Info),
Defns = TagwordDefns ++ NonTagwordDefns,
Stmts = TagwordStmts ++ NonTagwordStmts
;
TagwordArgs = no,
FirstNonTagwordArgNum = 1,
ml_gen_dynamic_deconstruct_args(FieldGen, RHSVarRepns, ArgModes,
FirstNonTagwordArgNum, Context, [], _, Defns, Stmts, !Info)
)
;
ConsTag = local_args_tag(LocalArgsTagInfo),
ml_gen_info_get_var_table(!.Info, VarTable),
lookup_var_entry(VarTable, LHSVar, LHSVarEntry),
ml_gen_var(!.Info, LHSVar, LHSVarEntry, LHSVarLval),
ml_gen_info_get_module_info(!.Info, ModuleInfo),
get_cons_repn_defn_det(ModuleInfo, ConsId, ConsRepnDefn),
CtorArgRepns = ConsRepnDefn ^ cr_args,
assoc_list.from_corresponding_lists(RHSVars, CtorArgRepns,
RHSVarRepns),
local_primsectag_filled_bitfield(!.Info, LocalArgsTagInfo,
TagFilledBitfield),
ml_gen_deconstruct_tagword_args(LHSVarLval, ml_lval(LHSVarLval),
mlds_builtin_type_int(int_type_uint), TagFilledBitfield,
RHSVarRepns, ArgModes, Context, Defns, Stmts, !Info)
).
:- pred ml_gen_deconstruct_tagword_args(mlds_lval::in, mlds_rval::in,
mlds_type::in, filled_bitfield::in,
assoc_list(prog_var, constructor_arg_repn)::in, list(unify_mode)::in,
prog_context::in,
list(mlds_local_var_defn)::out, list(mlds_stmt)::out,
ml_gen_info::in, ml_gen_info::out) is det.
ml_gen_deconstruct_tagword_args(LHSTagwordLval, CastTagwordRval,
TagwordType, TagFilledBitfield, RHSVarRepns, ArgModes,
Context, Defns, Stmts, !Info) :-
ml_gen_deconstruct_tagword_args_loop(!.Info, CastTagwordRval,
RHSVarRepns, ArgModes, Context, [], ToOrRvals, 0u, ToOrMask,
[], RevArgFilledBitfields,
all_partials_assign_right, AllPartialsRight, RightStmts),
(
AllPartialsRight = all_partials_assign_right,
expect(unify(ToOrRvals, []), $pred,
"all_partials_assign_right but ToOrRvals != []"),
list.reverse(RevArgFilledBitfields, ArgFilledBitfields),
FilledBitfields = [TagFilledBitfield | ArgFilledBitfields],
record_packed_word(FilledBitfields, CastTagwordRval, Context,
Defns, WordVarStmts, !Info),
Stmts = WordVarStmts ++ RightStmts
;
AllPartialsRight = not_all_partials_assign_right,
% We could think about adding calling record_packed_word on the
% (updated version of) the LHS word. It may help optimize some later
% construction unifications, though this is far less likely to happen
% than with all_partials_assign_right deconstructions. (The common
% use case motivating calls to record_packed_word, field updates,
% always leads to all_partials_assign_right deconstructions.)
(
ToOrRvals = [],
% If the unifications of some arguments assign to the left,
% but the value being assigned to the left is zero, then
% we do not include it in ToOrRvals. Thus it is possible
% for ToOrRvals to be empty.
Defns = [],
Stmts = RightStmts
;
ToOrRvals = [HeadToOrRval | TailToOrRvals],
Defns = [],
ToOrRval = ml_bitwise_or_some_rvals(HeadToOrRval, TailToOrRvals),
ComplementMask = ml_const(mlconst_uint(\ ToOrMask)),
MaskedOldTagwordRval = ml_binop(bitwise_and(int_type_uint),
CastTagwordRval, ComplementMask),
NewTagwordRval = ml_binop(bitwise_or(int_type_uint),
MaskedOldTagwordRval, ToOrRval),
( if TagwordType = mlds_builtin_type_int(int_type_uint) then
CastNewTagwordRval = NewTagwordRval
else
CastNewTagwordRval = ml_cast(TagwordType, NewTagwordRval)
),
LeftStmt =
ml_gen_assign(LHSTagwordLval, CastNewTagwordRval, Context),
Stmts = [LeftStmt | RightStmts]
)
).
ml_gen_dynamic_deconstruct_args(_, [], [], _, _, TakeAddr,
[], [], [], !Info) :-
expect(unify(TakeAddr, []), $pred, "TakeAddr != []").
ml_gen_dynamic_deconstruct_args(_, [], [_ | _], _, _, _, _, _, _, !Info) :-
unexpected($pred, "length mismatch").
ml_gen_dynamic_deconstruct_args(_, [_ | _], [], _, _, _, _, _, _, !Info) :-
unexpected($pred, "length mismatch").
ml_gen_dynamic_deconstruct_args(FieldGen,
[ArgVarRepn | ArgVarRepns], [ArgMode | ArgModes], CurArgNum,
Context, TakeAddr, TakeAddrInfos, Defns, Stmts, !Info) :-
ArgVarRepn = ArgVar - CtorArgRepn,
NextArgNum = CurArgNum + 1,
ArgPosWidth = CtorArgRepn ^ car_pos_width,
( if
TakeAddr = [CurArgNum | TailTakeAddr]
then
( if ArgPosWidth = apw_full(_, CellOffsetPrime) then
CellOffset = CellOffsetPrime
else
unexpected($pred,
"taking address of something other than a full word")
),
ml_gen_take_addr_of_arg(!.Info, ArgVar, CtorArgRepn,
CellOffset, TakeAddrInfo),
ml_gen_dynamic_deconstruct_args(FieldGen, ArgVarRepns, ArgModes,
NextArgNum, Context, TailTakeAddr, TakeAddrInfosTail,
Defns, Stmts, !Info),
TakeAddrInfos = [TakeAddrInfo | TakeAddrInfosTail]
else if
ArgPosWidth = apw_partial_first(_, CellOffset, _, _, _, _),
% Without field_via_offset, we have no way to get a whole word
% from a memory cell at once.
FieldGen = field_gen(_MaybePtag, _AddrRval, _AddrType, FieldVia),
FieldVia = field_via_offset
then
ml_gen_dynamic_deconstruct_args_in_word(FieldGen,
ArgVar, CtorArgRepn, ArgMode,
ArgVarRepns, ArgModes, LeftOverArgVarRepns, LeftOverArgModes,
CurArgNum, LeftOverArgNum,
CellOffset, Context, TakeAddr, HeadDefns, HeadStmts, !Info),
ml_gen_dynamic_deconstruct_args(FieldGen,
LeftOverArgVarRepns, LeftOverArgModes, LeftOverArgNum,
Context, TakeAddr, TakeAddrInfos, TailDefns, TailStmts, !Info),
Defns = HeadDefns ++ TailDefns,
Stmts = HeadStmts ++ TailStmts
else
ml_gen_dynamic_deconstruct_arg(FieldGen, ArgVar, CtorArgRepn, ArgMode,
CurArgNum, Context, _FilledBitfields, HeadStmts, !Info),
ml_gen_dynamic_deconstruct_args(FieldGen, ArgVarRepns, ArgModes,
NextArgNum, Context, TakeAddr, TakeAddrInfos,
Defns, TailStmts, !Info),
Stmts = HeadStmts ++ TailStmts
).
:- pred ml_gen_dynamic_deconstruct_args_in_word(field_gen,
prog_var, constructor_arg_repn, unify_mode,
assoc_list(prog_var, constructor_arg_repn), list(unify_mode),
assoc_list(prog_var, constructor_arg_repn), list(unify_mode),
int, int, cell_offset, prog_context, list(int),
list(mlds_local_var_defn), list(mlds_stmt), ml_gen_info, ml_gen_info).
:- mode ml_gen_dynamic_deconstruct_args_in_word(in, in, in, in, in, in,
out, out, in, out, in, in, in(bound([])), out, out, in, out) is det.
:- mode ml_gen_dynamic_deconstruct_args_in_word(in, in, in, in, in, in,
out, out, in, out, in, in, in, out, out, in, out) is det.
ml_gen_dynamic_deconstruct_args_in_word(FieldGen, ArgVar, CtorArgRepn, ArgMode,
ArgVarRepns, ArgModes, LeftOverArgVarRepns, LeftOverArgModes,
CurArgNum, LeftOverArgNum, CellOffset, Context, TakeAddr,
Defns, Stmts, !Info) :-
ml_gen_dynamic_deconstruct_arg(FieldGen, ArgVar, CtorArgRepn, ArgMode,
CurArgNum, Context, FirstFilledBitfields, HeadStmts, !Info),
(
FirstFilledBitfields = [],
AllPartialsRight0 = not_all_partials_assign_right
;
FirstFilledBitfields = [_ | _],
AllPartialsRight0 = all_partials_assign_right
),
NextArgNum = CurArgNum + 1,
ml_gen_dynamic_deconstruct_args_in_word_loop(FieldGen,
ArgVarRepns, ArgModes, LeftOverArgVarRepns, LeftOverArgModes,
NextArgNum, LeftOverArgNum,
Context, TakeAddr, AllPartialsRight0, AllPartialsRight,
LaterFilledBitfields, TailStmts, !Info),
% XXX ARG_PACK
% We could get ml_gen_dynamic_deconstruct_args_in_word_loop to tell us
% when all the args in the word assign left, as in that case,
% we could generate better code than the one generated by
% ml_gen_dynamic_deconstruct_arg_unify_assign_left.
Stmts0 = HeadStmts ++ TailStmts,
(
AllPartialsRight = not_all_partials_assign_right,
Defns = [],
Stmts = Stmts0
;
AllPartialsRight = all_partials_assign_right,
FilledBitfields = FirstFilledBitfields ++ LaterFilledBitfields,
CellOffset = cell_offset(CellOffsetInt),
FieldId = ml_field_offset(ml_const(mlconst_int(CellOffsetInt))),
FieldGen = field_gen(MaybePtag, AddrRval, AddrType, _),
FieldLval = ml_field(MaybePtag, AddrRval, AddrType, FieldId,
mlds_generic_type),
WordRval = ml_lval(FieldLval),
record_packed_word(FilledBitfields, WordRval, Context,
Defns, WordVarStmts, !Info),
Stmts = WordVarStmts ++ Stmts0
).
:- pred record_packed_word(list(filled_bitfield)::in, mlds_rval::in,
prog_context::in, list(mlds_local_var_defn)::out, list(mlds_stmt)::out,
ml_gen_info::in, ml_gen_info::out) is det.
record_packed_word(FilledBitfields, WordRval, Context,
WordVarDefns, WordVarStmts, !Info) :-
(
FilledBitfields = [],
WordVarDefns = [],
WordVarStmts = []
;
FilledBitfields = [HeadFilledBitfields | TailFilledBitfields],
ml_gen_info_new_packed_word_var(WordCompVar, !Info),
WordVar = lvn_comp_var(WordCompVar),
WordVarType = mlds_builtin_type_int(int_type_uint),
WordVarDefn = mlds_local_var_defn(WordVar, Context, WordVarType,
no_initializer, gc_no_stmt),
WordVarDefns = [WordVarDefn],
WordVarLval = ml_local_var(WordVar, WordVarType),
CastWordRval = ml_cast(WordVarType, WordRval),
WordAssignStmt = ml_gen_assign(WordVarLval, CastWordRval, Context),
WordVarStmts = [WordAssignStmt],
get_unfilled_filled_packed_words(
HeadFilledBitfields, TailFilledBitfields,
PackedWord, FilledPackedWord),
Instance = packed_word_instance(FilledPackedWord,
ml_lval(WordVarLval)),
ml_gen_info_get_packed_word_map(!.Info, PackedWordMap0),
% Since this unification *defines* the variables in PackedArgVars,
% none of them could have defined by another deconstruction
% unification earlier on this path. However, there may have been
% previous deconstruction unifications that involved the same
% packing scheme.
( if map.search(PackedWordMap0, PackedWord, OldInstances) then
OldInstances = one_or_more(HeadOldInstance, TailOldInstances),
NewInstances = one_or_more(Instance,
[HeadOldInstance | TailOldInstances]),
map.det_update(PackedWord, NewInstances,
PackedWordMap0, PackedWordMap)
else
map.det_insert(PackedWord, one_or_more(Instance, []),
PackedWordMap0, PackedWordMap)
),
ml_gen_info_set_packed_word_map(PackedWordMap, !Info)
).
:- type do_all_partials_assign_right
---> not_all_partials_assign_right
; all_partials_assign_right.
:- pred ml_gen_dynamic_deconstruct_args_in_word_loop(field_gen,
assoc_list(prog_var, constructor_arg_repn), list(unify_mode),
assoc_list(prog_var, constructor_arg_repn), list(unify_mode),
int, int, prog_context, list(int),
do_all_partials_assign_right, do_all_partials_assign_right,
list(filled_bitfield), list(mlds_stmt), ml_gen_info, ml_gen_info).
:- mode ml_gen_dynamic_deconstruct_args_in_word_loop(in, in, in, out, out,
in, out, in, in(bound([])), in, out, out, out, in, out) is det.
:- mode ml_gen_dynamic_deconstruct_args_in_word_loop(in, in, in, out, out,
in, out, in, in, in, out, out, out, in, out) is det.
ml_gen_dynamic_deconstruct_args_in_word_loop(_FieldGen, [], [], [], [],
CurArgNum, LeftOverArgNum,
_Context, _TakeAddr, !AllPartialsRight, [], [], !Info) :-
LeftOverArgNum = CurArgNum.
ml_gen_dynamic_deconstruct_args_in_word_loop(_FieldGen, [], [_ | _], _, _,
_, _, _, _, !AllPartialsRight, _, _, !Info) :-
unexpected($pred, "length mismatch").
ml_gen_dynamic_deconstruct_args_in_word_loop(_FieldGen, [_ | _], [], _, _,
_, _, _, _, !AllPartialsRight, _, _, !Info) :-
unexpected($pred, "length mismatch").
ml_gen_dynamic_deconstruct_args_in_word_loop(FieldGen,
[ArgVarRepn | ArgVarRepns], [ArgMode | ArgModes],
LeftOverArgVarRepns, LeftOverArgModes, CurArgNum, LeftOverArgNum,
Context, TakeAddr, !AllPartialsRight,
FilledBitfields, Stmts, !Info) :-
ArgVarRepn = ArgVar - CtorArgRepn,
ArgPosWidth = CtorArgRepn ^ car_pos_width,
(
(
ArgPosWidth = apw_partial_shifted(_, _, _, _, _, _),
ml_gen_dynamic_deconstruct_arg(FieldGen, ArgVar, CtorArgRepn,
ArgMode, CurArgNum, Context,
HeadFilledBitfields, HeadStmts, !Info),
(
HeadFilledBitfields = [],
!:AllPartialsRight = not_all_partials_assign_right
;
HeadFilledBitfields = [_ | _]
)
;
ArgPosWidth = apw_none_shifted(_, _),
ml_gen_dynamic_deconstruct_arg(FieldGen, ArgVar, CtorArgRepn,
ArgMode, CurArgNum, Context,
HeadFilledBitfields, HeadStmts, !Info),
expect(unify(HeadFilledBitfields, []), $pred,
"HeadFilledBitfields != [] for apw_none_shifted")
),
( if TakeAddr = [CurArgNum | _TailTakeAddr] then
unexpected($pred,
"taking address of something other than a full word")
else
true
),
NextArgNum = CurArgNum + 1,
ml_gen_dynamic_deconstruct_args_in_word_loop(FieldGen,
ArgVarRepns, ArgModes, LeftOverArgVarRepns, LeftOverArgModes,
NextArgNum, LeftOverArgNum,
Context, TakeAddr, !AllPartialsRight,
TailFilledBitfields, TailStmts, !Info),
FilledBitfields = HeadFilledBitfields ++ TailFilledBitfields,
Stmts = HeadStmts ++ TailStmts
;
( ArgPosWidth = apw_full(_, _)
; ArgPosWidth = apw_double(_, _, _)
; ArgPosWidth = apw_partial_first(_, _, _, _, _, _)
; ArgPosWidth = apw_none_nowhere
),
LeftOverArgVarRepns = [ArgVarRepn | ArgVarRepns],
LeftOverArgModes = [ArgMode | ArgModes],
LeftOverArgNum = CurArgNum,
FilledBitfields = [],
Stmts = []
).
:- pred ml_gen_dynamic_deconstruct_arg(field_gen::in,
prog_var::in, constructor_arg_repn::in, unify_mode::in,
int::in, prog_context::in,
list(filled_bitfield)::out, list(mlds_stmt)::out,
ml_gen_info::in, ml_gen_info::out) is det.
ml_gen_dynamic_deconstruct_arg(FieldGen, ArgVar, CtorArgRepn, ArgMode,
ArgNum, Context, FilledBitfields, Stmts, !Info) :-
FieldGen = field_gen(MaybePrimaryTag, AddrRval, AddrType, FieldVia),
ArgPosWidth = CtorArgRepn ^ car_pos_width,
(
FieldVia = field_via_offset,
(
( ArgPosWidth = apw_full(_, CellOffset)
; ArgPosWidth = apw_double(_, CellOffset, _)
; ArgPosWidth = apw_partial_first(_, CellOffset, _, _, _, _)
; ArgPosWidth = apw_partial_shifted(_, CellOffset, _, _, _, _)
; ArgPosWidth = apw_none_shifted(_, CellOffset)
),
CellOffset = cell_offset(CellOffsetInt)
;
ArgPosWidth = apw_none_nowhere,
% The FieldId we generate from this will *not* be used.
CellOffsetInt = -1
),
FieldId = ml_field_offset(ml_const(mlconst_int(CellOffsetInt)))
;
FieldVia = field_via_name(FieldQualifier, ClassPtrType),
MaybeFieldName = CtorArgRepn ^ car_field_name,
FieldName = ml_gen_hld_field_name(MaybeFieldName, ArgNum),
QualifiedFieldName =
qual_field_var_name(FieldQualifier, type_qual, FieldName),
FieldId = ml_field_named(QualifiedFieldName, ClassPtrType)
),
% Box the field type, if needed.
% XXX ARG_PACK For sub-word-sized fields, this should *never* be needed,
% so we should do this only for full- and double-word arguments.
ml_gen_info_get_module_info(!.Info, ModuleInfo),
ml_gen_info_get_high_level_data(!.Info, HighLevelData),
FieldWidth = arg_pos_width_to_width_only(ArgPosWidth),
FieldRawType = CtorArgRepn ^ car_type,
ml_type_as_field(ModuleInfo, HighLevelData, FieldRawType, FieldWidth,
FieldType),
% Generate lvals for the LHS ...
ml_gen_mlds_type(!.Info, FieldType, MLDS_FieldType),
FieldLval = ml_field(MaybePrimaryTag, AddrRval, AddrType,
FieldId, MLDS_FieldType),
% ... and the RHS.
ml_gen_info_get_var_table(!.Info, VarTable),
lookup_var_entry(VarTable, ArgVar, ArgVarEntry),
ml_gen_var(!.Info, ArgVar, ArgVarEntry, ArgLval),
ArgType = ArgVarEntry ^ vte_type,
% Now generate code to unify them.
% Figure out the direction of data-flow from the mode,
% and generate code accordingly.
%
% Note that in some cases, the code we generate assigns to a variable
% that is never referred to. This happens quite often for deconstruct
% unifications that implement field access; the argument variables that
% correspond to the fields other than the one being accessed end up
% being assigned to but not used. While we generate suboptimal C code,
% ml_unused_assign.m can delete both the unused assignments, and the
% declarations of the unused variables, in most cases.
ml_compute_assign_direction(ModuleInfo, ArgMode, FieldType, ArgVarEntry,
Dir),
(
Dir = assign_nondummy_right,
ml_gen_dynamic_deconstruct_arg_unify_assign_right(ModuleInfo,
FieldLval, FieldType, ArgVar, ArgLval, ArgType, ArgPosWidth,
Context, FilledBitfields, Stmts)
;
Dir = assign_nondummy_left,
FilledBitfields = [],
ml_gen_dynamic_deconstruct_arg_unify_assign_left(ModuleInfo,
HighLevelData, FieldLval, FieldType, ArgLval, ArgType,
ArgPosWidth, Context, Stmts)
;
( Dir = assign_nondummy_unused
; Dir = assign_dummy
),
% The unification has no effect.
FilledBitfields = [],
Stmts = []
).
:- pred ml_gen_dynamic_deconstruct_arg_unify_assign_right(module_info::in,
mlds_lval::in, mer_type::in, prog_var::in, mlds_lval::in, mer_type::in,
arg_pos_width::in, prog_context::in,
list(filled_bitfield)::out, list(mlds_stmt)::out) is det.
ml_gen_dynamic_deconstruct_arg_unify_assign_right(ModuleInfo,
LHSLval, LHSType, RHSVar, RHSLval, RHSType, ArgPosWidth,
Context, FilledBitfields, Stmts) :-
(
ArgPosWidth = apw_double(_, _, _),
FilledBitfields = [],
( if ml_field_offset_pair(LHSLval, LHSLvalA, LHSLvalB) then
LHSRval = ml_binop(float_from_dword,
ml_lval(LHSLvalA), ml_lval(LHSLvalB))
else
ml_gen_box_or_unbox_rval(ModuleInfo, LHSType, RHSType,
bp_native_if_possible, ml_lval(LHSLval), LHSRval)
),
Stmt = ml_gen_assign(RHSLval, LHSRval, Context),
Stmts = [Stmt]
;
ArgPosWidth = apw_full(_, _),
FilledBitfields = [],
ml_gen_box_or_unbox_rval(ModuleInfo, LHSType, RHSType,
bp_native_if_possible, ml_lval(LHSLval), LHSRval),
Stmt = ml_gen_assign(RHSLval, LHSRval, Context),
Stmts = [Stmt]
;
(
ArgPosWidth = apw_partial_first(_, _, Shift, NumBits, Mask, Fill)
;
ArgPosWidth = apw_partial_shifted(_, _, Shift, NumBits, Mask, Fill)
),
Bitfield = bitfield(Shift, NumBits, Fill),
FilledBitfields = [filled_bitfield(Bitfield, bv_var(RHSVar))],
ml_extract_subword_value(ml_lval(LHSLval), Shift, Mask, Fill,
ToAssignRval),
Stmt = ml_gen_assign(RHSLval, ToAssignRval, Context),
Stmts = [Stmt]
;
( ArgPosWidth = apw_none_nowhere
; ArgPosWidth = apw_none_shifted(_, _)
),
% Generate no code.
FilledBitfields = [],
Stmts = []
).
:- pred ml_gen_dynamic_deconstruct_arg_unify_assign_left(module_info::in,
bool::in, mlds_lval::in, mer_type::in, mlds_lval::in, mer_type::in,
arg_pos_width::in, prog_context::in, list(mlds_stmt)::out) is det.
ml_gen_dynamic_deconstruct_arg_unify_assign_left(ModuleInfo, HighLevelData,
LHSLval, LHSType, RHSLval, RHSType, ArgPosWidth, Context, Stmts) :-
(
ArgPosWidth = apw_double(_, _, _),
ml_gen_box_or_unbox_rval(ModuleInfo, RHSType, LHSType,
bp_native_if_possible, ml_lval(RHSLval), RHSRval),
( if ml_field_offset_pair(LHSLval, LHSLvalA, LHSLvalB) then
FloatWordA = ml_unop(dword_float_get_word0, RHSRval),
FloatWordB = ml_unop(dword_float_get_word1, RHSRval),
ml_type_as_field(ModuleInfo, HighLevelData, int_type,
aw_full_word, IntLHSType),
ml_gen_box_or_unbox_rval(ModuleInfo, int_type, IntLHSType,
bp_native_if_possible, FloatWordA, RHSRvalA),
ml_gen_box_or_unbox_rval(ModuleInfo, int_type, IntLHSType,
bp_native_if_possible, FloatWordB, RHSRvalB),
StmtA = ml_gen_assign(LHSLvalA, RHSRvalA, Context),
StmtB = ml_gen_assign(LHSLvalB, RHSRvalB, Context),
Stmts = [StmtA, StmtB]
else
Stmt = ml_gen_assign(LHSLval, RHSRval, Context),
Stmts = [Stmt]
)
;
ArgPosWidth = apw_full(_, _),
ml_gen_box_or_unbox_rval(ModuleInfo, RHSType, LHSType,
bp_native_if_possible, ml_lval(RHSLval), RHSRval),
Stmt = ml_gen_assign(LHSLval, RHSRval, Context),
Stmts = [Stmt]
;
(
ArgPosWidth = apw_partial_first(_, _, Shift, _, Mask, Fill)
;
ArgPosWidth = apw_partial_shifted(_, _, Shift, _, Mask, Fill)
),
% XXX ARG_PACK Optimize this when replacing the whole word.
RHSRval = ml_lval(RHSLval),
Shift = arg_shift(ShiftInt),
Mask = arg_mask(MaskInt),
CastLHSRVal = ml_unbox(mlds_builtin_type_int(int_type_uint),
ml_lval(LHSLval)),
OldLHSBits = ml_bitwise_mask(CastLHSRVal, \ (MaskInt << ShiftInt)),
NewLHSBits = ml_left_shift_rval(RHSRval, Shift, Fill),
UpdatedLHSBits = ml_cast(mlds_generic_type,
ml_bitwise_or_two_rvals(OldLHSBits, NewLHSBits)),
Stmt = ml_gen_assign(LHSLval, UpdatedLHSBits, Context),
Stmts = [Stmt]
;
( ArgPosWidth = apw_none_shifted(_, _)
; ArgPosWidth = apw_none_nowhere
),
% Nothing to do.
Stmts = []
).
:- pred ml_gen_deconstruct_tagword_args_loop(ml_gen_info::in, mlds_rval::in,
assoc_list(prog_var, constructor_arg_repn)::in, list(unify_mode)::in,
prog_context::in,
list(mlds_rval)::in, list(mlds_rval)::out, uint::in, uint::out,
list(filled_bitfield)::in, list(filled_bitfield)::out,
do_all_partials_assign_right::in, do_all_partials_assign_right::out,
list(mlds_stmt)::out) is det.
ml_gen_deconstruct_tagword_args_loop(_, _, [], [],
_, !ToOrRvals, !ToOrMask, !RevFilledBitfields, !AllPartialsRight, []).
ml_gen_deconstruct_tagword_args_loop(_, _, [], [_ | _],
_, !ToOrRvals, !ToOrMask, !RevFilledBitfields, !AllPartialsRight, _) :-
unexpected($pred, "length mismatch").
ml_gen_deconstruct_tagword_args_loop(_, _, [_ | _], [],
_, !ToOrRvals, !ToOrMask, !RevFilledBitfields, !AllPartialsRight, _) :-
unexpected($pred, "length mismatch").
ml_gen_deconstruct_tagword_args_loop(Info, WordRval,
[ArgVarRepn | ArgVarRepns], [ArgMode | ArgModes],
Context, !ToOrRvals, !ToOrMask,
!RevFilledBitfields, !AllPartialsRight, Stmts) :-
ml_gen_deconstruct_tagword_arg(Info, WordRval, ArgVarRepn, ArgMode,
Context, !ToOrRvals, !ToOrMask,
!RevFilledBitfields, !AllPartialsRight, HeadStmts),
ml_gen_deconstruct_tagword_args_loop(Info, WordRval, ArgVarRepns, ArgModes,
Context, !ToOrRvals, !ToOrMask,
!RevFilledBitfields, !AllPartialsRight, TailStmts),
Stmts = HeadStmts ++ TailStmts.
:- pred ml_gen_deconstruct_tagword_arg(ml_gen_info::in, mlds_rval::in,
pair(prog_var, constructor_arg_repn)::in, unify_mode::in, prog_context::in,
list(mlds_rval)::in, list(mlds_rval)::out, uint::in, uint::out,
list(filled_bitfield)::in, list(filled_bitfield)::out,
do_all_partials_assign_right::in, do_all_partials_assign_right::out,
list(mlds_stmt)::out) is det.
ml_gen_deconstruct_tagword_arg(Info, WordRval, ArgVar - CtorArgRepn, ArgMode,
Context, !ToOrRvals, !ToOrMask,
!RevFilledBitfields, !AllPartialsRight, Stmts) :-
ml_gen_info_get_var_table(Info, VarTable),
lookup_var_entry(VarTable, ArgVar, ArgVarEntry),
ml_gen_var(Info, ArgVar, ArgVarEntry, ArgLval),
ml_gen_info_get_module_info(Info, ModuleInfo),
ml_gen_info_get_high_level_data(Info, HighLevelData),
ArgPosWidth = CtorArgRepn ^ car_pos_width,
FieldWidth = arg_pos_width_to_width_only(ArgPosWidth),
FieldRawType = CtorArgRepn ^ car_type,
ml_type_as_field(ModuleInfo, HighLevelData, FieldRawType, FieldWidth,
FieldType),
ml_compute_assign_direction(ModuleInfo, ArgMode, FieldType, ArgVarEntry,
Dir),
(
Dir = assign_nondummy_right,
ml_gen_deconstruct_tagword_arg_assign_right(WordRval,
ArgPosWidth, ArgVar, ArgLval, Context, !RevFilledBitfields, Stmts)
;
Dir = assign_nondummy_left,
ml_gen_deconstruct_tagword_arg_assign_left(WordRval,
ArgPosWidth, ArgLval, !ToOrRvals, !ToOrMask),
!:AllPartialsRight = not_all_partials_assign_right,
Stmts = []
;
( Dir = assign_nondummy_unused
; Dir = assign_dummy
),
% The unification has no effect.
!:AllPartialsRight = not_all_partials_assign_right,
Stmts = []
).
:- pred ml_gen_deconstruct_tagword_arg_assign_right(mlds_rval::in,
arg_pos_width::in, prog_var::in, mlds_lval::in, prog_context::in,
list(filled_bitfield)::in, list(filled_bitfield)::out,
list(mlds_stmt)::out) is det.
ml_gen_deconstruct_tagword_arg_assign_right(WordRval, ArgPosWidth,
ArgVar, ArgLval, Context, !RevFilledBitfields, Stmts) :-
(
ArgPosWidth = apw_partial_shifted(_, _, Shift, NumBits, Mask, Fill),
Bitfield = bitfield(Shift, NumBits, Fill),
BitfieldValue = bv_var(ArgVar),
FilledBitfield = filled_bitfield(Bitfield, BitfieldValue),
!:RevFilledBitfields = [FilledBitfield | !.RevFilledBitfields],
ml_extract_subword_value(WordRval, Shift, Mask, Fill, ToAssignRval),
Stmt = ml_gen_assign(ArgLval, ToAssignRval, Context),
Stmts = [Stmt]
;
ArgPosWidth = apw_none_shifted(_, _),
% The value being assigned is of a dummy type, so no assignment
% is actually necessary.
Stmts = []
;
( ArgPosWidth = apw_double(_, _, _)
; ArgPosWidth = apw_full(_, _)
; ArgPosWidth = apw_partial_first(_, _, _, _, _, _)
; ArgPosWidth = apw_none_nowhere
),
unexpected($pred, "ArgPosWidth does not belong in tagword")
).
:- pred ml_gen_deconstruct_tagword_arg_assign_left(mlds_rval::in,
arg_pos_width::in, mlds_lval::in,
list(mlds_rval)::in, list(mlds_rval)::out, uint::in, uint::out) is det.
ml_gen_deconstruct_tagword_arg_assign_left(_WordRval, ArgPosWidth, ArgLval,
!ToOrRvals, !ToOrMask) :-
(
ArgPosWidth = apw_partial_shifted(_, _, Shift, _NumBits, Mask, Fill),
Shift = arg_shift(ShiftInt),
Mask = arg_mask(MaskInt),
LeftShiftedArgRval = ml_left_shift_rval(ml_lval(ArgLval), Shift, Fill),
!:ToOrRvals = [LeftShiftedArgRval | !.ToOrRvals],
!:ToOrMask = (uint.cast_from_int(MaskInt) << ShiftInt) \/ !.ToOrMask
;
ArgPosWidth = apw_none_shifted(_, _)
% The value being assigned is of a dummy type, so no assignment
% is actually necessary.
;
( ArgPosWidth = apw_double(_, _, _)
; ArgPosWidth = apw_full(_, _)
; ArgPosWidth = apw_partial_first(_, _, _, _, _, _)
; ArgPosWidth = apw_none_nowhere
),
unexpected($pred, "ArgPosWidth does not belong in tagword")
).
:- pred ml_gen_dynamic_deconstruct_direct_arg(ml_gen_info::in, ptag::in,
prog_var::in, prog_var::in, unify_mode::in,
prog_context::in, list(mlds_stmt)::out) is det.
ml_gen_dynamic_deconstruct_direct_arg(Info, Ptag, LHSVar, RHSVar, ArgMode,
Context, Stmts) :-
ml_gen_info_get_var_table(Info, VarTable),
lookup_var_entry(VarTable, LHSVar, LHSVarEntry),
lookup_var_entry(VarTable, RHSVar, RHSVarEntry),
ml_gen_var(Info, LHSVar, LHSVarEntry, LHSLval),
ml_gen_var(Info, RHSVar, RHSVarEntry, RHSLval),
LHSType = LHSVarEntry ^ vte_type,
RHSType = RHSVarEntry ^ vte_type,
ml_gen_info_get_module_info(Info, ModuleInfo),
ml_compute_assign_direction(ModuleInfo, ArgMode, LHSType, RHSVarEntry,
Dir),
(
Dir = assign_nondummy_right,
ml_gen_box_or_unbox_rval(ModuleInfo, LHSType, RHSType,
bp_native_if_possible, ml_lval(LHSLval), LHSRval),
MLDS_Type = mercury_type_to_mlds_type(ModuleInfo, RHSType),
Ptag = ptag(PtagUint8),
( if PtagUint8 = 0u8 then
% Masking off the ptag would be a null operation, since it is
% already all zeroes.
CastRval = ml_cast(MLDS_Type, LHSRval)
else
PtagInt = uint8.cast_to_int(PtagUint8),
CastRval = ml_cast(MLDS_Type,
ml_binop(body, LHSRval, ml_const(mlconst_int(PtagInt))))
),
Stmt = ml_gen_assign(RHSLval, CastRval, Context),
Stmts = [Stmt]
;
Dir = assign_nondummy_left,
ml_gen_box_or_unbox_rval(ModuleInfo, RHSType, LHSType,
bp_native_if_possible, ml_lval(RHSLval), RHSRval),
MLDS_Type = mercury_type_to_mlds_type(ModuleInfo, LHSType),
CastRval = ml_cast(MLDS_Type, ml_mkword(Ptag, RHSRval)),
Stmt = ml_gen_assign(LHSLval, CastRval, Context),
Stmts = [Stmt]
;
Dir = assign_nondummy_unused,
Stmts = []
;
Dir = assign_dummy,
unexpected($pred, "dummy unify")
).
:- pred ml_gen_dynamic_deconstruct_no_tag(ml_gen_info::in,
prog_var::in, prog_var::in, unify_mode::in, prog_context::in,
list(mlds_stmt)::out) is det.
ml_gen_dynamic_deconstruct_no_tag(Info, LHSVar, RHSVar, ArgMode, Context,
Stmts) :-
ml_gen_info_get_var_table(Info, VarTable),
lookup_var_entry(VarTable, LHSVar, LHSVarEntry),
lookup_var_entry(VarTable, RHSVar, RHSVarEntry),
ml_gen_var(Info, LHSVar, LHSVarEntry, LHSLval),
ml_gen_var(Info, RHSVar, RHSVarEntry, RHSLval),
LHSType = LHSVarEntry ^ vte_type,
RHSType = RHSVarEntry ^ vte_type,
ml_gen_info_get_module_info(Info, ModuleInfo),
ml_gen_info_get_high_level_data(Info, HighLevelData),
ArgPosWidth = apw_full(arg_only_offset(0), cell_offset(0)),
ml_compute_assign_direction(ModuleInfo, ArgMode, LHSType, RHSVarEntry,
Dir),
(
Dir = assign_nondummy_right,
ml_gen_dynamic_deconstruct_arg_unify_assign_right(ModuleInfo,
LHSLval, LHSType, RHSVar, RHSLval, RHSType,
ArgPosWidth, Context, _FilledBitfields, Stmts)
;
Dir = assign_nondummy_left,
ml_gen_dynamic_deconstruct_arg_unify_assign_left(ModuleInfo,
HighLevelData, LHSLval, LHSType, RHSLval, RHSType,
ArgPosWidth, Context, Stmts)
;
( Dir = assign_nondummy_unused
; Dir = assign_dummy
),
% The unification has no effect.
Stmts = []
).
%---------------------------------------------------------------------------%
:- pred ml_gen_take_addr_of_arg(ml_gen_info::in,
prog_var::in, constructor_arg_repn::in, cell_offset::in,
take_addr_info::out) is det.
ml_gen_take_addr_of_arg(Info, ArgVar, CtorArgRepn, CurOffset, TakeAddrInfo) :-
ml_gen_info_get_module_info(Info, ModuleInfo),
ml_gen_info_get_high_level_data(Info, HighLevelData),
FieldType = CtorArgRepn ^ car_type,
ArgPosWidth = CtorArgRepn ^ car_pos_width,
FieldWidth = arg_pos_width_to_width_only(ArgPosWidth),
ml_type_as_field(ModuleInfo, HighLevelData, FieldType, FieldWidth,
BoxedFieldType),
ml_gen_mlds_type(Info, FieldType, MLDS_FieldType),
ml_gen_mlds_type(Info, BoxedFieldType, MLDS_BoxedFieldType),
TakeAddrInfo = take_addr_info(ArgVar, CurOffset, MLDS_FieldType,
MLDS_BoxedFieldType).
:- pred ml_field_offset_pair(mlds_lval::in, mlds_lval::out, mlds_lval::out)
is semidet.
ml_field_offset_pair(FieldLval, FieldLvalA, FieldLvalB) :-
FieldLval = ml_field(Ptag, PtrRval, PtrType, FieldIdA, _),
FieldIdA = ml_field_offset(FieldOffsetA),
( if FieldOffsetA = ml_const(mlconst_int(Offset)) then
FieldIdB = ml_field_offset(ml_const(mlconst_int(Offset + 1))),
SubstType = mlds_generic_type,
FieldLvalA = ml_field(Ptag, PtrRval, PtrType, FieldIdA, SubstType),
FieldLvalB = ml_field(Ptag, PtrRval, PtrType, FieldIdB, SubstType)
else
sorry($pred, "unexpected field offset")
).
:- pred ml_extract_subword_value(mlds_rval::in, arg_shift::in, arg_mask::in,
fill_kind::in, mlds_rval::out) is det.
ml_extract_subword_value(WordRval, Shift, Mask, Fill, Rval) :-
UnsignedWordRval = ml_cast(mlds_builtin_type_int(int_type_uint), WordRval),
Mask = arg_mask(MaskInt),
MaskedRval = ml_bitwise_mask(
ml_right_shift_rval(UnsignedWordRval, Shift), MaskInt),
(
( Fill = fill_enum
; Fill = fill_char21
),
Rval = MaskedRval
;
( Fill = fill_int8, CastIntType = int_type_int8
; Fill = fill_uint8, CastIntType = int_type_uint8
; Fill = fill_int16, CastIntType = int_type_int16
; Fill = fill_uint16, CastIntType = int_type_uint16
; Fill = fill_int32, CastIntType = int_type_int32
; Fill = fill_uint32, CastIntType = int_type_uint32
),
CastMLDSType = mlds_builtin_type_int(CastIntType),
Rval = ml_cast(CastMLDSType, MaskedRval)
).
%---------------------------------------------------------------------------%
:- pred ml_take_tagword_args(
assoc_list(prog_var, constructor_arg_repn)::in, list(unify_mode)::in,
assoc_list(prog_var, constructor_arg_repn)::out, list(unify_mode)::out,
assoc_list(prog_var, constructor_arg_repn)::out, list(unify_mode)::out,
int::in, int::out) is det.
ml_take_tagword_args([], [], [], [], [], [], !FirstNonTagwordArgNum).
ml_take_tagword_args([], [_ | _], _, _, _, _, !FirstNonTagwordArgNum) :-
unexpected($pred, "length mismatch").
ml_take_tagword_args([_ | _], [], _, _, _, _, !FirstNonTagwordArgNum) :-
unexpected($pred, "length mismatch").
ml_take_tagword_args([RHSVarRepn | RHSVarRepns], [ArgMode | ArgModes],
TagwordRHSVarRepns, TagwordArgModes,
NonTagwordRHSVarRepns, NonTagwordArgModes, !FirstNonTagwordArgNum) :-
RHSVarRepn = _ - Repn,
ArgPosWidth = Repn ^ car_pos_width,
(
( ArgPosWidth = apw_partial_shifted(_, _, _, _, _, _)
; ArgPosWidth = apw_none_shifted(_, _)
),
!:FirstNonTagwordArgNum = !.FirstNonTagwordArgNum + 1,
ml_take_tagword_args(RHSVarRepns, ArgModes,
TailTagwordRHSVarRepns, TailTagwordArgModes,
NonTagwordRHSVarRepns, NonTagwordArgModes,
!FirstNonTagwordArgNum),
TagwordRHSVarRepns = [RHSVarRepn | TailTagwordRHSVarRepns],
TagwordArgModes = [ArgMode | TailTagwordArgModes]
;
( ArgPosWidth = apw_full(_, _)
; ArgPosWidth = apw_double(_, _, _)
; ArgPosWidth = apw_partial_first(_, _, _, _, _, _)
; ArgPosWidth = apw_none_nowhere
),
TagwordRHSVarRepns = [],
TagwordArgModes = [],
NonTagwordRHSVarRepns = [RHSVarRepn | RHSVarRepns],
NonTagwordArgModes = [ArgMode | ArgModes]
).
%---------------------------------------------------------------------------%
:- end_module ml_backend.ml_unify_gen_deconstruct.
%---------------------------------------------------------------------------%