Files
mercury/compiler/ml_lookup_switch.m
Zoltan Somogyi 3dd0f2e03b Act on all remaining warnings about unused state vars.
compiler/add_heap_ops.m:
compiler/check_import_accessibility.m:
compiler/comp_unit_interface.m:
compiler/convert_import_use.m:
compiler/deforest.m:
compiler/dep_par_conj.m:
compiler/distance_granularity.m:
compiler/equiv_type.m:
compiler/generate_dep_d_files.m:
compiler/generate_mmakefile_fragments.m:
compiler/get_dependencies.m:
compiler/grab_modules.m:
compiler/higher_order.specialize_unify_compare.m:
compiler/jumpopt.m:
compiler/layout_out.m:
compiler/lco.m:
compiler/live_vars.m:
compiler/liveness.m:
compiler/llds_out_file.m:
compiler/make.build.m:
compiler/make.get_module_dep_info.m:
compiler/make.library_install.m:
compiler/make.module_target.m:
compiler/make.program_target.m:
compiler/make.track_flags.m:
compiler/make_hlds_passes.m:
compiler/make_module_file_names.m:
compiler/mercury_compile_front_end.m:
compiler/mercury_compile_llds_back_end.m:
compiler/mercury_compile_main.m:
compiler/mercury_compile_middle_passes.m:
compiler/ml_call_gen.m:
compiler/ml_closure_gen.m:
compiler/ml_code_gen.m:
compiler/ml_code_util.m:
compiler/ml_disj_gen.m:
compiler/ml_elim_nested.m:
compiler/ml_foreign_proc_gen.m:
compiler/ml_lookup_switch.m:
compiler/ml_switch_gen.m:
compiler/ml_unify_gen_deconstruct.m:
compiler/ml_unify_gen_test.m:
compiler/mlds_to_c_file.m:
compiler/mlds_to_target_util.m:
compiler/module_cmds.m:
compiler/opt_deps_spec.m:
compiler/optimize.m:
compiler/parse_dcg_goal.m:
compiler/parse_goal.m:
compiler/parse_item.m:
compiler/parse_module.m:
compiler/parse_string_format.m:
compiler/proc_gen.m:
compiler/prop_mode_constraints.m:
compiler/rbmm.points_to_analysis.m:
compiler/rbmm.region_analysis.m:
compiler/rbmm.region_transformation.m:
compiler/simplify_goal_disj.m:
compiler/ssdebug.m:
compiler/stack_opt.m:
compiler/string_switch.m:
compiler/switch_gen.m:
compiler/term_constr_build.m:
compiler/trace_gen.m:
compiler/tupling.m:
compiler/untupling.m:
compiler/write_deps_file.m:
deep_profiler/autopar_calc_overlap.m:
deep_profiler/autopar_find_best_par.m:
deep_profiler/html_format.m:
deep_profiler/startup.m:
profiler/mercury_profile.m:
profiler/propagate.m:
    Act on the new warnings. In a few cases, conform to the changes
    resulting from acting on the warnings in other modules.

browser/Mercury.options:
compiler/Mercury.options:
library/Mercury.options:
mdbcomp/Mercury.options:
ssdb/Mercury.options:
    Specify options for disabling the new warnings for modules
    where we (probably) won't want them.

configure.ac:
    Require the installed compiler to understand the options that
    we now reference in the Mercury.options files above.

tests/debugger/tailrec1.exp:
    Expect variable names for the middle versions of state vars
    using the new naming scheme.

tests/invalid/Mercury.options:
    Fix references to obsolete test names.

tests/warnings/Mercury.options:
    Avoid a test failure with intermodule optimization.
2025-05-19 00:33:06 +10:00

920 lines
39 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 2009-2012 The University of Melbourne.
% Copyright (C) 2014-2018, 2020-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_lookup_switch.m
% Author: zs.
%
% This module implements lookup switches for the MLDS backend.
% Much of its structure is modelled after the structure of lookup_switch.m,
% which does the same thing for the LLDS backend. Most of the documentation
% you may need is in that module.
%
% Any changes here may need to be reflected in lookup_switch.m as well.
%
%---------------------------------------------------------------------------%
:- module ml_backend.ml_lookup_switch.
:- interface.
:- import_module backend_libs.
:- import_module backend_libs.lookup_switch_util.
:- 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.mlds.
:- import_module parse_tree.
:- import_module parse_tree.prog_data.
:- import_module list.
:- import_module map.
:- import_module maybe.
:- import_module unit.
%---------------------------------------------------------------------------%
:- type ml_lookup_switch_info
---> ml_lookup_switch_info(
% The map from the case_id of each switch arm to the
% values of the variables in that switch arm.
mllsi_cases :: case_consts(case_id, mlds_rval,
unit),
% The output variables, which become (some of) the fields
% in each row of a lookup table.
mllsi_out_variables :: list(prog_var),
% The types of the fields holding output variables.
mllsi_out_types :: list(mlds_type),
mllsi_gen_info :: ml_gen_info
).
% Is the given list of cases implementable as a lookup switch?
%
:- pred ml_is_lookup_switch(prog_var::in, list(tagged_case)::in,
hlds_goal_info::in, code_model::in, ml_gen_info::in,
maybe(ml_lookup_switch_info)::out) is det.
% Given a case_id->V map, create the corresponding cons_id->V map.
% Given an entry caseid1->values1 in the case_id->V map, if the case
% with case_id caseid1 has main and other cons_ids consid1a, consid1b
% and consid1c, the cons_id->V map will have the corresponding entries
% consid1a->values1, consid1b->values1 and consid1c->values1.
%
:- pred ml_case_id_soln_consts_to_tag_soln_consts((func(cons_tag) = T)::in,
list(tagged_case)::in, map(case_id, V)::in, map(T, V)::out) is det.
%---------------------------------------------------------------------------%
% Generate MLDS code for the lookup switch.
%
:- pred ml_gen_int_max_32_lookup_switch(prog_var::in,
list(tagged_case)::in, ml_lookup_switch_info::in,
code_model::in, prog_context::in, int::in, int::in,
need_bit_vec_check::in, need_range_check::in, mlds_stmt::out,
ml_gen_info::out) is det.
%---------------------------------------------------------------------------%
%
% These types and predicates are exported because they are useful in the
% implementation of string lookup switches.
%
:- pred ml_gen_several_soln_lookup_code(prog_context::in,
mlds_rval::in, list(prog_var)::in, list(mlds_type)::in,
mlds_type::in, mlds_type::in, mlds_field_id::in, mlds_field_id::in,
list(mlds_field_id)::in, list(mlds_field_id)::in,
mlds_vector_common::in, mlds_vector_common::in, need_bit_vec_check::in,
list(mlds_local_var_defn)::out, list(mlds_stmt)::out,
ml_gen_info::in, ml_gen_info::out) is det.
:- type ml_several_soln_lookup_vars
---> ml_several_soln_lookup_vars(
msslv_num_later_solns_var :: mlds_local_var_name_type,
msslv_later_slot_var :: mlds_local_var_name_type,
msslv_limit_var :: mlds_local_var_name_type,
msslv_limit_assign_statement :: mlds_stmt,
msslv_incr_later_slot_statement :: mlds_stmt,
msslv_denfs :: list(mlds_local_var_defn)
).
:- pred make_several_soln_lookup_vars(prog_context::in,
ml_several_soln_lookup_vars::out,
ml_gen_info::in, ml_gen_info::out) is det.
%---------------------------------------------------------------------------%
:- func ml_construct_later_soln_row(mlds_type, list(mlds_rval)) =
mlds_initializer.
:- func ml_default_value_for_type(mlds_type) = mlds_rval.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
:- import_module backend_libs.builtin_ops.
:- import_module backend_libs.switch_util.
:- import_module hlds.goal_form.
:- import_module hlds.hlds_module.
:- import_module libs.
:- import_module libs.globals.
:- import_module libs.optimization_options.
:- import_module ml_backend.ml_code_util.
:- import_module ml_backend.ml_global_data.
:- import_module ml_backend.ml_util.
:- import_module parse_tree.set_of_var.
:- import_module parse_tree.var_table.
:- import_module assoc_list.
:- import_module bool.
:- import_module cord.
:- import_module int.
:- import_module pair.
:- import_module require.
:- import_module uint.
%---------------------------------------------------------------------------%
ml_is_lookup_switch(SwitchVar, TaggedCases, GoalInfo, CodeModel, Info0,
MaybeLookupSwitchInfo) :-
NonLocals = goal_info_get_nonlocals(GoalInfo),
% SwitchVar must be nonlocal to the switch, since it must be bound
% *before* the switch.
set_of_var.delete(SwitchVar, NonLocals, OtherNonLocals),
set_of_var.to_sorted_list(OtherNonLocals, OutVars),
ml_gen_info_get_module_info(Info0, ModuleInfo),
module_info_get_globals(ModuleInfo, Globals),
globals.get_opt_tuple(Globals, OptTuple),
( if
OptTuple ^ ot_use_static_ground_cells = use_static_ground_cells,
ml_generate_constants_for_lookup_switch(CodeModel, OutVars,
OtherNonLocals, TaggedCases, map.init, CaseSolnMap, Info0, Info)
then
% While the LLDS backend has to worry about implementing trailing
% for model_non lookup switches, we do not. The MLDS backend implements
% trailing by a HLDS-to-HLDS transform (which is in add_trail_ops.m),
% so we can get here only if trailing is not enabled, since otherwise
% the calls or foreign_procs inserted into all non-first disjuncts
% would cause ml_generate_constants_for_lookup_switch to fail.
( if project_all_to_one_solution(CaseSolnMap, CaseValuePairMap) then
CaseConsts = all_one_soln(CaseValuePairMap)
else
CaseConsts = some_several_solns(CaseSolnMap, unit)
),
ml_gen_info_get_var_table(Info, VarTable),
lookup_var_entries(VarTable, OutVars, OutVarEntries),
FieldTypes =
list.map(var_table_entry_to_mlds_type(ModuleInfo), OutVarEntries),
LookupSwitchInfo =
ml_lookup_switch_info(CaseConsts, OutVars, FieldTypes, Info),
MaybeLookupSwitchInfo = yes(LookupSwitchInfo)
else
% We keep the original !.Info.
MaybeLookupSwitchInfo = no
).
:- pred ml_generate_constants_for_lookup_switch(code_model::in,
list(prog_var)::in, set_of_progvar::in, list(tagged_case)::in,
map(case_id, soln_consts(mlds_rval))::in,
map(case_id, soln_consts(mlds_rval))::out,
ml_gen_info::in, ml_gen_info::out) is semidet.
ml_generate_constants_for_lookup_switch(_CodeModel, _OutVars, _ArmNonLocals,
[], !IndexMap, !Info).
ml_generate_constants_for_lookup_switch(CodeModel, OutVars, ArmNonLocals,
[TaggedCase | TaggedCases], !CaseIdMap, !Info) :-
TaggedCase = tagged_case(_TaggedMainConsId, _TaggedOtherConsIds,
CaseId, Goal),
Goal = hlds_goal(GoalExpr, _GoalInfo),
( if GoalExpr = disj(Disjuncts) then
(
Disjuncts = []
;
Disjuncts = [FirstDisjunct | LaterDisjuncts],
goal_is_conj_of_unify(ArmNonLocals, FirstDisjunct),
all_disjuncts_are_conj_of_unify(ArmNonLocals, LaterDisjuncts),
ml_generate_constants_for_arm(OutVars, FirstDisjunct, FirstSoln,
!Info),
ml_generate_constants_for_arms(OutVars, LaterDisjuncts, LaterSolns,
!Info),
SolnConsts = several_solns(FirstSoln, LaterSolns),
map.det_insert(CaseId, SolnConsts, !CaseIdMap)
)
else
goal_is_conj_of_unify(ArmNonLocals, Goal),
ml_generate_constants_for_arm(OutVars, Goal, Soln, !Info),
SolnConsts = one_soln(Soln),
map.det_insert(CaseId, SolnConsts, !CaseIdMap)
),
ml_generate_constants_for_lookup_switch(CodeModel,
OutVars, ArmNonLocals, TaggedCases, !CaseIdMap, !Info).
%---------------------------------------------------------------------------%
ml_case_id_soln_consts_to_tag_soln_consts(GetTag, TaggedCases, CaseIdMap,
TagMap) :-
ml_case_id_soln_consts_to_tag_soln_consts_loop(GetTag, TaggedCases,
CaseIdMap, DepletedCaseIdMap, map.init, TagMap),
expect(map.is_empty(DepletedCaseIdMap), $pred,
"DepletedCaseIdMap not empty").
:- pred ml_case_id_soln_consts_to_tag_soln_consts_loop(
(func(cons_tag) = Key)::in, list(tagged_case)::in,
map(case_id, V)::in, map(case_id, V)::out,
map(Key, V)::in, map(Key, V)::out) is det.
ml_case_id_soln_consts_to_tag_soln_consts_loop(_GetTag, [],
!CaseIdMap, !TagMap).
ml_case_id_soln_consts_to_tag_soln_consts_loop(GetTag,
[TaggedCase | TaggedCases], !CaseIdMap, !TagMap) :-
TaggedCase = tagged_case(TaggedMainConsId, TaggedOtherConsIds,
CaseId, _Goal),
map.det_remove(CaseId, SolnConsts, !CaseIdMap),
ml_record_lookup_for_tagged_cons_id(GetTag, SolnConsts,
TaggedMainConsId, !TagMap),
list.foldl(ml_record_lookup_for_tagged_cons_id(GetTag, SolnConsts),
TaggedOtherConsIds, !TagMap),
ml_case_id_soln_consts_to_tag_soln_consts_loop(GetTag, TaggedCases,
!CaseIdMap, !TagMap).
:- pred ml_record_lookup_for_tagged_cons_id((func(cons_tag) = Key)::in,
V::in, tagged_cons_id::in, map(Key, V)::in, map(Key, V)::out) is det.
ml_record_lookup_for_tagged_cons_id(GetTag, SolnConsts, TaggedConsId,
!IndexMap) :-
TaggedConsId = tagged_cons_id(_ConsId, ConsTag),
Index = GetTag(ConsTag),
map.det_insert(Index, SolnConsts, !IndexMap).
%---------------------------------------------------------------------------%
ml_gen_int_max_32_lookup_switch(SwitchVar, TaggedCases, LookupSwitchInfo,
CodeModel, Context, StartVal, EndVal, NeedBitVecCheck, NeedRangeCheck,
Stmt, !:Info) :-
LookupSwitchInfo =
ml_lookup_switch_info(CaseIdConstMap, OutVars, FieldTypes, !:Info),
ml_gen_var_direct(!.Info, SwitchVar, SwitchVarLval),
SwitchVarRval = ml_lval(SwitchVarLval),
( if StartVal = 0 then
IndexRval = SwitchVarRval
else
StartRval = ml_const(mlconst_int(StartVal)),
IndexRval = ml_binop(int_arith(int_type_int, ao_sub),
SwitchVarRval, StartRval)
),
(
CaseIdConstMap = all_one_soln(CaseIdValueMap),
ml_case_id_soln_consts_to_tag_soln_consts(get_int_tag, TaggedCases,
CaseIdValueMap, IntValueMap),
map.to_assoc_list(IntValueMap, IntValues),
ml_gen_simple_atomic_lookup_switch(IndexRval, OutVars, FieldTypes,
IntValues, CodeModel, Context, StartVal, EndVal,
NeedBitVecCheck, NeedRangeCheck, Stmt, !Info)
;
CaseIdConstMap = some_several_solns(CaseIdSolnMap, _Unit),
expect(unify(CodeModel, model_non), $pred, "CodeModel != model_non"),
ml_case_id_soln_consts_to_tag_soln_consts(get_int_tag, TaggedCases,
CaseIdSolnMap, IntSolnMap),
map.to_assoc_list(IntSolnMap, IntSolns),
ml_gen_several_soln_atomic_lookup_switch(IndexRval, OutVars,
FieldTypes, IntSolns, Context, StartVal, EndVal,
NeedBitVecCheck, NeedRangeCheck, Stmt, !Info)
).
%---------------------------------------------------------------------------%
:- pred ml_gen_simple_atomic_lookup_switch(mlds_rval::in, list(prog_var)::in,
list(mlds_type)::in, assoc_list(int, list(mlds_rval))::in, code_model::in,
prog_context::in, int::in, int::in,
need_bit_vec_check::in, need_range_check::in, mlds_stmt::out,
ml_gen_info::in, ml_gen_info::out) is det.
ml_gen_simple_atomic_lookup_switch(IndexRval, OutVars, OutTypes, CaseValues,
CodeModel, Context, StartVal, EndVal, NeedBitVecCheck, NeedRangeCheck,
Stmt, !Info) :-
ml_gen_info_get_module_info(!.Info, ModuleInfo),
module_info_get_name(ModuleInfo, ModuleName),
MLDS_ModuleName = mercury_module_name_to_mlds(ModuleName),
ml_gen_info_get_target(!.Info, Target),
(
OutTypes = [],
% There are no output parameters, so there is nothing to look up.
% Generating a structure with no fields would cause problems for
% Visual C, which cannot handle such structures.
%
% This should happen only for model_semi switches. If it happens for
% a model_det switch, that switch is effectively a no-op.
LookupStmts = []
;
OutTypes = [_ | _],
ml_gen_info_get_global_data(!.Info, GlobalData0),
ml_gen_static_vector_type(MLDS_ModuleName, Context, Target,
OutTypes, StructTypeNum, StructType, FieldIds,
GlobalData0, GlobalData1),
ml_construct_simple_switch_vector(ModuleInfo, StructType,
OutTypes, StartVal, CaseValues, RowInitializers),
ml_gen_static_vector_defn(MLDS_ModuleName, StructTypeNum,
RowInitializers, VectorCommon, GlobalData1, GlobalData),
ml_gen_info_set_global_data(GlobalData, !Info),
ml_generate_field_assigns(OutVars, OutTypes, FieldIds, VectorCommon,
StructType, IndexRval, Context, LookupStmts, !Info)
),
(
CodeModel = model_det,
expect(unify(NeedRangeCheck, do_not_need_range_check), $pred,
"model_det need_range_check"),
(
NeedBitVecCheck = need_bit_vec_check,
unexpected($pred, "model_det need_bit_vec_check")
;
( NeedBitVecCheck = do_not_need_bit_vec_check_no_gaps
; NeedBitVecCheck = do_not_need_bit_vec_check_with_gaps
)
),
Stmt = ml_stmt_block([], [], LookupStmts, Context)
;
CodeModel = model_semi,
ml_gen_set_success(ml_const(mlconst_true), Context, SetSuccessTrueStmt,
!Info),
LookupSucceedStmt = ml_stmt_block([], [],
LookupStmts ++ [SetSuccessTrueStmt], Context),
(
NeedRangeCheck = do_not_need_range_check,
(
( NeedBitVecCheck = do_not_need_bit_vec_check_no_gaps
; NeedBitVecCheck = do_not_need_bit_vec_check_with_gaps
),
Stmt = LookupSucceedStmt
;
NeedBitVecCheck = need_bit_vec_check,
ml_generate_bitvec_test(MLDS_ModuleName, Context, IndexRval,
CaseValues, StartVal, EndVal, BitVecCheckCond, !Info),
ml_gen_set_success(ml_const(mlconst_false), Context,
SetSuccessFalseStmt, !Info),
Stmt = ml_stmt_if_then_else(BitVecCheckCond,
LookupSucceedStmt, yes(SetSuccessFalseStmt), Context)
)
;
NeedRangeCheck = need_range_check,
Difference = EndVal - StartVal,
RangeCheckCond = ml_binop(int_as_uint_cmp(le), IndexRval,
ml_const(mlconst_int(Difference))),
ml_gen_set_success(ml_const(mlconst_false), Context,
SetSuccessFalseStmt, !Info),
(
( NeedBitVecCheck = do_not_need_bit_vec_check_no_gaps
; NeedBitVecCheck = do_not_need_bit_vec_check_with_gaps
),
RangeCheckSuccessStmt = LookupSucceedStmt
;
NeedBitVecCheck = need_bit_vec_check,
ml_generate_bitvec_test(MLDS_ModuleName, Context, IndexRval,
CaseValues, StartVal, EndVal, BitVecCheckCond, !Info),
RangeCheckSuccessStmt = ml_stmt_if_then_else(BitVecCheckCond,
LookupSucceedStmt, yes(SetSuccessFalseStmt), Context)
),
% We want to execute the bit vector test only if the range check
% succeeded, since otherwise the bit vector test will probably
% access the bit vector outside its bounds.
Stmt = ml_stmt_if_then_else(RangeCheckCond,
RangeCheckSuccessStmt, yes(SetSuccessFalseStmt), Context)
)
;
CodeModel = model_non,
% If all the switch arms have exactly one solution, then the switch
% as a whole cannot be model_non.
unexpected($pred, "model_non")
).
%---------------------------------------------------------------------------%
:- pred ml_gen_several_soln_atomic_lookup_switch(mlds_rval::in,
list(prog_var)::in, list(mlds_type)::in,
assoc_list(int, soln_consts(mlds_rval))::in, prog_context::in,
int::in, int::in, need_bit_vec_check::in, need_range_check::in,
mlds_stmt::out, ml_gen_info::in, ml_gen_info::out) is det.
ml_gen_several_soln_atomic_lookup_switch(IndexRval, OutVars, OutTypes,
CaseSolns, Context, StartVal, EndVal, NeedBitVecCheck, NeedRangeCheck,
Stmt, !Info) :-
ml_gen_info_get_module_info(!.Info, ModuleInfo),
module_info_get_name(ModuleInfo, ModuleName),
MLDS_ModuleName = mercury_module_name_to_mlds(ModuleName),
ml_gen_info_get_target(!.Info, Target),
MLDS_IntType = mlds_builtin_type_int(int_type_int),
FirstSolnFieldTypes = [MLDS_IntType, MLDS_IntType | OutTypes],
ml_gen_info_get_global_data(!.Info, GlobalData0),
ml_gen_static_vector_type(MLDS_ModuleName, Context, Target,
FirstSolnFieldTypes, FirstSolnStructTypeNum, FirstSolnStructType,
FirstSolnTableFieldIds, GlobalData0, GlobalData1),
ml_gen_static_vector_type(MLDS_ModuleName, Context, Target,
OutTypes, LaterSolnStructTypeNum, LaterSolnStructType,
LaterSolnOutFieldIds, GlobalData1, GlobalData2),
(
( FirstSolnTableFieldIds = []
; FirstSolnTableFieldIds = [_]
),
unexpected($pred, "not enough field_ids")
;
FirstSolnTableFieldIds =
[NumLaterSolnsFieldId, FirstLaterSolnRowFieldId
| FirstSolnOutFieldIds]
),
ml_construct_model_non_switch_vector(ModuleInfo, StartVal, EndVal,
0, CaseSolns, FirstSolnStructType, LaterSolnStructType, OutTypes,
[], RevFirstSolnRowInitializers,
cord.init, LaterSolnRowInitializersCord, no, HadDummyRows),
list.reverse(RevFirstSolnRowInitializers, FirstSolnRowInitializers),
LaterSolnRowInitializers = cord.list(LaterSolnRowInitializersCord),
ml_gen_static_vector_defn(MLDS_ModuleName, FirstSolnStructTypeNum,
FirstSolnRowInitializers, FirstSolnVectorCommon,
GlobalData2, GlobalData3),
ml_gen_static_vector_defn(MLDS_ModuleName, LaterSolnStructTypeNum,
LaterSolnRowInitializers, LaterSolnVectorCommon,
GlobalData3, GlobalData),
ml_gen_info_set_global_data(GlobalData, !Info),
(
NeedBitVecCheck = do_not_need_bit_vec_check_no_gaps,
expect(unify(HadDummyRows, no), $pred,
"bad do_not_need_bit_vec_check_no_gaps")
;
NeedBitVecCheck = do_not_need_bit_vec_check_with_gaps,
expect(unify(HadDummyRows, yes), $pred,
"bad do_not_need_bit_vec_check_with_gaps")
;
NeedBitVecCheck = need_bit_vec_check,
expect(unify(HadDummyRows, yes), $pred, "bad need_bit_vec_check")
),
ml_gen_several_soln_lookup_code(Context, IndexRval,
OutVars, OutTypes, FirstSolnStructType, LaterSolnStructType,
NumLaterSolnsFieldId, FirstLaterSolnRowFieldId,
FirstSolnOutFieldIds, LaterSolnOutFieldIds,
FirstSolnVectorCommon, LaterSolnVectorCommon, NeedBitVecCheck,
MatchDefns, InRangeStmts, !Info),
InRangeStmt = ml_stmt_block(MatchDefns, [], InRangeStmts, Context),
(
NeedRangeCheck = do_not_need_range_check,
Stmt = InRangeStmt
;
NeedRangeCheck = need_range_check,
Difference = EndVal - StartVal,
RangeCheckCond = ml_binop(int_as_uint_cmp(le), IndexRval,
ml_const(mlconst_int(Difference))),
Stmt = ml_stmt_if_then_else(RangeCheckCond, InRangeStmt, no, Context)
).
%---------------------------------------------------------------------------%
ml_gen_several_soln_lookup_code(Context, SlotVarRval,
OutVars, OutTypes, FirstSolnStructType, LaterSolnStructType,
NumLaterSolnsFieldId, FirstLaterSolnRowFieldId,
FirstSolnOutFieldIds, LaterSolnOutFieldIds,
FirstSolnVectorCommon, LaterSolnVectorCommon, NeedBitVecCheck,
MatchDefns, Stmts, !Info) :-
make_several_soln_lookup_vars(Context, SeveralSolnLookupVars, !Info),
SeveralSolnLookupVars = ml_several_soln_lookup_vars(
NumLaterSolnsVarNameType, LaterSlotVarNameType, LimitVarNameType,
LimitAssignStmt, IncrLaterSlotVarStmt, MatchDefns),
NumLaterSolnsVarNameType =
mlds_local_var_name_type(NumLaterSolnsVarName, NumLaterSolnsType),
NumLaterSolnsVarLval =
ml_local_var(NumLaterSolnsVarName, NumLaterSolnsType),
LaterSlotVarNameType =
mlds_local_var_name_type(LaterSlotVarName, LaterSlotType),
LaterSlotVarLval =
ml_local_var(LaterSlotVarName, LaterSlotType),
LimitVarNameType =
mlds_local_var_name_type(LimitVarName, LimitType),
LimitVarLval =
ml_local_var(LimitVarName, LimitType),
NumLaterSolnsVarRval = ml_lval(NumLaterSolnsVarLval),
LaterSlotVarRval = ml_lval(LaterSlotVarLval),
LimitVarRval = ml_lval(LimitVarLval),
MLDS_IntType = mlds_builtin_type_int(int_type_int),
ml_generate_field_assign(NumLaterSolnsVarLval, MLDS_IntType,
NumLaterSolnsFieldId, FirstSolnVectorCommon, FirstSolnStructType,
SlotVarRval, Context, NumLaterSolnsAssignStmt),
ml_generate_field_assign(LaterSlotVarLval, MLDS_IntType,
FirstLaterSolnRowFieldId, FirstSolnVectorCommon, FirstSolnStructType,
SlotVarRval, Context, LaterSlotVarAssignStmt),
ml_generate_field_assigns(OutVars, OutTypes, FirstSolnOutFieldIds,
FirstSolnVectorCommon, FirstSolnStructType,
SlotVarRval, Context, FirstSolnLookupStmts, !Info),
ml_generate_field_assigns(OutVars, OutTypes, LaterSolnOutFieldIds,
LaterSolnVectorCommon, LaterSolnStructType,
LaterSlotVarRval, Context, LaterSolnLookupStmts, !Info),
ml_gen_call_current_success_cont(!.Info, Context, CallContStmt),
FirstLookupSucceedStmt = ml_stmt_block([], [],
FirstSolnLookupStmts ++ [CallContStmt], Context),
LaterLookupSucceedStmt = ml_stmt_block([], [],
LaterSolnLookupStmts ++ [CallContStmt, IncrLaterSlotVarStmt], Context),
MoreSolnsLoopCond = ml_binop(int_cmp(int_type_int, lt),
LaterSlotVarRval, LimitVarRval),
MoreSolnsLoopStmt = ml_stmt_while(may_loop_zero_times, MoreSolnsLoopCond,
LaterLookupSucceedStmt, [LaterSlotVarName], Context),
OneOrMoreSolnsStmts = [FirstLookupSucceedStmt, LaterSlotVarAssignStmt,
LimitAssignStmt, MoreSolnsLoopStmt],
(
( NeedBitVecCheck = do_not_need_bit_vec_check_no_gaps
; NeedBitVecCheck = do_not_need_bit_vec_check_with_gaps
),
Stmts = [NumLaterSolnsAssignStmt | OneOrMoreSolnsStmts]
;
NeedBitVecCheck = need_bit_vec_check,
OneOrMoreSolnsBlockStmt =
ml_stmt_block([], [], OneOrMoreSolnsStmts, Context),
AnySolnsCond = ml_binop(int_cmp(int_type_int, ge),
NumLaterSolnsVarRval, ml_const(mlconst_int(0))),
ZeroOrMoreSolnsStmt = ml_stmt_if_then_else(AnySolnsCond,
OneOrMoreSolnsBlockStmt, no, Context),
Stmts = [NumLaterSolnsAssignStmt, ZeroOrMoreSolnsStmt]
).
make_several_soln_lookup_vars(Context, SeveralSolnLookupVars, !Info) :-
ml_gen_info_new_aux_var_name(mcav_num_later_solns, NumLaterSolnsVarName,
!Info),
% We never need to trace ints.
IntType = mlds_builtin_type_int(int_type_int),
NumLaterSolnsVarDefn = ml_gen_mlds_var_decl(NumLaterSolnsVarName, IntType,
gc_no_stmt, Context),
NumLaterSolnsVarNameType =
mlds_local_var_name_type(NumLaterSolnsVarName, IntType),
NumLaterSolnsVarLval = ml_local_var(NumLaterSolnsVarName, IntType),
ml_gen_info_new_aux_var_name(mcav_later_slot, LaterSlotVarName, !Info),
% We never need to trace ints.
LaterSlotVarDefn = ml_gen_mlds_var_decl(LaterSlotVarName, IntType,
gc_no_stmt, Context),
LaterSlotVarNameType = mlds_local_var_name_type(LaterSlotVarName, IntType),
LaterSlotVarLval = ml_local_var(LaterSlotVarName, IntType),
ml_gen_info_new_aux_var_name(mcav_limit, LimitVarName, !Info),
% We never need to trace ints.
LimitVarDefn = ml_gen_mlds_var_decl(LimitVarName, IntType,
gc_no_stmt, Context),
LimitVarNameType = mlds_local_var_name_type(LimitVarName, IntType),
LimitVarLval = ml_local_var(LimitVarName, IntType),
Defns = [NumLaterSolnsVarDefn, LaterSlotVarDefn, LimitVarDefn],
LaterSlotVarRval = ml_lval(LaterSlotVarLval),
NumLaterSolnsVarRval = ml_lval(NumLaterSolnsVarLval),
LimitAssign = assign(LimitVarLval,
ml_binop(int_arith(int_type_int, ao_add),
LaterSlotVarRval, NumLaterSolnsVarRval)),
LimitAssignStmt = ml_stmt_atomic(LimitAssign, Context),
IncrLaterSlotVar = assign(LaterSlotVarLval,
ml_binop(int_arith(int_type_int, ao_add), LaterSlotVarRval,
ml_const(mlconst_int(1)))),
IncrLaterSlotVarStmt = ml_stmt_atomic(IncrLaterSlotVar, Context),
SeveralSolnLookupVars = ml_several_soln_lookup_vars(
NumLaterSolnsVarNameType, LaterSlotVarNameType, LimitVarNameType,
LimitAssignStmt, IncrLaterSlotVarStmt, Defns).
%---------------------------------------------------------------------------%
% The bitvector is an array of words (where we use the first 32 bits
% of each word). Each bit represents a tag value for the (range checked)
% input to the lookup switch. The bit is `1' iff we have a case for that
% tag value.
%
:- pred ml_generate_bitvec_test(mlds_module_name::in, prog_context::in,
mlds_rval::in, assoc_list(int, T)::in, int::in, int::in,
mlds_rval::out, ml_gen_info::in, ml_gen_info::out) is det.
ml_generate_bitvec_test(MLDS_ModuleName, Context, IndexRval, CaseVals,
Start, _End, CheckRval, !Info) :-
ml_gen_info_get_globals(!.Info, Globals),
get_target_host_min_word_size(Globals, WordSize),
( WordSize = word_size_32, WordBits = 32, Log2WordBits = 5
; WordSize = word_size_64, WordBits = 64, Log2WordBits = 6
),
ml_gen_info_get_global_data(!.Info, GlobalData0),
ml_generate_bit_vec(MLDS_ModuleName, Context, CaseVals, Start, WordBits,
BitVecArgRvals, BitVecRval, GlobalData0, GlobalData),
% Optimize the single-word case: if all the cases fit into a single word,
% then the word to use is always that word, and the index specifies which
% bit; we don't need the array.
( if BitVecArgRvals = [SingleWordRval] then
% Do not save GlobalData back into !Info.
WordRval = SingleWordRval,
BitNumRval = IndexRval
else
% Otherwise, the high bits of the index specify which word in the array
% to use and the low bits specify which bit in that word.
ml_gen_info_set_global_data(GlobalData, !Info),
% This is the same as
% WordNumRval = ml_binop(int_div, IndexRval,
% ml_const(mlconst_int(WordBits)))
% except that it can generate more efficient code.
WordNumRval =
ml_binop(unchecked_right_shift(int_type_int, shift_by_int),
IndexRval, ml_const(mlconst_int(Log2WordBits))),
ArrayElemType = array_elem_scalar(scalar_elem_int),
WordRval = ml_binop(array_index(ArrayElemType),
BitVecRval, WordNumRval),
% This is the same as
% BitNumRval = ml_binop(int_mod, IndexRval,
% ml_const(mlconst_int(WordBits)))
% except that it can generate more efficient code.
BitNumRval = ml_binop(bitwise_and(int_type_int), IndexRval,
ml_const(mlconst_int(WordBits - 1)))
),
CheckRval = ml_binop(bitwise_and(int_type_int), WordRval,
ml_binop(unchecked_left_shift(int_type_int, shift_by_int),
ml_const(mlconst_int(1)), BitNumRval)).
% We generate the bitvector by iterating through the cases marking the bit
% for each case. We represent the bitvector here as a map from the word
% number in the vector to the bits for that word.
%
:- pred ml_generate_bit_vec(mlds_module_name::in, prog_context::in,
assoc_list(int, T)::in, int::in, int::in,
list(mlds_rval)::out, mlds_rval::out,
ml_global_data::in, ml_global_data::out) is det.
ml_generate_bit_vec(MLDS_ModuleName, Context, CaseVals, Start, WordBits,
WordRvals, BitVecRval, !GlobalData) :-
map.init(BitMap0),
ml_generate_bit_vec_2(CaseVals, Start, WordBits, BitMap0, BitMap),
map.to_assoc_list(BitMap, WordVals),
ml_generate_bit_vec_initializers(WordVals, 0, WordRvals, WordInitializers),
Initializer = init_array(WordInitializers),
ConstType = mlds_array_type(mlds_builtin_type_int(int_type_int)),
ml_gen_static_scalar_const_value(MLDS_ModuleName, mgcv_bit_vector,
ConstType, Initializer, Context, BitVecRval, !GlobalData).
:- pred ml_generate_bit_vec_2(assoc_list(int, T)::in, int::in, int::in,
map(int, uint)::in, map(int, uint)::out) is det.
ml_generate_bit_vec_2([], _, _, !BitMap).
ml_generate_bit_vec_2([Tag - _ | Rest], Start, WordBits, !BitMap) :-
Val = Tag - Start,
WordNum = Val // WordBits,
Offset = Val mod WordBits,
( if map.search(!.BitMap, WordNum, X0) then
X1 = X0 \/ (1u << Offset),
map.det_update(WordNum, X1, !BitMap)
else
X1 = (1u << Offset),
map.det_insert(WordNum, X1, !BitMap)
),
ml_generate_bit_vec_2(Rest, Start, WordBits, !BitMap).
:- pred ml_generate_bit_vec_initializers(list(pair(int, uint))::in, int::in,
list(mlds_rval)::out, list(mlds_initializer)::out) is det.
ml_generate_bit_vec_initializers([], _, [], []).
ml_generate_bit_vec_initializers(All @ [WordNum - Bits | Rest], Count,
[Rval | Rvals], [Initializer | Initializers]) :-
( if Count < WordNum then
WordVal = 0u,
Remainder = All
else
WordVal = Bits,
Remainder = Rest
),
Rval = ml_const(mlconst_uint(WordVal)),
Initializer = init_obj(Rval),
ml_generate_bit_vec_initializers(Remainder, Count + 1,
Rvals, Initializers).
%---------------------------------------------------------------------------%
:- pred ml_construct_simple_switch_vector(module_info::in,
mlds_type::in, list(mlds_type)::in, int::in,
assoc_list(int, list(mlds_rval))::in, list(mlds_initializer)::out) is det.
ml_construct_simple_switch_vector(_, _, _, _, [], []).
ml_construct_simple_switch_vector(ModuleInfo, StructType, FieldTypes,
CurIndex, [Pair | Pairs], [RowInitializer | RowInitializers]) :-
Pair = Index - Rvals,
( if CurIndex < Index then
FieldRvals = list.map(ml_default_value_for_type, FieldTypes),
RemainingPairs = [Pair | Pairs]
else
FieldRvals = Rvals,
RemainingPairs = Pairs
),
FieldInitializers = list.map(wrap_init_obj, FieldRvals),
RowInitializer = init_struct(StructType, FieldInitializers),
ml_construct_simple_switch_vector(ModuleInfo, StructType, FieldTypes,
CurIndex + 1, RemainingPairs, RowInitializers).
:- pred ml_construct_model_non_switch_vector(module_info::in,
int::in, int::in, int::in, assoc_list(int, soln_consts(mlds_rval))::in,
mlds_type::in, mlds_type::in, list(mlds_type)::in,
list(mlds_initializer)::in, list(mlds_initializer)::out,
cord(mlds_initializer)::in, cord(mlds_initializer)::out,
bool::in, bool::out) is det.
ml_construct_model_non_switch_vector(ModuleInfo, CurIndex, EndVal,
!.NextLaterSolnRow, [],
FirstSolnStructType, LaterSolnStructType, FieldTypes,
!RevFirstSolnRowInitializers, !LaterSolnRowInitializersCord,
!HadDummyRows) :-
( if CurIndex > EndVal then
true
else
make_dummy_first_soln_row(FirstSolnStructType, FieldTypes,
!RevFirstSolnRowInitializers),
!:HadDummyRows = yes,
ml_construct_model_non_switch_vector(ModuleInfo, CurIndex + 1, EndVal,
!.NextLaterSolnRow, [],
FirstSolnStructType, LaterSolnStructType, FieldTypes,
!RevFirstSolnRowInitializers, !LaterSolnRowInitializersCord,
!HadDummyRows)
).
ml_construct_model_non_switch_vector(ModuleInfo, CurIndex, EndVal,
!.NextLaterSolnRow, [Pair | Pairs],
FirstSolnStructType, LaterSolnStructType, FieldTypes,
!RevFirstSolnRowInitializers, !LaterSolnRowInitializersCord,
!HadDummyRows) :-
Pair = Index - Soln,
( if CurIndex < Index then
make_dummy_first_soln_row(FirstSolnStructType, FieldTypes,
!RevFirstSolnRowInitializers),
!:HadDummyRows = yes,
NextPairs = [Pair | Pairs]
else
(
Soln = one_soln(FieldRvals),
FieldInitializers = list.map(wrap_init_obj, FieldRvals),
NumLaterSolnsInitializer = gen_init_int(0),
FirstLaterSlotInitializer = gen_init_int(-1),
FirstSolnFieldInitializers =
[NumLaterSolnsInitializer, FirstLaterSlotInitializer
| FieldInitializers],
FirstSolnRowInitializer =
init_struct(FirstSolnStructType, FirstSolnFieldInitializers),
!:RevFirstSolnRowInitializers =
[FirstSolnRowInitializer | !.RevFirstSolnRowInitializers]
;
Soln = several_solns(FirstSolnRvals, LaterSolns),
FieldInitializers = list.map(wrap_init_obj, FirstSolnRvals),
list.length(LaterSolns, NumLaterSolns),
NumLaterSolnsInitializer = gen_init_int(NumLaterSolns),
FirstLaterSlotInitializer = gen_init_int(!.NextLaterSolnRow),
FirstSolnFieldInitializers =
[NumLaterSolnsInitializer, FirstLaterSlotInitializer
| FieldInitializers],
FirstSolnRowInitializer =
init_struct(FirstSolnStructType, FirstSolnFieldInitializers),
!:RevFirstSolnRowInitializers =
[FirstSolnRowInitializer | !.RevFirstSolnRowInitializers],
LaterSolnRowInitializers = list.map(
ml_construct_later_soln_row(LaterSolnStructType),
LaterSolns),
!:LaterSolnRowInitializersCord = !.LaterSolnRowInitializersCord ++
from_list(LaterSolnRowInitializers),
!:NextLaterSolnRow = !.NextLaterSolnRow + NumLaterSolns
),
NextPairs = Pairs
),
ml_construct_model_non_switch_vector(ModuleInfo, CurIndex + 1, EndVal,
!.NextLaterSolnRow, NextPairs,
FirstSolnStructType, LaterSolnStructType, FieldTypes,
!RevFirstSolnRowInitializers, !LaterSolnRowInitializersCord,
!HadDummyRows).
ml_construct_later_soln_row(StructType, Rvals) = RowInitializer :-
FieldInitializers = list.map(wrap_init_obj, Rvals),
RowInitializer = init_struct(StructType, FieldInitializers).
%---------------------------------------------------------------------------%
:- pred make_dummy_first_soln_row(mlds_type::in, list(mlds_type)::in,
list(mlds_initializer)::in, list(mlds_initializer)::out) is det.
make_dummy_first_soln_row(FirstSolnStructType, FieldTypes,
!RevFirstSolnRowInitializers) :-
FieldRvals = list.map(ml_default_value_for_type, FieldTypes),
FieldInitializers = list.map(wrap_init_obj, FieldRvals),
NumLaterSolnsInitializer = gen_init_int(-1),
FirstLaterSlotInitializer = gen_init_int(-1),
FirstSolnFieldInitializers =
[NumLaterSolnsInitializer, FirstLaterSlotInitializer
| FieldInitializers],
FirstSolnRowInitializer =
init_struct(FirstSolnStructType, FirstSolnFieldInitializers),
!:RevFirstSolnRowInitializers =
[FirstSolnRowInitializer | !.RevFirstSolnRowInitializers].
ml_default_value_for_type(MLDS_Type) = DefaultRval :-
(
MLDS_Type = mlds_builtin_type_int(IntType),
(
IntType = int_type_int,
DefaultRval = ml_const(mlconst_int(0))
;
IntType = int_type_int8,
DefaultRval = ml_const(mlconst_int8(0i8))
;
IntType = int_type_int16,
DefaultRval = ml_const(mlconst_int16(0i16))
;
IntType = int_type_int32,
DefaultRval = ml_const(mlconst_int32(0i32))
;
IntType = int_type_int64,
DefaultRval = ml_const(mlconst_int64(0i64))
;
IntType = int_type_uint,
DefaultRval = ml_const(mlconst_uint(0u))
;
IntType = int_type_uint8,
DefaultRval = ml_const(mlconst_uint8(0u8))
;
IntType = int_type_uint16,
DefaultRval = ml_const(mlconst_uint16(0u16))
;
IntType = int_type_uint32,
DefaultRval = ml_const(mlconst_uint32(0u32))
;
IntType = int_type_uint64,
DefaultRval = ml_const(mlconst_uint64(0u64))
)
;
MLDS_Type = mlds_builtin_type_float,
DefaultRval = ml_const(mlconst_float(0.0))
;
MLDS_Type = mlds_builtin_type_string,
DefaultRval = ml_cast(MLDS_Type, ml_const(mlconst_int(0)))
;
MLDS_Type = mlds_builtin_type_char,
DefaultRval = ml_const(mlconst_char(0))
;
MLDS_Type = mlds_native_bool_type,
DefaultRval = ml_const(mlconst_false)
;
( MLDS_Type = mercury_nb_type(_, _)
; MLDS_Type = mlds_mercury_array_type(_)
; MLDS_Type = mlds_foreign_type(_)
; MLDS_Type = mlds_class_type(_)
; MLDS_Type = mlds_enum_class_type(_)
; MLDS_Type = mlds_env_type(_)
; MLDS_Type = mlds_struct_type(_)
; MLDS_Type = mlds_array_type(_)
; MLDS_Type = mlds_mostly_generic_array_type(_)
; MLDS_Type = mlds_func_type(_)
; MLDS_Type = mlds_generic_type
; MLDS_Type = mlds_type_info_type
; MLDS_Type = mlds_pseudo_type_info_type
),
DefaultRval = ml_cast(MLDS_Type, ml_const(mlconst_int(0)))
;
( MLDS_Type = mlds_cont_type(_)
; MLDS_Type = mlds_commit_type
; MLDS_Type = mlds_ptr_type(_)
; MLDS_Type = mlds_generic_env_ptr_type
; MLDS_Type = mlds_rtti_type(_)
; MLDS_Type = mlds_tabling_type(_)
; MLDS_Type = mlds_unknown_type
),
unexpected($pred, "unexpected MLDS_Type")
).
%---------------------------------------------------------------------------%
:- end_module ml_backend.ml_lookup_switch.
%---------------------------------------------------------------------------%