mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-18 15:26:31 +00:00
Estimated hours taken: 40
Branches: main
Implement lookup switches in which a switch arm may contain more than one
solution, such as this code here:
p(d, "four", f1, 4.4).
p(e, "five", f2, 5.5).
p(e, "five2", f3(5), 55.5).
p(f, "six", f4("hex"), 6.6).
p(g, "seven", f5(77.7), 7.7).
p(g, "seven2", f1, 777.7).
p(g, "seven3", f2, 7777.7).
Such code occurs frequently in benchmark programs used to evaluate the
performance of tabled logic programming systems.
Change frameopt.m, which previously worked only on det and semidet code,
to also work for nondet code. For predicates such as the one above, frameopt
can now arrange for the predicate's nondet stack frame to be created only
when a switch arm that has more than one solution is selected.
compiler/lookup_switch.m:
Extend the existing code for recognizing and implementing lookup
switches to recognize and implement them even if they are model_non.
compiler/lookup_util.m:
New module containing utility predicates useful for implementing
both lookup switches, and in the future, lookup disjunctions (i.e.
disjunctions that correspond to a nondet arm of a lookup switch).
compiler/ll_backend.m:
Include the new module.
compiler/notes/compiler_design.html:
Mention the new module.
compiler/global_data.m:
Move the job of filling in dummy slots to our caller, in this case
lookup_switch.m.
compiler/frameopt.m:
Generalize the existing code for delaying stack frame creation,
which worked only on predicates that live on the det stack, to work
also on predicates that live on the nondet stack. Without this,
predicates whose bodies are model_non lookup switches would create
a nonstack stack frame before the switch is ever entered, which
is wasteful if the selected switch arm has at most one solution.
Since the structure of model_non predicates is more complex (you can
cause a branch to a label by storing its address in a redoip slot,
you can succeed from the frame without removing the frame), this
required considerable extra work. To make the new code debuggable,
record, for each basic block that needs a stack frame, *why* it
needs that stack frame.
compiler/opt_util.m:
Be more conservative about what refers to the stack. Export some
previously internal functionality for frameopt. Turn some predicates
into functions, and rename them to better reflect their purpose.
compiler/opt_debug.m:
Print much more information about pragma_c and call LLDS instructions.
compiler/prog_data.m:
Add an extra attribute to foreign_procs that says that the code
of the foreign_proc assumes the existence of a stack frame.
This is needed to avoid frameopt optimizing the stack frame away.
compiler/add_pragma.m:
When processing fact tables, we create foreign_procs that assume
the existence of the stack frame, so set the new attribute.
compiler/pragma_c_gen.m:
When processing foreign_procs, transmit the information in the
attribute to the generated LLDS code.
compiler/llds.m:
Rename the function symbols referring to the fixed slots in nondet
stack frames to make them clearer and to avoid overloading function
symbols such as curfr and succip.
Rename the function symbols of the call_model type to avoid overloading
the function symbols of the code_model type.
Add a new field to the c_procedure type giving the code_model of the
procedure, and give names to all the fields.
Describe the stack slots used by lookup switches to the debugger
and native gc.
compiler/options.m:
doc/user_guide.texi:
Add a new option, --debug-opt-pred-name, that does when the existing
--debug-opt-pred-id options does, but taking a user-friendly predicate
name rather than a pred_id as its argument.
compiler/handle_options.m:
Process --debug-opt-pred-name, and make --frameopt-comments imply
--auto-comments, since it is not useful without it.
Reformat some existing comments that were written in the days of
8-space indentation.
compiler/optimize.m:
Implement the new option.
Use the new field of the c_procedure type to try only the version
of frameopt appropriate for the code model of the current procedure.
Do a peephole pass after frameopt, since frameopt can generate code
sequences that peephole can optimize.
Make the mechanism for recording the process of optimizing procedure
bodies more easily usable by including the name of the optimization
that created a given version of the code in the name of the file
that contains that version of the code, and ensuring that all numbers
are two characters long, so that "vi procname*.opt*" looks at the
relevant files in the proper chronological sequence, instead of having
version 11 appear before version 2.
compiler/peephole.m:
Add a new optimization pattern: a "mkframe, goto fail" pair (which
can be generated by frameopt) should be replaced by a simple "goto
redo".
compiler/code_gen.m:
Factor out some common code.
compiler/llds_out.m:
Ensure that C comments nested inside comment(_) LLDS instructions
aren't emitted as nested C comments, since C compilers cannot handle
these.
compiler/code_info.m:
compiler/code_util.m:
compiler/continuation_info.m:
compiler/dupelim.m:
compiler/exprn_aux.m:
compiler/jumpopt.m:
compiler/livemap.m:
compiler/llds_out.m:
compiler/mercury_compile.m:
compiler/middle_rec.m:
compiler/ml_code_gen.m:
compiler/opt_debug.m:
compiler/opt_util.m:
compiler/peephole.m:
compiler/stack_layout.m:
compiler/transform_llds.m:
compiler/var_locn.m:
Conform to the change to prog_data.m, opt_util.m and/or llds.m.
compiler/handle_options.m:
Don't execute the code in stdlabel.m if doing so would cause a compiler
abort.
tests/hard_coded/dense_lookup_switch_non.{m,exp}:
New test case to exercise the new algorithm.
tests/hard_coded/Mmakefile:
Enable the new test case.
tests/hard_coded/cycles.m:
Make this test case conform to our coding convention.
452 lines
15 KiB
Mathematica
452 lines
15 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1994-2006 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.
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% File: code_util.m.
|
|
|
|
% Various utilities routines for code generation and recognition of builtins.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module ll_backend.code_util.
|
|
:- interface.
|
|
|
|
:- import_module hlds.hlds_goal.
|
|
:- import_module hlds.hlds_llds.
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module hlds.hlds_rtti.
|
|
:- import_module ll_backend.llds.
|
|
:- import_module mdbcomp.prim_data.
|
|
:- import_module parse_tree.prog_data.
|
|
|
|
:- import_module assoc_list.
|
|
:- import_module list.
|
|
:- import_module maybe.
|
|
:- import_module pair.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Create a code address which holds the address of the specified procedure.
|
|
% The `immed' argument should be `no' if the the caller wants the returned
|
|
% address to be valid from everywhere in the program. If being valid from
|
|
% within the current procedure is enough, this argument should be `yes'
|
|
% wrapped around the value of the --procs-per-c-function option and the
|
|
% current procedure id. Using an address that is only valid from within
|
|
% the current procedure may make jumps more efficient.
|
|
%
|
|
:- type immed == maybe(pair(int, pred_proc_id)).
|
|
:- pred make_entry_label(module_info::in, pred_id::in, proc_id::in, immed::in,
|
|
code_addr::out) is det.
|
|
|
|
:- pred make_entry_label_from_rtti(rtti_proc_label::in, immed::in,
|
|
code_addr::out) is det.
|
|
|
|
% Create a label which holds the address of the specified procedure,
|
|
% which must be defined in the current module (procedures that are
|
|
% imported from other modules have representations only as code_addrs,
|
|
% not as labels, since their address is not known at C compilation time).
|
|
% The fourth argument has the same meaning as for make_entry_label.
|
|
%
|
|
:- pred make_local_entry_label(module_info::in, pred_id::in, proc_id::in,
|
|
immed::in, label::out) is det.
|
|
|
|
% Create a label internal to a Mercury procedure.
|
|
%
|
|
:- pred make_internal_label(module_info::in, pred_id::in, proc_id::in, int::in,
|
|
label::out) is det.
|
|
|
|
:- pred extract_proc_label_from_code_addr(code_addr::in, proc_label::out)
|
|
is det.
|
|
|
|
:- pred arg_loc_to_register(arg_loc::in, lval::out) is det.
|
|
|
|
:- pred max_mentioned_reg(list(lval)::in, int::out) is det.
|
|
:- pred max_mentioned_abs_reg(list(abs_locn)::in, int::out) is det.
|
|
|
|
:- pred goal_may_alloc_temp_frame(hlds_goal::in) is semidet.
|
|
|
|
% Negate a condition.
|
|
% This is used mostly just to make the generated code more readable.
|
|
%
|
|
:- pred neg_rval(rval::in, rval::out) is det.
|
|
|
|
:- pred negate_the_test(list(instruction)::in, list(instruction)::out) is det.
|
|
|
|
% These predicates return the set of lvals referenced in an rval
|
|
% and an lval respectively. Lvals referenced indirectly through
|
|
% lvals of the form var(_) are not counted.
|
|
%
|
|
:- pred lvals_in_rval(rval::in, list(lval)::out) is det.
|
|
:- pred lvals_in_lval(lval::in, list(lval)::out) is det.
|
|
:- pred lvals_in_lvals(list(lval)::in, list(lval)::out) is det.
|
|
|
|
% Given a procedure that already has its arg_info field filled in,
|
|
% return a list giving its input variables and their initial locations.
|
|
%
|
|
:- pred build_input_arg_list(proc_info::in, assoc_list(prog_var, lval)::out)
|
|
is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module backend_libs.builtin_ops.
|
|
:- import_module backend_libs.proc_label.
|
|
:- import_module backend_libs.rtti.
|
|
:- import_module hlds.code_model.
|
|
:- import_module hlds.goal_form.
|
|
:- import_module hlds.special_pred.
|
|
:- import_module libs.compiler_util.
|
|
:- import_module libs.options.
|
|
:- import_module parse_tree.prog_util.
|
|
|
|
:- import_module bool.
|
|
:- import_module char.
|
|
:- import_module int.
|
|
:- import_module set.
|
|
:- import_module string.
|
|
:- import_module term.
|
|
:- import_module varset.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
make_entry_label(ModuleInfo, PredId, ProcId, Immed, ProcAddr) :-
|
|
RttiProcLabel = rtti.make_rtti_proc_label(ModuleInfo, PredId, ProcId),
|
|
make_entry_label_from_rtti(RttiProcLabel, Immed, ProcAddr).
|
|
|
|
make_entry_label_from_rtti(RttiProcLabel, Immed, ProcAddr) :-
|
|
( RttiProcLabel ^ proc_is_imported = yes ->
|
|
ProcLabel = make_proc_label_from_rtti(RttiProcLabel),
|
|
ProcAddr = imported(ProcLabel)
|
|
;
|
|
make_local_entry_label_from_rtti(RttiProcLabel, Immed, Label),
|
|
ProcAddr = label(Label)
|
|
).
|
|
|
|
make_local_entry_label(ModuleInfo, PredId, ProcId, Immed, Label) :-
|
|
RttiProcLabel = rtti.make_rtti_proc_label(ModuleInfo, PredId, ProcId),
|
|
make_local_entry_label_from_rtti(RttiProcLabel, Immed, Label).
|
|
|
|
:- pred make_local_entry_label_from_rtti(rtti_proc_label::in,
|
|
immed::in, label::out) is det.
|
|
|
|
make_local_entry_label_from_rtti(RttiProcLabel, Immed, Label) :-
|
|
ProcLabel = make_proc_label_from_rtti(RttiProcLabel),
|
|
(
|
|
Immed = no,
|
|
% If we want to define the label or use it to put it into a data
|
|
% structure, a label that is usable only within the current C module
|
|
% won't do.
|
|
( RttiProcLabel ^ proc_is_exported = yes ->
|
|
EntryType = exported
|
|
;
|
|
EntryType = local
|
|
),
|
|
Label = entry(EntryType, ProcLabel)
|
|
;
|
|
Immed = yes(ProcsPerFunc - proc(CurPredId, CurProcId)),
|
|
choose_local_label_type(ProcsPerFunc, CurPredId, CurProcId,
|
|
RttiProcLabel^pred_id, RttiProcLabel^proc_id,
|
|
ProcLabel, Label)
|
|
).
|
|
|
|
:- pred choose_local_label_type(int::in, pred_id::in, proc_id::in,
|
|
pred_id::in, proc_id::in, proc_label::in, label::out) is det.
|
|
|
|
choose_local_label_type(ProcsPerFunc, CurPredId, CurProcId,
|
|
PredId, ProcId, ProcLabel, Label) :-
|
|
(
|
|
% If we want to branch to the label now, we prefer a form that is
|
|
% usable only within the current C module, since it is likely to be
|
|
% faster.
|
|
(
|
|
ProcsPerFunc = 0
|
|
;
|
|
PredId = CurPredId,
|
|
ProcId = CurProcId
|
|
)
|
|
->
|
|
EntryType = c_local
|
|
;
|
|
EntryType = local
|
|
),
|
|
Label = entry(EntryType, ProcLabel).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
make_internal_label(ModuleInfo, PredId, ProcId, LabelNum, Label) :-
|
|
ProcLabel = make_proc_label(ModuleInfo, PredId, ProcId),
|
|
Label = internal(LabelNum, ProcLabel).
|
|
|
|
extract_proc_label_from_code_addr(CodeAddr, ProcLabel) :-
|
|
( CodeAddr = label(Label) ->
|
|
ProcLabel = get_proc_label(Label)
|
|
; CodeAddr = imported(ProcLabelPrime) ->
|
|
ProcLabel = ProcLabelPrime
|
|
;
|
|
unexpected(this_file, "extract_label_from_code_addr failed")
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
arg_loc_to_register(ArgLoc, reg(r, ArgLoc)).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
max_mentioned_reg(Lvals, MaxRegNum) :-
|
|
max_mentioned_reg_2(Lvals, 0, MaxRegNum).
|
|
|
|
:- pred max_mentioned_reg_2(list(lval)::in, int::in, int::out) is det.
|
|
|
|
max_mentioned_reg_2([], !MaxRegNum).
|
|
max_mentioned_reg_2([Lval | Lvals], !MaxRegNum) :-
|
|
( Lval = reg(r, N) ->
|
|
int.max(N, !MaxRegNum)
|
|
;
|
|
true
|
|
),
|
|
max_mentioned_reg_2(Lvals, !MaxRegNum).
|
|
|
|
max_mentioned_abs_reg(Lvals, MaxRegNum) :-
|
|
max_mentioned_abs_reg_2(Lvals, 0, MaxRegNum).
|
|
|
|
:- pred max_mentioned_abs_reg_2(list(abs_locn)::in, int::in, int::out) is det.
|
|
|
|
max_mentioned_abs_reg_2([], !MaxRegNum).
|
|
max_mentioned_abs_reg_2([Lval | Lvals], !MaxRegNum) :-
|
|
( Lval = abs_reg(N) ->
|
|
int.max(N, !MaxRegNum)
|
|
;
|
|
true
|
|
),
|
|
max_mentioned_abs_reg_2(Lvals, !MaxRegNum).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
goal_may_alloc_temp_frame(Goal) :-
|
|
goal_may_alloc_temp_frame(Goal, yes).
|
|
|
|
:- pred goal_may_alloc_temp_frame(hlds_goal::in, bool::out) is det.
|
|
|
|
goal_may_alloc_temp_frame(Goal - _GoalInfo, May) :-
|
|
goal_may_alloc_temp_frame_2(Goal, May).
|
|
|
|
:- pred goal_may_alloc_temp_frame_2(hlds_goal_expr::in, bool::out)
|
|
is det.
|
|
|
|
goal_may_alloc_temp_frame_2(generic_call(_, _, _, _), no).
|
|
goal_may_alloc_temp_frame_2(call(_, _, _, _, _, _), no).
|
|
goal_may_alloc_temp_frame_2(unify(_, _, _, _, _), no).
|
|
% We cannot safely say that a foreign code fragment does not allocate
|
|
% temporary nondet frames without knowing all the #defined macros
|
|
% that expand to mktempframe and variants thereof. The performance
|
|
% impact of being too conservative is probably not too bad.
|
|
goal_may_alloc_temp_frame_2(foreign_proc(_, _, _, _, _, _), yes).
|
|
goal_may_alloc_temp_frame_2(scope(_, Goal), May) :-
|
|
Goal = _ - GoalInfo,
|
|
goal_info_get_code_model(GoalInfo, CodeModel),
|
|
( CodeModel = model_non ->
|
|
May = yes
|
|
;
|
|
goal_may_alloc_temp_frame(Goal, May)
|
|
).
|
|
goal_may_alloc_temp_frame_2(not(Goal), May) :-
|
|
goal_may_alloc_temp_frame(Goal, May).
|
|
goal_may_alloc_temp_frame_2(conj(_ConjType, Goals), May) :-
|
|
goal_list_may_alloc_temp_frame(Goals, May).
|
|
goal_may_alloc_temp_frame_2(disj(Goals), May) :-
|
|
goal_list_may_alloc_temp_frame(Goals, May).
|
|
goal_may_alloc_temp_frame_2(switch(_Var, _Det, Cases), May) :-
|
|
cases_may_alloc_temp_frame(Cases, May).
|
|
goal_may_alloc_temp_frame_2(if_then_else(_Vars, C, T, E), May) :-
|
|
( goal_may_alloc_temp_frame(C, yes) ->
|
|
May = yes
|
|
; goal_may_alloc_temp_frame(T, yes) ->
|
|
May = yes
|
|
;
|
|
goal_may_alloc_temp_frame(E, May)
|
|
).
|
|
goal_may_alloc_temp_frame_2(shorthand(ShorthandGoal), May) :-
|
|
goal_may_alloc_temp_frame_2_shorthand(ShorthandGoal,May).
|
|
|
|
:- pred goal_may_alloc_temp_frame_2_shorthand(shorthand_goal_expr::in,
|
|
bool::out) is det.
|
|
|
|
goal_may_alloc_temp_frame_2_shorthand(bi_implication(G1, G2), May) :-
|
|
( goal_may_alloc_temp_frame(G1, yes) ->
|
|
May = yes
|
|
;
|
|
goal_may_alloc_temp_frame(G2, May)
|
|
).
|
|
|
|
:- pred goal_list_may_alloc_temp_frame(list(hlds_goal)::in, bool::out) is det.
|
|
|
|
goal_list_may_alloc_temp_frame([], no).
|
|
goal_list_may_alloc_temp_frame([Goal | Goals], May) :-
|
|
( goal_may_alloc_temp_frame(Goal, yes) ->
|
|
May = yes
|
|
;
|
|
goal_list_may_alloc_temp_frame(Goals, May)
|
|
).
|
|
|
|
:- pred cases_may_alloc_temp_frame(list(case)::in, bool::out) is det.
|
|
|
|
cases_may_alloc_temp_frame([], no).
|
|
cases_may_alloc_temp_frame([case(_, Goal) | Cases], May) :-
|
|
( goal_may_alloc_temp_frame(Goal, yes) ->
|
|
May = yes
|
|
;
|
|
cases_may_alloc_temp_frame(Cases, May)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
neg_rval(Rval, NegRval) :-
|
|
( neg_rval_2(Rval, NegRval0) ->
|
|
NegRval = NegRval0
|
|
;
|
|
NegRval = unop(logical_not, Rval)
|
|
).
|
|
|
|
:- pred neg_rval_2(rval::in, rval::out) is semidet.
|
|
|
|
neg_rval_2(const(Const), const(NegConst)) :-
|
|
(
|
|
Const = true,
|
|
NegConst = false
|
|
;
|
|
Const = false,
|
|
NegConst = true
|
|
).
|
|
neg_rval_2(unop(logical_not, Rval), Rval).
|
|
neg_rval_2(binop(Op, X, Y), binop(NegOp, X, Y)) :-
|
|
neg_op(Op, NegOp).
|
|
|
|
:- pred neg_op(binary_op::in, binary_op::out) is semidet.
|
|
|
|
neg_op(eq, ne).
|
|
neg_op(ne, eq).
|
|
neg_op(int_lt, int_ge).
|
|
neg_op(int_le, int_gt).
|
|
neg_op(int_gt, int_le).
|
|
neg_op(int_ge, int_lt).
|
|
neg_op(str_eq, str_ne).
|
|
neg_op(str_ne, str_eq).
|
|
neg_op(str_lt, str_ge).
|
|
neg_op(str_le, str_gt).
|
|
neg_op(str_gt, str_le).
|
|
neg_op(str_ge, str_lt).
|
|
neg_op(float_eq, float_ne).
|
|
neg_op(float_ne, float_eq).
|
|
neg_op(float_lt, float_ge).
|
|
neg_op(float_le, float_gt).
|
|
neg_op(float_gt, float_le).
|
|
neg_op(float_ge, float_lt).
|
|
|
|
negate_the_test([], _) :-
|
|
unexpected(this_file, "negate_the_test on empty list").
|
|
negate_the_test([Instr0 | Instrs0], Instrs) :-
|
|
( Instr0 = if_val(Test, Target) - Comment ->
|
|
neg_rval(Test, NewTest),
|
|
Instrs = [if_val(NewTest, Target) - Comment]
|
|
;
|
|
negate_the_test(Instrs0, Instrs1),
|
|
Instrs = [Instr0 | Instrs1]
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
lvals_in_lvals([], []).
|
|
lvals_in_lvals([First | Rest], FirstLvals ++ RestLvals) :-
|
|
lvals_in_lval(First, FirstLvals),
|
|
lvals_in_lvals(Rest, RestLvals).
|
|
|
|
lvals_in_rval(lval(Lval), [Lval | Lvals]) :-
|
|
lvals_in_lval(Lval, Lvals).
|
|
lvals_in_rval(var(_), []).
|
|
lvals_in_rval(mkword(_, Rval), Lvals) :-
|
|
lvals_in_rval(Rval, Lvals).
|
|
lvals_in_rval(const(_), []).
|
|
lvals_in_rval(unop(_, Rval), Lvals) :-
|
|
lvals_in_rval(Rval, Lvals).
|
|
lvals_in_rval(binop(_, Rval1, Rval2), Lvals1 ++ Lvals2) :-
|
|
lvals_in_rval(Rval1, Lvals1),
|
|
lvals_in_rval(Rval2, Lvals2).
|
|
lvals_in_rval(mem_addr(MemRef), Lvals) :-
|
|
lvals_in_mem_ref(MemRef, Lvals).
|
|
|
|
lvals_in_lval(reg(_, _), []).
|
|
lvals_in_lval(stackvar(_), []).
|
|
lvals_in_lval(framevar(_), []).
|
|
lvals_in_lval(succip, []).
|
|
lvals_in_lval(maxfr, []).
|
|
lvals_in_lval(curfr, []).
|
|
lvals_in_lval(succip_slot(Rval), Lvals) :-
|
|
lvals_in_rval(Rval, Lvals).
|
|
lvals_in_lval(redofr_slot(Rval), Lvals) :-
|
|
lvals_in_rval(Rval, Lvals).
|
|
lvals_in_lval(redoip_slot(Rval), Lvals) :-
|
|
lvals_in_rval(Rval, Lvals).
|
|
lvals_in_lval(succfr_slot(Rval), Lvals) :-
|
|
lvals_in_rval(Rval, Lvals).
|
|
lvals_in_lval(prevfr_slot(Rval), Lvals) :-
|
|
lvals_in_rval(Rval, Lvals).
|
|
lvals_in_lval(hp, []).
|
|
lvals_in_lval(sp, []).
|
|
lvals_in_lval(field(_, Rval1, Rval2), Lvals1 ++ Lvals2) :-
|
|
lvals_in_rval(Rval1, Lvals1),
|
|
lvals_in_rval(Rval2, Lvals2).
|
|
lvals_in_lval(lvar(_), []).
|
|
lvals_in_lval(temp(_, _), []).
|
|
lvals_in_lval(mem_ref(Rval), Lvals) :-
|
|
lvals_in_rval(Rval, Lvals).
|
|
|
|
:- pred lvals_in_mem_ref(mem_ref::in, list(lval)::out) is det.
|
|
|
|
lvals_in_mem_ref(stackvar_ref(Rval), Lvals) :-
|
|
lvals_in_rval(Rval, Lvals).
|
|
lvals_in_mem_ref(framevar_ref(Rval), Lvals) :-
|
|
lvals_in_rval(Rval, Lvals).
|
|
lvals_in_mem_ref(heap_ref(Rval1, _, Rval2), Lvals1 ++ Lvals2) :-
|
|
lvals_in_rval(Rval1, Lvals1),
|
|
lvals_in_rval(Rval2, Lvals2).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
build_input_arg_list(ProcInfo, VarLvals) :-
|
|
proc_info_get_headvars(ProcInfo, HeadVars),
|
|
proc_info_arg_info(ProcInfo, ArgInfos),
|
|
assoc_list.from_corresponding_lists(HeadVars, ArgInfos, VarArgInfos),
|
|
build_input_arg_list_2(VarArgInfos, VarLvals).
|
|
|
|
:- pred build_input_arg_list_2(assoc_list(prog_var, arg_info)::in,
|
|
assoc_list(prog_var, lval)::out) is det.
|
|
|
|
build_input_arg_list_2([], []).
|
|
build_input_arg_list_2([V - Arg | Rest0], VarArgs) :-
|
|
Arg = arg_info(Loc, Mode),
|
|
( Mode = top_in ->
|
|
arg_loc_to_register(Loc, Reg),
|
|
VarArgs = [V - Reg | VarArgs0]
|
|
;
|
|
VarArgs = VarArgs0
|
|
),
|
|
build_input_arg_list_2(Rest0, VarArgs0).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- func this_file = string.
|
|
|
|
this_file = "code_util.m".
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- end_module code_util.
|
|
%-----------------------------------------------------------------------------%
|