mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-27 15:24:00 +00:00
Estimated hours taken: 2.5 Some more changes to minimize the complexity of the intermodule dependencies. In particular, ensure that bytecode.m does not need to import llds.m. compiler/llds.m: compiler/builtin_ops.m: Move the definitions of the unary_op and binary_op types into a new module `builtin_ops'. These types are used by three of the different back-ends (bytecode, llds, and mlds) and therefore deserve to be in their own module. compiler/bytecode.m: Define a type `byte_reg_type' and use that instead of llds__reg_type. Delete the import of module llds. compiler/notes/compiler_design.html: Document the new module builtin_ops. compiler/rl_exprn.m: Add a comment explaining why we need to import llds (and builtin_ops). compiler/base_type_layout.m: compiler/bytecode.m: compiler/code_util.m: compiler/dense_switch.m: compiler/ite_gen.m: compiler/jumpopt.m: compiler/llds_out.m: compiler/lookup_switch.m: compiler/middle_rec.m: compiler/opt_debug.m: compiler/opt_util.m: compiler/rl_exprn.m: compiler/string_switch.m: compiler/tag_switch.m: compiler/transform_llds.m: compiler/unify_gen.m: compiler/value_number.m: compiler/vn_block.m: compiler/vn_cost.m: compiler/vn_flush.m: compiler/vn_type.m: compiler/vn_util.m: compiler/vn_verify.m: Add imports of module builtin_ops to lots of modules that imported llds.
521 lines
19 KiB
Mathematica
521 lines
19 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1996-1999 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.
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% lookup_switch.m
|
|
|
|
% For switches on atomic types in which the cases contain only the construction
|
|
% of constants, generate code which just assigns the values of the output
|
|
% variables by indexing into an array of values for each output variable.
|
|
|
|
% For switches that can fail, the generated code does a range check on the
|
|
% index, and then does a lookup in a bit-vector to see if there is a value
|
|
% for the appropriate case. If there is, then it does a lookup (using the
|
|
% field macro) in the array of results. The array is padded with "0"s for
|
|
% cases that are not covered. This is fine, since we do the lookup after
|
|
% we check the bit-vector for the appropriate case.
|
|
|
|
% The current implementation works out whether or not it can do a lookup
|
|
% switch by generating code for each case and looking to see that no code
|
|
% got generated (ie only the exprn cache got modified) and that the output
|
|
% variables of the switch are all constants. This is potentially quite in-
|
|
% efficient because it does the work of generating code for the cases and
|
|
% then may throw it away if a subsequent case generates actual code, or non
|
|
% constant outputs.
|
|
|
|
% A potential improvement would be to make a single array for each switch,
|
|
% since putting the values produced for each tag value side-by-side in
|
|
% memory will tend to lead to fewer cache misses.
|
|
|
|
% The number of bits per word is taken from the bits_per_word option which
|
|
% uses a flag in the mc script with a value from configuration. This is
|
|
% used when generating bit-vectors.
|
|
|
|
% Author: conway.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module lookup_switch.
|
|
|
|
:- interface.
|
|
|
|
:- import_module hlds_goal, hlds_data, llds, switch_gen, code_info, prog_data.
|
|
:- import_module std_util, map, set, list.
|
|
|
|
:- type case_consts == list(pair(int, list(rval))).
|
|
|
|
:- type rval_map == map(prog_var, list(pair(int, rval))).
|
|
|
|
:- pred lookup_switch__is_lookup_switch(prog_var, cases_list, hlds_goal_info,
|
|
can_fail, int, code_model, int, int, can_fail, can_fail,
|
|
list(prog_var), case_consts, maybe(set(prog_var)),
|
|
code_info, code_info).
|
|
:- mode lookup_switch__is_lookup_switch(in, in, in, in, in, in, out, out,
|
|
out, out, out, out, out, in, out) is semidet.
|
|
|
|
% Generate code for a switch using a lookup table.
|
|
|
|
:- pred lookup_switch__generate(prog_var, list(prog_var), case_consts,
|
|
int, int, can_fail, can_fail, maybe(set(prog_var)),
|
|
store_map, branch_end, branch_end, code_tree,
|
|
code_info, code_info).
|
|
:- mode lookup_switch__generate(in, in, in, in, in, in, in, in, in,
|
|
in, out, out, in, out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module builtin_ops, code_gen, type_util, tree.
|
|
:- import_module dense_switch, globals, options, mode_util.
|
|
:- import_module exprn_aux, getopt, prog_data, instmap.
|
|
|
|
:- import_module int, require, bool, assoc_list.
|
|
|
|
% Most of this predicate is taken from dense_switch.m
|
|
|
|
% We need the code_info structure to generate code for the cases to
|
|
% get the constants (if they exist). We can't throw it away at the
|
|
% end because we may have allocated some new static ground term labels.
|
|
lookup_switch__is_lookup_switch(CaseVar, TaggedCases, GoalInfo,
|
|
CanFail0, ReqDensity, CodeModel, FirstVal, LastVal,
|
|
NeedRangeCheck, NeedBitVecTest, OutVars,
|
|
CaseValues, MLiveness) -->
|
|
% Since lookup switches rely on static ground terms to
|
|
% work efficiently, there is no point in using a lookup
|
|
% switch if static-ground-terms are not enabled. Well,
|
|
% actually, it is possible that they might be a win in
|
|
% some circumstances, but it would take a pretty complex
|
|
% heuristic to get it right, so, lets just use a simple
|
|
% one - no static ground terms, no lookup switch.
|
|
code_info__get_globals(Globals),
|
|
{ globals__get_options(Globals, Options) },
|
|
{ getopt__lookup_bool_option(Options, static_ground_terms, yes) },
|
|
{
|
|
% We want to generate a lookup switch for any switch
|
|
% that is dense enough - we don't care how many cases
|
|
% it has. A memory lookup tends to be cheaper than
|
|
% a branch.
|
|
list__length(TaggedCases, NumCases),
|
|
TaggedCases = [FirstCase | _],
|
|
FirstCase = case(_, int_constant(FirstCaseVal), _, _),
|
|
list__index1_det(TaggedCases, NumCases, LastCase),
|
|
LastCase = case(_, int_constant(LastCaseVal), _, _),
|
|
Span is LastCaseVal - FirstCaseVal,
|
|
Range is Span + 1,
|
|
dense_switch__calc_density(NumCases, Range, Density),
|
|
Density > ReqDensity
|
|
},
|
|
% If there are going to be no gaps in the lookup
|
|
% table then we won't need a bitvector test to see
|
|
% if this switch has a value for this case.
|
|
(
|
|
{ NumCases = Range }
|
|
->
|
|
{ NeedBitVecTest0 = cannot_fail }
|
|
;
|
|
{ NeedBitVecTest0 = can_fail }
|
|
),
|
|
( { CanFail0 = can_fail } ->
|
|
% For semidet switches, we normally need to check that
|
|
% the variable is in range before we index into the jump table.
|
|
% However, if the range of the type is sufficiently small,
|
|
% we can make the jump table large enough to hold all
|
|
% of the values for the type, but then we will need to do the
|
|
% bitvector test.
|
|
code_info__variable_type(CaseVar, Type),
|
|
code_info__get_module_info(ModuleInfo),
|
|
{ classify_type(Type, ModuleInfo, TypeCategory) },
|
|
(
|
|
dense_switch__type_range(TypeCategory, Type, TypeRange),
|
|
{ dense_switch__calc_density(NumCases, TypeRange, DetDensity) },
|
|
{ DetDensity > ReqDensity }
|
|
->
|
|
{ NeedRangeCheck = cannot_fail },
|
|
{ NeedBitVecTest = can_fail },
|
|
{ FirstVal = 0 },
|
|
{ LastVal is TypeRange - 1 }
|
|
;
|
|
{ NeedRangeCheck = CanFail0 },
|
|
{ NeedBitVecTest = NeedBitVecTest0 },
|
|
{ FirstVal = FirstCaseVal },
|
|
{ LastVal = LastCaseVal }
|
|
)
|
|
;
|
|
{ NeedRangeCheck = CanFail0 },
|
|
{ NeedBitVecTest = NeedBitVecTest0 },
|
|
{ FirstVal = FirstCaseVal },
|
|
{ LastVal = LastCaseVal }
|
|
),
|
|
lookup_switch__figure_out_output_vars(GoalInfo, OutVars),
|
|
lookup_switch__generate_constants(TaggedCases, OutVars, CodeModel,
|
|
CaseValues, MLiveness).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred lookup_switch__figure_out_output_vars(hlds_goal_info, list(prog_var),
|
|
code_info, code_info).
|
|
:- mode lookup_switch__figure_out_output_vars(in, out, in, out) is det.
|
|
|
|
% Figure out which variables are bound in the switch.
|
|
% We do this by using the current instmap and the instmap delta in
|
|
% the goal info to work out which variables are [further] bound by
|
|
% the switch.
|
|
|
|
lookup_switch__figure_out_output_vars(GoalInfo, OutVars) -->
|
|
{ goal_info_get_instmap_delta(GoalInfo, InstMapDelta) },
|
|
(
|
|
{ instmap_delta_is_unreachable(InstMapDelta) }
|
|
->
|
|
{ OutVars = [] }
|
|
;
|
|
code_info__get_instmap(CurrentInstMap),
|
|
code_info__get_module_info(ModuleInfo),
|
|
{ instmap_delta_changed_vars(InstMapDelta, ChangedVars) },
|
|
{ instmap__apply_instmap_delta(CurrentInstMap, InstMapDelta,
|
|
InstMapAfter) },
|
|
{ Lambda = lambda([Var::out] is nondet, (
|
|
% If a variable has a final inst, then it changed
|
|
% instantiatedness during the switch.
|
|
set__member(Var, ChangedVars),
|
|
instmap__lookup_var(CurrentInstMap, Var, Initial),
|
|
instmap__lookup_var(InstMapAfter, Var, Final),
|
|
mode_is_output(ModuleInfo, (Initial -> Final))
|
|
)) },
|
|
{ solutions(Lambda, OutVars) }
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred lookup_switch__generate_constants(cases_list, list(prog_var),
|
|
code_model, case_consts, maybe(set(prog_var)),
|
|
code_info, code_info).
|
|
:- mode lookup_switch__generate_constants(in, in, in, out, out,
|
|
in, out) is semidet.
|
|
|
|
% To figure out if the outputs are constants, we generate code for
|
|
% the cases, and check to see if each of the output vars is a constant,
|
|
% and that no actual code was generated for the goal.
|
|
lookup_switch__generate_constants([], _Vars, _CodeModel, [], no) --> [].
|
|
lookup_switch__generate_constants([Case|Cases], Vars, CodeModel,
|
|
[CaseVal|Rest], yes(Liveness)) -->
|
|
{ Case = case(_, int_constant(CaseTag), _, Goal) },
|
|
code_info__remember_position(BranchStart),
|
|
code_gen__generate_goal(CodeModel, Goal, Code),
|
|
code_info__get_forward_live_vars(Liveness),
|
|
{ tree__tree_of_lists_is_empty(Code) },
|
|
lookup_switch__get_case_rvals(Vars, CaseRvals),
|
|
{ CaseVal = CaseTag - CaseRvals },
|
|
code_info__reset_to_position(BranchStart),
|
|
lookup_switch__generate_constants(Cases, Vars, CodeModel, Rest, _).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred lookup_switch__get_case_rvals(list(prog_var), list(rval),
|
|
code_info, code_info).
|
|
:- mode lookup_switch__get_case_rvals(in, out, in, out) is semidet.
|
|
|
|
lookup_switch__get_case_rvals([], []) --> [].
|
|
lookup_switch__get_case_rvals([Var|Vars], [Rval|Rvals]) -->
|
|
code_info__produce_variable(Var, Code, Rval),
|
|
{ tree__tree_of_lists_is_empty(Code) },
|
|
code_info__get_globals(Globals),
|
|
{ globals__get_options(Globals, Options) },
|
|
{ exprn_aux__init_exprn_opts(Options, ExprnOpts) },
|
|
{ lookup_switch__rval_is_constant(Rval, ExprnOpts) },
|
|
lookup_switch__get_case_rvals(Vars, Rvals).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% lookup_switch__rval_is_constant(Rval, ExprnOpts) is
|
|
% true iff Rval is a constant. This depends on the options governing
|
|
% nonlocal gotos, asm labels enabled, and static ground terms, etc.
|
|
:- pred lookup_switch__rval_is_constant(rval, exprn_opts).
|
|
:- mode lookup_switch__rval_is_constant(in, in) is semidet.
|
|
|
|
% Based on code_exprn__rval_is_constant, but differs in
|
|
% that it doesn't happen with respect to the expresion cache.
|
|
|
|
lookup_switch__rval_is_constant(const(Const), ExprnOpts) :-
|
|
exprn_aux__const_is_constant(Const, ExprnOpts, yes).
|
|
lookup_switch__rval_is_constant(unop(_, Exprn), ExprnOpts) :-
|
|
lookup_switch__rval_is_constant(Exprn, ExprnOpts).
|
|
lookup_switch__rval_is_constant(binop(_, Exprn0, Exprn1), ExprnOpts) :-
|
|
lookup_switch__rval_is_constant(Exprn0, ExprnOpts),
|
|
lookup_switch__rval_is_constant(Exprn1, ExprnOpts).
|
|
lookup_switch__rval_is_constant(mkword(_, Exprn0), ExprnOpts) :-
|
|
lookup_switch__rval_is_constant(Exprn0, ExprnOpts).
|
|
lookup_switch__rval_is_constant(create(_, Args, _, StatDyn, _,_), ExprnOpts) :-
|
|
(
|
|
StatDyn = must_be_static
|
|
;
|
|
ExprnOpts = nlg_asm_sgt_ubf(_, _, StaticGroundTerms, _),
|
|
StaticGroundTerms = yes,
|
|
lookup_switch__rvals_are_constant(Args, ExprnOpts)
|
|
).
|
|
|
|
:- pred lookup_switch__rvals_are_constant(list(maybe(rval)), exprn_opts).
|
|
:- mode lookup_switch__rvals_are_constant(in, in) is semidet.
|
|
|
|
lookup_switch__rvals_are_constant([], _).
|
|
lookup_switch__rvals_are_constant([MRval|MRvals], ExprnOpts) :-
|
|
MRval = yes(Rval),
|
|
lookup_switch__rval_is_constant(Rval, ExprnOpts),
|
|
lookup_switch__rvals_are_constant(MRvals, ExprnOpts).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
lookup_switch__generate(Var, OutVars, CaseValues,
|
|
StartVal, EndVal, NeedRangeCheck, NeedBitVecCheck,
|
|
MLiveness, StoreMap, MaybeEnd0, MaybeEnd, Code) -->
|
|
% Evaluate the variable which we are going to be switching on
|
|
code_info__produce_variable(Var, VarCode, Rval),
|
|
% If the case values start at some number other than 0,
|
|
% then subtract that number to give us a zero-based index
|
|
{ StartVal = 0 ->
|
|
Index = Rval
|
|
;
|
|
Index = binop(-, Rval, const(int_const(StartVal)))
|
|
},
|
|
% If the switch is not locally deterministic, we need to
|
|
% check that the value of the variable lies within the
|
|
% appropriate range
|
|
(
|
|
{ NeedRangeCheck = can_fail },
|
|
{ Difference is EndVal - StartVal },
|
|
code_info__fail_if_rval_is_false(
|
|
binop(<=, unop(cast_to_unsigned, Index),
|
|
const(int_const(Difference))), RangeCheck)
|
|
;
|
|
{ NeedRangeCheck = cannot_fail },
|
|
{ RangeCheck = empty }
|
|
),
|
|
(
|
|
{ NeedBitVecCheck = can_fail },
|
|
lookup_switch__generate_bitvec_test(Index, CaseValues,
|
|
StartVal, EndVal, CheckBitVec)
|
|
;
|
|
{ NeedBitVecCheck = cannot_fail },
|
|
{ CheckBitVec = empty }
|
|
),
|
|
% Now generate the terms into which we do the lookups
|
|
lookup_switch__generate_terms(Index, OutVars, CaseValues, StartVal),
|
|
% We keep track of what variables are supposed to be
|
|
% live at the end of cases. We have to do this explicitly
|
|
% because generating a `fail' slot last would yield the
|
|
% wrong liveness.
|
|
(
|
|
{ MLiveness = yes(Liveness) },
|
|
code_info__set_forward_live_vars(Liveness)
|
|
;
|
|
{ MLiveness = no },
|
|
{ error("lookup_switch__generate: no liveness!") }
|
|
),
|
|
code_info__generate_branch_end(StoreMap, MaybeEnd0, MaybeEnd,
|
|
LookupCode),
|
|
% Assemble to code together
|
|
{ Comment = node([comment("lookup switch") - ""]) },
|
|
{ Code =
|
|
tree(Comment,
|
|
tree(VarCode,
|
|
tree(RangeCheck,
|
|
tree(CheckBitVec,
|
|
LookupCode))))
|
|
}.
|
|
|
|
%------------------------------------------------------------------------------%
|
|
|
|
:- pred lookup_switch__generate_bitvec_test(rval, case_consts, int, int,
|
|
code_tree, code_info, code_info).
|
|
:- mode lookup_switch__generate_bitvec_test(in, in, in, in, out,
|
|
in, out) is det.
|
|
|
|
% 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.
|
|
lookup_switch__generate_bitvec_test(Index, CaseVals, Start, _End,
|
|
CheckCode) -->
|
|
lookup_switch__get_word_bits(WordBits),
|
|
generate_bit_vec(CaseVals, Start, WordBits, BitVec),
|
|
|
|
{ UIndex = unop(cast_to_unsigned, Index) },
|
|
%
|
|
% 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. Otherwise, the high bits
|
|
% of the index specify which word to use and the
|
|
% low bits specify which bit.
|
|
%
|
|
{
|
|
BitVec = create(_, [yes(SingleWord)], _, _, _, _)
|
|
->
|
|
Word = SingleWord,
|
|
BitNum = UIndex
|
|
;
|
|
WordNum = binop(/, UIndex, const(int_const(WordBits))),
|
|
Word = lval(field(yes(0), BitVec, WordNum)),
|
|
BitNum = binop(mod, UIndex, const(int_const(WordBits)))
|
|
},
|
|
{ HasBit = binop((&),
|
|
binop((<<), const(int_const(1)), BitNum),
|
|
Word) },
|
|
code_info__fail_if_rval_is_false(HasBit, CheckCode).
|
|
|
|
|
|
:- pred lookup_switch__get_word_bits(int, code_info, code_info).
|
|
:- mode lookup_switch__get_word_bits(out, in, out) is det.
|
|
|
|
% Prevent cross-compilation errors by making sure that
|
|
% the bitvector uses a number of bits that will fit both
|
|
% on this machine (so that we can correctly generate it),
|
|
% and on the target machine (so that it can be executed
|
|
% correctly)
|
|
|
|
lookup_switch__get_word_bits(WordBits) -->
|
|
{ int__bits_per_int(HostWordBits) },
|
|
code_info__get_globals(Globals),
|
|
{ globals__get_options(Globals, Options) },
|
|
{ getopt__lookup_int_option(Options, bits_per_word, TargetWordBits) },
|
|
{ int__min(HostWordBits, TargetWordBits, WordBits) }.
|
|
|
|
:- pred generate_bit_vec(case_consts, int, int, rval, code_info, code_info).
|
|
:- mode generate_bit_vec(in, in, in, out, in, out) is det.
|
|
|
|
% 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.
|
|
generate_bit_vec(CaseVals, Start, WordBits, BitVec) -->
|
|
{ map__init(Empty) },
|
|
{ generate_bit_vec_2(CaseVals, Start, WordBits, Empty, BitMap) },
|
|
{ map__to_assoc_list(BitMap, WordVals) },
|
|
{ generate_bit_vec_args(WordVals, 0, Args) },
|
|
code_info__get_next_cell_number(CellNo),
|
|
{ BitVec = create(0, Args, uniform(no), must_be_static,
|
|
CellNo, "lookup_switch_bit_vector") }.
|
|
|
|
:- pred generate_bit_vec_2(case_consts, int, int,
|
|
map(int, int), map(int, int)).
|
|
:- mode generate_bit_vec_2(in, in, in, in, out) is det.
|
|
|
|
generate_bit_vec_2([], _, _, Bits, Bits).
|
|
generate_bit_vec_2([Tag-_|Rest], Start, WordBits, Bits0, Bits) :-
|
|
Val is Tag - Start,
|
|
Word is Val // WordBits,
|
|
Offset is Val mod WordBits,
|
|
(
|
|
map__search(Bits0, Word, X0)
|
|
->
|
|
X1 is X0 \/ (1 << Offset)
|
|
;
|
|
X1 is (1 << Offset)
|
|
),
|
|
map__set(Bits0, Word, X1, Bits1),
|
|
generate_bit_vec_2(Rest, Start, WordBits, Bits1, Bits).
|
|
|
|
:- pred generate_bit_vec_args(list(pair(int)), int, list(maybe(rval))).
|
|
:- mode generate_bit_vec_args(in, in, out) is det.
|
|
|
|
generate_bit_vec_args([], _, []).
|
|
generate_bit_vec_args([Word - Bits|Rest], Count, [yes(Rval)|Rvals]) :-
|
|
(
|
|
Count < Word
|
|
->
|
|
WordVal = 0,
|
|
Remainder = [Word - Bits|Rest]
|
|
;
|
|
WordVal = Bits,
|
|
Remainder = Rest
|
|
),
|
|
Rval = const(int_const(WordVal)),
|
|
Count1 is Count + 1,
|
|
generate_bit_vec_args(Remainder, Count1, Rvals).
|
|
|
|
%------------------------------------------------------------------------------%
|
|
|
|
:- pred lookup_switch__generate_terms(rval, list(prog_var),
|
|
case_consts, int, code_info, code_info).
|
|
:- mode lookup_switch__generate_terms(in, in, in, in, in, out) is det.
|
|
|
|
% Add an expression to the expression cache in the code_info
|
|
% structure for each of the output variables of the lookup
|
|
% switch. This is done by creating a `create' term for the
|
|
% array, and caching an expression for the variable to get the
|
|
% Index'th field of that therm.
|
|
|
|
lookup_switch__generate_terms(Index, OutVars, CaseVals, Start) -->
|
|
{ map__init(Empty) },
|
|
{ rearrange_vals(OutVars, CaseVals, Start, Empty, ValMap) },
|
|
lookup_switch__generate_terms_2(Index, OutVars, ValMap).
|
|
|
|
:- pred lookup_switch__generate_terms_2(rval, list(prog_var),
|
|
rval_map, code_info, code_info).
|
|
:- mode lookup_switch__generate_terms_2(in, in, in, in, out) is det.
|
|
|
|
lookup_switch__generate_terms_2(_Index, [], _Map) --> [].
|
|
lookup_switch__generate_terms_2(Index, [Var|Vars], Map) -->
|
|
{ map__lookup(Map, Var, Vals0) },
|
|
{ list__sort(Vals0, Vals) },
|
|
{ construct_args(Vals, 0, Args) },
|
|
code_info__get_next_cell_number(CellNo),
|
|
{ ArrayTerm = create(0, Args, uniform(no), must_be_static,
|
|
CellNo, "lookup_switch_data") },
|
|
{ LookupTerm = lval(field(yes(0), ArrayTerm, Index)) },
|
|
code_info__cache_expression(Var, LookupTerm),
|
|
lookup_switch__generate_terms_2(Index, Vars, Map).
|
|
|
|
:- pred construct_args(list(pair(int, rval)), int, list(maybe(rval))).
|
|
:- mode construct_args(in, in, out) is det.
|
|
|
|
construct_args([], _, []).
|
|
construct_args([Index - Rval|Rest], Count0, [yes(Arg)|Args]) :-
|
|
(
|
|
Count0 < Index
|
|
->
|
|
% If this argument (array element) is a place-holder and
|
|
% will never be referenced, just fill it in with a `0'
|
|
Arg = const(int_const(0)),
|
|
Remainder = [Index - Rval|Rest]
|
|
;
|
|
Arg = Rval,
|
|
Remainder = Rest
|
|
),
|
|
Count1 is Count0 + 1,
|
|
construct_args(Remainder, Count1, Args).
|
|
|
|
%------------------------------------------------------------------------------%
|
|
|
|
:- pred rearrange_vals(list(prog_var), case_consts, int, rval_map, rval_map).
|
|
:- mode rearrange_vals(in, in, in, in, out) is det.
|
|
|
|
% For the purpose of constructing the terms, the case_consts
|
|
% structure is a bit inconvenient, so we rearrange the data
|
|
% into a map from var to list of tag-value pairs.
|
|
rearrange_vals(_Vars, [], _Start, Map, Map).
|
|
rearrange_vals(Vars, [Tag - Rvals|Rest], Start, Map0, Map) :-
|
|
assoc_list__from_corresponding_lists(Vars, Rvals, Pairs),
|
|
Index is Tag - Start,
|
|
rearrange_vals_2(Pairs, Index, Map0, Map1),
|
|
rearrange_vals(Vars, Rest, Start, Map1, Map).
|
|
|
|
:- pred rearrange_vals_2(list(pair(prog_var, rval)), int, rval_map, rval_map).
|
|
:- mode rearrange_vals_2(in, in, in, out) is det.
|
|
|
|
rearrange_vals_2([], _, Map, Map).
|
|
rearrange_vals_2([Var - Rval|Rest], Tag, Map0, Map) :-
|
|
(
|
|
map__search(Map0, Var, Vals0)
|
|
->
|
|
Vals = [Tag - Rval|Vals0]
|
|
;
|
|
Vals = [Tag - Rval]
|
|
),
|
|
map__set(Map0, Var, Vals, Map1),
|
|
rearrange_vals_2(Rest, Tag, Map1, Map).
|
|
|
|
%------------------------------------------------------------------------------%
|