mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-17 18:33:58 +00:00
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.
690 lines
28 KiB
Mathematica
690 lines
28 KiB
Mathematica
%---------------------------------------------------------------------------e
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------e
|
|
% Copyright (C) 1994-2012 The University of Melbourne.
|
|
% Copyright (C) 2013-2018 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.
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module ll_backend.unify_gen_deconstruct.
|
|
:- interface.
|
|
|
|
:- import_module hlds.
|
|
:- import_module hlds.hlds_goal.
|
|
:- import_module ll_backend.code_info.
|
|
:- import_module ll_backend.code_loc_dep.
|
|
:- import_module ll_backend.llds.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.prog_data.
|
|
|
|
:- import_module list.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred generate_deconstruction_unification(prog_var::in, cons_id::in,
|
|
list(prog_var)::in, list(unify_mode)::in, can_fail::in, can_cgc::in,
|
|
llds_code::out, code_info::in, code_info::out,
|
|
code_loc_dep::in, code_loc_dep::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Generate a subunification between two [field | variable].
|
|
%
|
|
:- pred generate_deconstruct_no_tag_unify_arg(prog_var::in, prog_var::in,
|
|
mer_type::in, unify_mode::in, llds_code::out,
|
|
code_info::in, code_loc_dep::in, code_loc_dep::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_code_util.
|
|
:- import_module hlds.hlds_data.
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module libs.
|
|
:- import_module libs.globals.
|
|
:- import_module ll_backend.unify_gen_test.
|
|
:- import_module ll_backend.unify_gen_util.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module parse_tree.prog_type.
|
|
:- import_module parse_tree.var_table.
|
|
|
|
:- import_module cord.
|
|
:- import_module int.
|
|
:- import_module maybe.
|
|
:- import_module require.
|
|
:- import_module string.
|
|
:- import_module term.
|
|
:- import_module uint.
|
|
:- import_module uint8.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
generate_deconstruction_unification(LHSVar, ConsId, RHSVars, ArgModes,
|
|
CanFail, CanCGC, Code, !CI, !CLD) :-
|
|
(
|
|
CanFail = can_fail,
|
|
generate_semi_deconstruction(LHSVar, ConsId, RHSVars, ArgModes,
|
|
DeconstructCode, !CI, !CLD)
|
|
;
|
|
CanFail = cannot_fail,
|
|
generate_det_deconstruction(LHSVar, ConsId, RHSVars, ArgModes,
|
|
DeconstructCode, !.CI, !CLD)
|
|
),
|
|
(
|
|
CanCGC = can_cgc,
|
|
get_var_table(!.CI, VarTable),
|
|
lookup_var_entry(VarTable, LHSVar, LHSVarEntry),
|
|
LHSVarName = var_entry_name(LHSVar, LHSVarEntry),
|
|
produce_variable(LHSVar, ProduceVarCode, VarRval, !CLD),
|
|
( if VarRval = lval(VarLval) then
|
|
save_reused_cell_fields(LHSVar, VarLval, SaveArgsCode, Regs, !CLD),
|
|
% This seems to be fine.
|
|
list.foldl(release_reg, Regs, !CLD),
|
|
% XXX avoid strip_tag when we know what ptag it will have
|
|
FreeVarCode = singleton(
|
|
llds_instr(free_heap(unop(strip_tag, VarRval)),
|
|
"Free " ++ LHSVarName)
|
|
),
|
|
Code = DeconstructCode ++
|
|
ProduceVarCode ++ SaveArgsCode ++ FreeVarCode
|
|
else
|
|
Code = DeconstructCode
|
|
)
|
|
;
|
|
CanCGC = cannot_cgc,
|
|
Code = DeconstructCode
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Generate a semideterministic deconstruction.
|
|
% A semideterministic deconstruction unification is tag-test
|
|
% followed by a deterministic deconstruction.
|
|
%
|
|
:- pred generate_semi_deconstruction(prog_var::in, cons_id::in,
|
|
list(prog_var)::in, list(unify_mode)::in,
|
|
llds_code::out, code_info::in, code_info::out,
|
|
code_loc_dep::in, code_loc_dep::out) is det.
|
|
|
|
generate_semi_deconstruction(LHSVar, ConsId, RHSVars, Modes, Code,
|
|
!CI, !CLD) :-
|
|
produce_variable(LHSVar, LHSVarCode, LHSVarRval, !CLD),
|
|
get_var_table(!.CI, VarTable),
|
|
lookup_var_entry(VarTable, LHSVar, LHSVarEntry),
|
|
LHSVarName = var_entry_name(LHSVar, LHSVarEntry),
|
|
LHSVarType = LHSVarEntry ^ vte_type,
|
|
CheaperTagTest = lookup_cheaper_tag_test(!.CI, LHSVarType),
|
|
generate_test_var_has_cons_id(LHSVarRval, LHSVarName, ConsId,
|
|
CheaperTagTest, branch_on_success, SuccLabel, TagTestCode, !CI),
|
|
remember_position(!.CLD, AfterUnify),
|
|
generate_failure(FailCode, !CI, !.CLD),
|
|
reset_to_position(AfterUnify, !.CI, !:CLD),
|
|
generate_det_deconstruction(LHSVar, ConsId, RHSVars, Modes,
|
|
DetDeconstructCode, !.CI, !CLD),
|
|
SuccessLabelCode = singleton(llds_instr(label(SuccLabel), "")),
|
|
Code = LHSVarCode ++ TagTestCode ++ FailCode ++
|
|
SuccessLabelCode ++ DetDeconstructCode.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Generate a deterministic deconstruction. In a deterministic
|
|
% deconstruction, we know the value of the cons_id, so we don't need
|
|
% to generate a test for it.
|
|
%
|
|
% Deconstructions are generated semi-eagerly. Any test sub-unifications
|
|
% are generated eagerly (they _must_ be), but assignment unifications
|
|
% are cached.
|
|
%
|
|
:- pred generate_det_deconstruction(prog_var::in, cons_id::in,
|
|
list(prog_var)::in, list(unify_mode)::in,
|
|
llds_code::out, code_info::in, code_loc_dep::in, code_loc_dep::out) is det.
|
|
|
|
generate_det_deconstruction(LHSVar, ConsId, RHSVars, ArgModes, Code,
|
|
CI, !CLD) :-
|
|
get_module_info(CI, ModuleInfo),
|
|
ConsTag = cons_id_to_tag(ModuleInfo, ConsId),
|
|
(
|
|
( ConsTag = string_tag(_String)
|
|
; ConsTag = int_tag(_)
|
|
; ConsTag = foreign_tag(_, _)
|
|
; ConsTag = float_tag(_Float)
|
|
; ConsTag = dummy_tag
|
|
; ConsTag = closure_tag(_, _, _)
|
|
; ConsTag = type_ctor_info_tag(_, _, _)
|
|
; ConsTag = base_typeclass_info_tag(_, _, _)
|
|
; ConsTag = tabling_info_tag(_, _)
|
|
; ConsTag = deep_profiling_proc_layout_tag(_, _)
|
|
; ConsTag = shared_local_tag_no_args(_, _, _)
|
|
),
|
|
% For constants, if the deconstruction is det, then we already know
|
|
% the value of the constant.
|
|
Code = empty
|
|
;
|
|
( ConsTag = type_info_const_tag(_)
|
|
; ConsTag = typeclass_info_const_tag(_)
|
|
; ConsTag = ground_term_const_tag(_, _)
|
|
; ConsTag = table_io_entry_tag(_, _)
|
|
),
|
|
unexpected($pred, "unexpected tag")
|
|
;
|
|
ConsTag = no_tag,
|
|
get_notag_or_direct_arg_arg_mode(RHSVars, ArgModes, RHSVar, ArgMode),
|
|
VarType = variable_type(CI, LHSVar),
|
|
IsDummy = is_type_a_dummy(ModuleInfo, VarType),
|
|
(
|
|
IsDummy = is_dummy_type,
|
|
% We must handle this case specially. If we didn't, the
|
|
% generated code would copy the reference to the Var's
|
|
% current location, which may be stackvar(N) or framevar(N)
|
|
% for negative N, to be the location of Arg, and since Arg
|
|
% may not be a dummy type, it would actually use that location.
|
|
% This can happen in the unify/compare routines for e.g.
|
|
% io.state.
|
|
( if variable_is_forward_live(!.CLD, RHSVar) then
|
|
assign_const_to_var(RHSVar, const(llconst_int(0)), CI, !CLD)
|
|
else
|
|
true
|
|
),
|
|
Code = empty
|
|
;
|
|
IsDummy = is_not_dummy_type,
|
|
RHSType = variable_type(CI, RHSVar),
|
|
generate_deconstruct_no_tag_unify_arg(LHSVar, RHSVar, RHSType,
|
|
ArgMode, Code, CI, !CLD)
|
|
)
|
|
;
|
|
ConsTag = direct_arg_tag(Ptag),
|
|
get_notag_or_direct_arg_arg_mode(RHSVars, ArgModes, RHSVar, ArgMode),
|
|
generate_direct_arg_deconstruct(LHSVar, RHSVar, Ptag, ArgMode,
|
|
Code, CI, !CLD)
|
|
;
|
|
ConsTag = remote_args_tag(RemoteArgsTagInfo),
|
|
LHSBaseRval = var(LHSVar),
|
|
get_var_table(CI, VarTable),
|
|
associate_cons_id_args_with_widths(ModuleInfo, ConsId,
|
|
RHSVars, RHSVarsWidths),
|
|
(
|
|
(
|
|
RemoteArgsTagInfo = remote_args_only_functor,
|
|
LHSPtag = ptag(0u8)
|
|
;
|
|
RemoteArgsTagInfo = remote_args_unshared(LHSPtag)
|
|
),
|
|
generate_deconstruct_unify_args(VarTable, LHSPtag, LHSBaseRval,
|
|
RHSVarsWidths, ArgModes, Code, CI, !CLD)
|
|
;
|
|
RemoteArgsTagInfo = remote_args_shared(LHSPtag, RemoteSectag),
|
|
RemoteSectag = remote_sectag(_SectagUint, SectagSize),
|
|
(
|
|
SectagSize = rsectag_word,
|
|
generate_deconstruct_unify_args(VarTable, LHSPtag, LHSBaseRval,
|
|
RHSVarsWidths, ArgModes, Code, CI, !CLD)
|
|
;
|
|
SectagSize = rsectag_subword(_),
|
|
take_tagword_args(RHSVarsWidths, ArgModes,
|
|
TagwordRHSVarsWidths, TagwordArgModes,
|
|
NonTagwordRHSVarsWidths, NonTagwordArgModes),
|
|
LHSSectagWordLval = field(yes(LHSPtag), LHSBaseRval,
|
|
const(llconst_int(0))),
|
|
LHSSectagWordRval0 = lval(LHSSectagWordLval),
|
|
LHSSectagWordRval = LHSSectagWordRval0,
|
|
MaterializeTagwordCode = empty,
|
|
generate_deconstruct_tagword_unify_args(LHSSectagWordRval,
|
|
TagwordRHSVarsWidths, TagwordArgModes, [LHSSectagWordLval],
|
|
[], ToOrRvals, 0u, ToOrMask, AssignRightCode, CI, !CLD),
|
|
(
|
|
ToOrRvals = [],
|
|
TagwordCode = MaterializeTagwordCode ++ AssignRightCode
|
|
;
|
|
ToOrRvals = [HeadToOrRval | TailToOrRvals],
|
|
ToOrRval0 =
|
|
bitwise_or_some_rvals(HeadToOrRval, TailToOrRvals),
|
|
materialize_vars_in_rval(ToOrRval0, ToOrRval,
|
|
ToOrRvalCode, !CLD),
|
|
ComplementMask = const(llconst_uint(\ ToOrMask)),
|
|
MaskedOldSectagWordRval = binop(bitwise_and(int_type_uint),
|
|
lval(LHSSectagWordLval), ComplementMask),
|
|
NewSectagWordRval = binop(bitwise_or(int_type_uint),
|
|
MaskedOldSectagWordRval, ToOrRval),
|
|
Comment = "updating tagword",
|
|
AssignLeftCode = singleton(llds_instr(
|
|
assign(LHSSectagWordLval, NewSectagWordRval),
|
|
Comment)),
|
|
TagwordCode = MaterializeTagwordCode ++
|
|
AssignRightCode ++ ToOrRvalCode ++ AssignLeftCode
|
|
),
|
|
generate_deconstruct_unify_args(VarTable, LHSPtag, LHSBaseRval,
|
|
NonTagwordRHSVarsWidths, NonTagwordArgModes,
|
|
NonTagwordCode, CI, !CLD),
|
|
Code = TagwordCode ++ NonTagwordCode
|
|
)
|
|
;
|
|
RemoteArgsTagInfo = remote_args_ctor(_Data),
|
|
% These are supported only on the MLDS backend.
|
|
unexpected($pred, "remote_args_ctor")
|
|
)
|
|
;
|
|
ConsTag = local_args_tag(_),
|
|
associate_cons_id_args_with_widths(ModuleInfo, ConsId,
|
|
RHSVars, RHSVarsWidths),
|
|
generate_deconstruct_tagword_unify_args(var(LHSVar),
|
|
RHSVarsWidths, ArgModes, [], [], ToOrRvals, 0u, ToOrMask,
|
|
AssignRightCode, CI, !CLD),
|
|
(
|
|
ToOrRvals = [],
|
|
Code = AssignRightCode
|
|
;
|
|
ToOrRvals = [HeadToOrRval | TailToOrRvals],
|
|
ToOrRval = bitwise_or_some_rvals(HeadToOrRval, TailToOrRvals),
|
|
reassign_tagword_var(LHSVar, ToOrMask, ToOrRval, AssignLeftCode,
|
|
!CLD),
|
|
Code = AssignRightCode ++ AssignLeftCode
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Generate code to perform a list of deterministic subunifications
|
|
% for the arguments of a construction.
|
|
%
|
|
:- pred generate_deconstruct_unify_args(var_table::in, ptag::in, rval::in,
|
|
list(arg_and_width(prog_var))::in, list(unify_mode)::in, llds_code::out,
|
|
code_info::in, code_loc_dep::in, code_loc_dep::out) is det.
|
|
|
|
generate_deconstruct_unify_args(_, _, _, [], [], empty, _CI, !CLD).
|
|
generate_deconstruct_unify_args(_, _, _, [], [_ | _], _, _, !CLD) :-
|
|
unexpected($pred, "length mismatch").
|
|
generate_deconstruct_unify_args(_, _, _, [_ | _], [], _, _, !CLD) :-
|
|
unexpected($pred, "length mismatch").
|
|
generate_deconstruct_unify_args(VarTable, LHSPtag, LHSBaseRval,
|
|
[RHSVarLHSWidth | RHSVarsLHSWidths], [ArgMode | ArgModes],
|
|
Code, CI, !CLD) :-
|
|
RHSVarLHSWidth = arg_and_width(RHSVar, LHSArgPosWidth),
|
|
lookup_var_entry(VarTable, RHSVar, RHSVarEntry),
|
|
RHSType = RHSVarEntry ^ vte_type,
|
|
generate_deconstruct_unify_arg(LHSPtag, LHSBaseRval, LHSArgPosWidth,
|
|
RHSVar, RHSType, ArgMode, HeadCode, CI, !CLD),
|
|
generate_deconstruct_unify_args(VarTable, LHSPtag, LHSBaseRval,
|
|
RHSVarsLHSWidths, ArgModes, TailCode, CI, !CLD),
|
|
Code = HeadCode ++ TailCode.
|
|
|
|
:- pred generate_deconstruct_unify_arg(ptag::in, rval::in, arg_pos_width::in,
|
|
prog_var::in, mer_type::in, unify_mode::in, llds_code::out,
|
|
code_info::in, code_loc_dep::in, code_loc_dep::out) is det.
|
|
|
|
generate_deconstruct_unify_arg(LHSPtag, LHSBaseRval, LHSArgPosWidth,
|
|
RHSVar, RHSType, ArgMode, Code, CI, !CLD) :-
|
|
get_module_info(CI, ModuleInfo),
|
|
compute_assign_direction(ModuleInfo, ArgMode, RHSType, Dir),
|
|
(
|
|
Dir = assign_right,
|
|
( if variable_is_forward_live(!.CLD, RHSVar) then
|
|
generate_deconstruct_assign_right(LHSPtag, LHSBaseRval,
|
|
LHSArgPosWidth, RHSVar, Code, CI, !CLD)
|
|
else
|
|
Code = empty
|
|
)
|
|
;
|
|
Dir = assign_left,
|
|
% Fields are always considered forward live.
|
|
generate_deconstruct_assign_left(LHSPtag, LHSBaseRval, LHSArgPosWidth,
|
|
RHSVar, Code, !CLD)
|
|
;
|
|
Dir = assign_unused,
|
|
% XXX This will have to change if we start to support aliasing.
|
|
Code = empty
|
|
).
|
|
|
|
generate_deconstruct_no_tag_unify_arg(LHSVar, RHSVar, RHSType, ArgMode,
|
|
Code, CI, !CLD) :-
|
|
get_module_info(CI, ModuleInfo),
|
|
compute_assign_direction(ModuleInfo, ArgMode, RHSType, Dir),
|
|
(
|
|
Dir = assign_right,
|
|
( if variable_is_forward_live(!.CLD, RHSVar) then
|
|
assign_var_to_var(RHSVar, LHSVar, !CLD),
|
|
Code = empty
|
|
else
|
|
Code = empty
|
|
)
|
|
;
|
|
Dir = assign_left,
|
|
( if variable_is_forward_live(!.CLD, LHSVar) then
|
|
assign_var_to_var(LHSVar, RHSVar, !CLD)
|
|
else
|
|
true
|
|
),
|
|
Code = empty
|
|
;
|
|
Dir = assign_unused,
|
|
% XXX This will have to change if we start to support aliasing.
|
|
Code = empty
|
|
).
|
|
|
|
:- pred generate_deconstruct_tagword_unify_args(rval::in,
|
|
list(arg_and_width(prog_var))::in, list(unify_mode)::in, list(lval)::in,
|
|
list(rval)::in, list(rval)::out, uint::in, uint::out,
|
|
llds_code::out, code_info::in, code_loc_dep::in, code_loc_dep::out) is det.
|
|
|
|
generate_deconstruct_tagword_unify_args(_LHSRval, [], [], _,
|
|
!ToOrRvals, !ToOrMask, empty, _CI, !CLD).
|
|
generate_deconstruct_tagword_unify_args(_LHSRval, [], [_ | _], _,
|
|
!ToOrRvals, !ToOrMask, _, _, !CLD) :-
|
|
unexpected($pred, "length mismatch").
|
|
generate_deconstruct_tagword_unify_args(_LHSRval, [_ | _], [], _,
|
|
!ToOrRvals, !ToOrMask, _, _, !CLD) :-
|
|
unexpected($pred, "length mismatch").
|
|
generate_deconstruct_tagword_unify_args(LHSRval,
|
|
[RHSVarWidth | RHSVarsWidths], [ArgMode | ArgModes], FieldLvals,
|
|
!ToOrRvals, !ToOrMask, Code, CI, !CLD) :-
|
|
generate_deconstruct_tagword_unify_arg(LHSRval, RHSVarWidth,
|
|
ArgMode, FieldLvals, !ToOrRvals, !ToOrMask, HeadCode, CI, !CLD),
|
|
generate_deconstruct_tagword_unify_args(LHSRval, RHSVarsWidths,
|
|
ArgModes, FieldLvals, !ToOrRvals, !ToOrMask, TailCode, CI, !CLD),
|
|
Code = HeadCode ++ TailCode.
|
|
|
|
% Unify (on the left)a word containing tags and packed arguments, and
|
|
% (on the right) a sequence of argument variables. Generate code for
|
|
% the assignments to the right, and update the state variables to help
|
|
% our caller generate a single assignment to the left.
|
|
%
|
|
:- pred generate_deconstruct_tagword_unify_arg(rval::in,
|
|
arg_and_width(prog_var)::in, unify_mode::in, list(lval)::in,
|
|
list(rval)::in, list(rval)::out, uint::in, uint::out,
|
|
llds_code::out, code_info::in, code_loc_dep::in, code_loc_dep::out) is det.
|
|
|
|
generate_deconstruct_tagword_unify_arg(LHSRval, RHSVarWidth, ArgMode,
|
|
FieldLvals, !ToOrRvals, !ToOrMask, Code, CI, !CLD) :-
|
|
RHSVarWidth = arg_and_width(RHSVar, ArgPosWidth),
|
|
get_module_info(CI, ModuleInfo),
|
|
get_var_table(CI, VarTable),
|
|
lookup_var_entry(VarTable, RHSVar, RHSVarEntry),
|
|
RHSType = RHSVarEntry ^ vte_type,
|
|
compute_assign_direction(ModuleInfo, ArgMode, RHSType, Dir),
|
|
(
|
|
Dir = assign_right,
|
|
( if variable_is_forward_live(!.CLD, RHSVar) then
|
|
generate_deconstruct_tagword_assign_right(LHSRval, RHSVar,
|
|
ArgPosWidth, FieldLvals, Code, !CLD)
|
|
else
|
|
Code = empty
|
|
)
|
|
;
|
|
Dir = assign_left,
|
|
generate_deconstruct_tagword_assign_left(RHSVar, ArgPosWidth,
|
|
!ToOrRvals, !ToOrMask),
|
|
Code = empty
|
|
;
|
|
Dir = assign_unused,
|
|
% XXX This will have to change if we start to support aliasing.
|
|
Code = empty
|
|
).
|
|
|
|
:- pred generate_deconstruct_assign_right(ptag::in, rval::in,
|
|
arg_pos_width::in, prog_var::in,
|
|
llds_code::out, code_info::in, code_loc_dep::in, code_loc_dep::out) is det.
|
|
|
|
generate_deconstruct_assign_right(LHSPtag, LHSBaseRval, LHSArgPosWidth,
|
|
RHSVar, Code, CI, !CLD) :-
|
|
(
|
|
LHSArgPosWidth = apw_full(_, cell_offset(LHSCellOffset)),
|
|
LHSLval = field(yes(LHSPtag), LHSBaseRval,
|
|
const(llconst_int(LHSCellOffset))),
|
|
assign_lval_to_var(RHSVar, LHSLval, Code, CI, !CLD)
|
|
;
|
|
LHSArgPosWidth = apw_double(_, cell_offset(LHSCellOffset), _),
|
|
LHSLvalA = field(yes(LHSPtag), LHSBaseRval,
|
|
const(llconst_int(LHSCellOffset))),
|
|
LHSLvalB = field(yes(LHSPtag), LHSBaseRval,
|
|
const(llconst_int(LHSCellOffset + 1))),
|
|
LHSRval = binop(float_from_dword, lval(LHSLvalA), lval(LHSLvalB)),
|
|
assign_field_lval_expr_to_var(RHSVar, [LHSLvalA, LHSLvalB],
|
|
LHSRval, Code, !CLD)
|
|
;
|
|
(
|
|
LHSArgPosWidth = apw_partial_first(_, cell_offset(LHSCellOffset),
|
|
Shift, _, arg_mask(Mask), Fill)
|
|
;
|
|
LHSArgPosWidth = apw_partial_shifted(_, cell_offset(LHSCellOffset),
|
|
Shift, _, arg_mask(Mask), Fill)
|
|
),
|
|
LHSLval = field(yes(LHSPtag), LHSBaseRval,
|
|
const(llconst_int(LHSCellOffset))),
|
|
LHSRval0 = right_shift_rval(lval(LHSLval), Shift),
|
|
MaskedLHSRval0 = binop(bitwise_and(int_type_uint), LHSRval0,
|
|
const(llconst_int(Mask))),
|
|
maybe_cast_masked_off_rval(Fill, MaskedLHSRval0, MaskedLHSRval),
|
|
assign_field_lval_expr_to_var(RHSVar, [LHSLval], MaskedLHSRval,
|
|
Code, !CLD)
|
|
;
|
|
( LHSArgPosWidth = apw_none_nowhere
|
|
; LHSArgPosWidth = apw_none_shifted(_, _)
|
|
),
|
|
% The value being assigned is of a dummy type, so no assignment
|
|
% is actually necessary.
|
|
Code = empty
|
|
).
|
|
|
|
:- pred generate_deconstruct_tagword_assign_right(rval::in, prog_var::in,
|
|
arg_pos_width::in, list(lval)::in, llds_code::out,
|
|
code_loc_dep::in, code_loc_dep::out) is det.
|
|
|
|
generate_deconstruct_tagword_assign_right(LHSRval, RHSVar, ArgPosWidth,
|
|
FieldLvals, Code, !CLD) :-
|
|
(
|
|
ArgPosWidth = apw_partial_shifted(_, _, Shift, _, Mask, Fill),
|
|
LeftRval0 = right_shift_rval(LHSRval, Shift),
|
|
Mask = arg_mask(MaskInt),
|
|
MaskedLeftRval0 = binop(bitwise_and(int_type_uint), LeftRval0,
|
|
const(llconst_int(MaskInt))),
|
|
maybe_cast_masked_off_rval(Fill, MaskedLeftRval0, MaskedLeftRval),
|
|
(
|
|
FieldLvals = [],
|
|
assign_expr_to_var(RHSVar, MaskedLeftRval, Code, !CLD)
|
|
;
|
|
FieldLvals = [_ | _],
|
|
assign_field_lval_expr_to_var(RHSVar, FieldLvals, MaskedLeftRval,
|
|
Code, !CLD)
|
|
)
|
|
;
|
|
ArgPosWidth = apw_none_shifted(_, _),
|
|
% The value being assigned is of a dummy type, so no assignment
|
|
% is actually necessary.
|
|
Code = empty
|
|
;
|
|
( ArgPosWidth = apw_full(_, _)
|
|
; ArgPosWidth = apw_double(_, _, _)
|
|
; ArgPosWidth = apw_partial_first(_, _, _, _, _, _)
|
|
; ArgPosWidth = apw_none_nowhere
|
|
),
|
|
unexpected($pred, "ArgPosWidth does not belong in tagword")
|
|
).
|
|
|
|
:- pred generate_deconstruct_assign_left(ptag::in, rval::in, arg_pos_width::in,
|
|
prog_var::in, llds_code::out,
|
|
code_loc_dep::in, code_loc_dep::out) is det.
|
|
|
|
generate_deconstruct_assign_left(LHSPtag, LHSBaseRval0, LHSArgPosWidth,
|
|
RHSVar, Code, !CLD) :-
|
|
% Assignment from a variable to an field in a memory cell;
|
|
% we cannot cache this, so generate code for it immediately.
|
|
produce_variable(RHSVar, ProduceRHSVarCode, RHSRval, !CLD),
|
|
materialize_vars_in_rval(LHSBaseRval0, LHSBaseRval,
|
|
MaterializeLHSBaseCode, !CLD),
|
|
(
|
|
LHSArgPosWidth = apw_full(_, cell_offset(LHSCellOffset)),
|
|
LHSLval = field(yes(LHSPtag), LHSBaseRval,
|
|
const(llconst_int(LHSCellOffset))),
|
|
AssignCode = singleton(llds_instr(assign(LHSLval, RHSRval),
|
|
"Copy value"))
|
|
;
|
|
LHSArgPosWidth = apw_double(_, cell_offset(LHSCellOffset), _),
|
|
LHSLvalA = field(yes(LHSPtag), LHSBaseRval,
|
|
const(llconst_int(LHSCellOffset))),
|
|
LHSLvalB = field(yes(LHSPtag), LHSBaseRval,
|
|
const(llconst_int(LHSCellOffset + 1))),
|
|
SrcA = unop(dword_float_get_word0, RHSRval),
|
|
SrcB = unop(dword_float_get_word1, RHSRval),
|
|
Comment = "Update double word",
|
|
AssignCode = from_list([
|
|
llds_instr(assign(LHSLvalA, SrcA), Comment),
|
|
llds_instr(assign(LHSLvalB, SrcB), Comment)
|
|
])
|
|
;
|
|
(
|
|
LHSArgPosWidth = apw_partial_first(_, cell_offset(LHSCellOffset),
|
|
Shift, _, Mask, Fill)
|
|
;
|
|
LHSArgPosWidth = apw_partial_shifted(_, cell_offset(LHSCellOffset),
|
|
Shift, _, Mask, Fill)
|
|
),
|
|
Shift = arg_shift(ShiftInt),
|
|
Mask = arg_mask(MaskInt),
|
|
% XXX ARG_PACK
|
|
% In the usual case where the heap cell we are assigning to
|
|
% is freshly created, this code is *seriously* suboptimal.
|
|
% Instead of filling in the bits belonging to each variable
|
|
% as if the other bits were already there, first looking them up
|
|
% and then putting them back, we should just compute the bits
|
|
% for each variable (shifted by the appropriate amount),
|
|
% and OR them together.
|
|
LHSLval = field(yes(LHSPtag), LHSBaseRval,
|
|
const(llconst_int(LHSCellOffset))),
|
|
ComplementMask = const(llconst_int(\ (MaskInt << ShiftInt))),
|
|
MaskOld = binop(bitwise_and(int_type_uint),
|
|
lval(LHSLval), ComplementMask),
|
|
ShiftedRHSRval = left_shift_rval(RHSRval, Shift, Fill),
|
|
CombinedRval = bitwise_or_two_rvals(MaskOld, ShiftedRHSRval),
|
|
AssignCode = singleton(llds_instr(assign(LHSLval, CombinedRval),
|
|
"Update part of word"))
|
|
;
|
|
( LHSArgPosWidth = apw_none_nowhere
|
|
; LHSArgPosWidth = apw_none_shifted(_, _)
|
|
),
|
|
% The value being assigned is of a dummy type, so no assignment
|
|
% is actually necessary.
|
|
% XXX Should we try to avoid generating ProduceRHSVarCode
|
|
% and MaterializeLHSBaseCode as well? MaterializeLHSBaseCode
|
|
% is probably needed by other, non-dummy fields, and
|
|
% ProduceRHSVarCode is probably very cheap, so probably not.
|
|
AssignCode = empty
|
|
),
|
|
Code = ProduceRHSVarCode ++ MaterializeLHSBaseCode ++ AssignCode.
|
|
|
|
:- pred generate_deconstruct_tagword_assign_left(prog_var::in,
|
|
arg_pos_width::in,
|
|
list(rval)::in, list(rval)::out, uint::in, uint::out) is det.
|
|
|
|
generate_deconstruct_tagword_assign_left(RHSVar, ArgPosWidth,
|
|
!ToOrRvals, !ToOrMask) :-
|
|
(
|
|
ArgPosWidth = apw_partial_shifted(_, _, Shift, _, Mask, Fill),
|
|
Shift = arg_shift(ShiftInt),
|
|
Mask = arg_mask(MaskInt),
|
|
LeftShiftedRHSRval = left_shift_rval(var(RHSVar), Shift, Fill),
|
|
!:ToOrRvals = [LeftShiftedRHSRval | !.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_full(_, _)
|
|
; ArgPosWidth = apw_double(_, _, _)
|
|
; ArgPosWidth = apw_partial_first(_, _, _, _, _, _)
|
|
; ArgPosWidth = apw_none_nowhere
|
|
),
|
|
unexpected($pred, "ArgPosWidth is not a packed arg_pos_width")
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred take_tagword_args(
|
|
list(arg_and_width(prog_var))::in, list(unify_mode)::in,
|
|
list(arg_and_width(prog_var))::out, list(unify_mode)::out,
|
|
list(arg_and_width(prog_var))::out, list(unify_mode)::out) is det.
|
|
|
|
take_tagword_args([], [], [], [], [], []).
|
|
take_tagword_args([], [_ | _], _, _, _, _) :-
|
|
unexpected($pred, "length mismatch").
|
|
take_tagword_args([_ | _], [], _, _, _, _) :-
|
|
unexpected($pred, "length mismatch").
|
|
take_tagword_args([VarWidth | VarsWidths], [ArgMode | ArgModes],
|
|
TagwordVarsWidths, TagwordArgModes,
|
|
NonTagwordVarsWidths, NonTagwordArgModes) :-
|
|
VarWidth = arg_and_width(_, ArgPosWidth),
|
|
(
|
|
( ArgPosWidth = apw_partial_shifted(_, _, _, _, _, _)
|
|
; ArgPosWidth = apw_none_shifted(_, _)
|
|
),
|
|
take_tagword_args(VarsWidths, ArgModes,
|
|
TailTagwordVarsWidths, TailTagwordArgModes,
|
|
NonTagwordVarsWidths, NonTagwordArgModes),
|
|
TagwordVarsWidths = [VarWidth | TailTagwordVarsWidths],
|
|
TagwordArgModes = [ArgMode | TailTagwordArgModes]
|
|
;
|
|
( ArgPosWidth = apw_full(_, _)
|
|
; ArgPosWidth = apw_double(_, _, _)
|
|
; ArgPosWidth = apw_partial_first(_, _, _, _, _, _)
|
|
; ArgPosWidth = apw_none_nowhere
|
|
),
|
|
TagwordVarsWidths = [],
|
|
TagwordArgModes = [],
|
|
NonTagwordVarsWidths = [VarWidth | VarsWidths],
|
|
NonTagwordArgModes = [ArgMode | ArgModes]
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Generate a direct arg unification between
|
|
% - the left-hand-side (the whole term), and
|
|
% - the right-hand-side (the one argument).
|
|
%
|
|
:- pred generate_direct_arg_deconstruct(prog_var::in, prog_var::in,
|
|
ptag::in, unify_mode::in, llds_code::out,
|
|
code_info::in, code_loc_dep::in, code_loc_dep::out) is det.
|
|
|
|
generate_direct_arg_deconstruct(LHSVar, RHSVar, Ptag, ArgMode, Code,
|
|
CI, !CLD) :-
|
|
get_module_info(CI, ModuleInfo),
|
|
RHSType = variable_type(CI, RHSVar),
|
|
compute_assign_direction(ModuleInfo, ArgMode, RHSType, Dir),
|
|
(
|
|
Dir = assign_right,
|
|
( if variable_is_forward_live(!.CLD, RHSVar) then
|
|
Ptag = ptag(PtagUint8),
|
|
( if PtagUint8 = 0u8 then
|
|
% Masking off the ptag would be a null operation,
|
|
% since it is already all zeroes.
|
|
assign_var_to_var(RHSVar, LHSVar, !CLD),
|
|
Code = empty
|
|
else
|
|
LHSBodyRval = binop(body, var(LHSVar),
|
|
const(llconst_int(uint8.cast_to_int(PtagUint8)))),
|
|
assign_expr_to_var(RHSVar, LHSBodyRval, Code, !CLD)
|
|
)
|
|
else
|
|
Code = empty
|
|
)
|
|
;
|
|
Dir = assign_left,
|
|
reassign_mkword_hole_var(LHSVar, Ptag, var(RHSVar), Code, !CLD)
|
|
;
|
|
Dir = assign_unused,
|
|
% XXX This will have to change if we start to support aliasing.
|
|
Code = empty
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module ll_backend.unify_gen_deconstruct.
|
|
%---------------------------------------------------------------------------%
|