Files
mercury/compiler/code_util.m
Zoltan Somogyi 4954da84cc Reduce the dependence of the MLDS backend on the LLDS backend by moving
Estimated hours taken: 2
Branches: main

Reduce the dependence of the MLDS backend on the LLDS backend by moving
functionality dealing with proc_labels from the LLDS backend (code_util.m)
to a new module, proc_label.m, which is part of backend_libs.

compiler/code_util.m:
compiler/proc_label.m:
	Move a type and some code from code_util to the new module. Convert
	predicates to functions as relevant. (The old code was written before
	functions were available).

compiler/backend_libs.m:
	Add proc_label to the list of submodules.

compiler/rtti.m:
	Rename a function to avoid a name clash with a function in
	proc_label.m.

compiler/*.m:
	Conform to the changes above.

	Ensure that all imports of modules in the compiler directory are on
	lines of their own, to make CVS merges easier. Sort the imports.
2003-03-14 08:10:12 +00:00

859 lines
31 KiB
Mathematica

%-----------------------------------------------------------------------------%
% Copyright (C) 1994-2003 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 backend_libs__proc_label.
:- import_module backend_libs__rtti.
:- import_module hlds__hlds_data.
:- import_module hlds__hlds_goal.
:- import_module hlds__hlds_module.
:- import_module hlds__hlds_pred.
:- import_module ll_backend__llds.
:- import_module parse_tree__prog_data.
:- import_module list, std_util.
% 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 code_util__make_entry_label(module_info, pred_id, proc_id,
immed, code_addr).
:- mode code_util__make_entry_label(in, in, in, in, out) is det.
:- pred code_util__make_entry_label_from_rtti(rtti_proc_label, immed,
code_addr).
:- mode code_util__make_entry_label_from_rtti(in, in, 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
% code_util__make_entry_label.
:- pred code_util__make_local_entry_label(module_info, pred_id, proc_id,
immed, label).
:- mode code_util__make_local_entry_label(in, in, in, in, out) is det.
% Create a label internal to a Mercury procedure.
:- pred code_util__make_internal_label(module_info, pred_id, proc_id, int,
label).
:- mode code_util__make_internal_label(in, in, in, in, out) is det.
:- pred code_util__extract_proc_label_from_code_addr(code_addr, proc_label).
:- mode code_util__extract_proc_label_from_code_addr(in, out) is det.
:- pred code_util__extract_proc_label_from_label(label, proc_label).
:- mode code_util__extract_proc_label_from_label(in, out) is det.
:- pred code_util__arg_loc_to_register(arg_loc, lval).
:- mode code_util__arg_loc_to_register(in, out) is det.
:- pred code_util__max_mentioned_reg(list(lval), int).
:- mode code_util__max_mentioned_reg(in, out) is det.
% Determine whether a goal might allocate some heap space,
% i.e. whether it contains any construction unifications
% or predicate calls. BEWARE that this predicate is only
% an approximation, used to decide whether or not to try to
% reclaim the heap space; currently it fails even for some
% goals which do allocate heap space, such as construction
% of boxed constants.
:- pred code_util__goal_may_allocate_heap(hlds_goal).
:- mode code_util__goal_may_allocate_heap(in) is semidet.
:- pred code_util__goal_list_may_allocate_heap(list(hlds_goal)).
:- mode code_util__goal_list_may_allocate_heap(in) is semidet.
:- pred code_util__goal_may_alloc_temp_frame(hlds_goal).
:- mode code_util__goal_may_alloc_temp_frame(in) is semidet.
% Negate a condition.
% This is used mostly just to make the generated code more readable.
:- pred code_util__neg_rval(rval, rval).
:- mode code_util__neg_rval(in, out) is det.
:- pred code_util__negate_the_test(list(instruction), list(instruction)).
:- mode code_util__negate_the_test(in, out) is det.
% Find out how a function symbol (constructor) is represented
% in the given type.
:- pred code_util__cons_id_to_tag(cons_id, type, module_info, cons_tag).
:- mode code_util__cons_id_to_tag(in, in, in, out) is det.
% Succeed if execution of the given goal cannot encounter a context
% that causes any variable to be flushed to its stack slot.
% If such a goal needs a resume point, and that resume point cannot
% be backtracked to once control leaves the goal, then the only entry
% point we need for the resume point is the one with the resume
% variables in their original locations.
:- pred code_util__cannot_stack_flush(hlds_goal).
:- mode code_util__cannot_stack_flush(in) is semidet.
% Succeed if execution of the given goal cannot encounter a context
% that causes any variable to be flushed to its stack slot or to a
% register.
:- pred code_util__cannot_flush(hlds_goal).
:- mode code_util__cannot_flush(in) is semidet.
% Succeed if the given goal cannot fail before encountering a context
% that forces all variables to be flushed to their stack slots.
% If such a goal needs a resume point, the only entry point we need
% is the stack entry point.
:- pred code_util__cannot_fail_before_stack_flush(hlds_goal).
:- mode code_util__cannot_fail_before_stack_flush(in) is semidet.
% code_util__count_recursive_calls(Goal, PredId, ProcId, Min, Max)
% Given that we are in predicate PredId and procedure ProcId,
% return the minimum and maximum number of recursive calls that
% an execution of Goal may encounter.
:- pred code_util__count_recursive_calls(hlds_goal, pred_id, proc_id,
int, int).
:- mode code_util__count_recursive_calls(in, in, in, out, 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 code_util__lvals_in_rval(rval, list(lval)).
:- mode code_util__lvals_in_rval(in, out) is det.
:- pred code_util__lvals_in_lval(lval, list(lval)).
:- mode code_util__lvals_in_lval(in, out) is det.
:- pred code_util__lvals_in_lvals(list(lval), list(lval)).
:- mode code_util__lvals_in_lvals(in, out) is det.
%---------------------------------------------------------------------------%
:- implementation.
:- import_module backend_libs__builtin_ops.
:- import_module backend_libs__code_model.
:- import_module check_hlds__type_util.
:- import_module hlds__special_pred.
:- import_module libs__globals.
:- import_module libs__options.
:- import_module parse_tree__prog_util.
:- import_module bool, char, int, string, set, map, term, varset.
:- import_module require, std_util, assoc_list.
%---------------------------------------------------------------------------%
code_util__make_entry_label(ModuleInfo, PredId, ProcId, Immed, ProcAddr) :-
RttiProcLabel = rtti__make_rtti_proc_label(ModuleInfo, PredId, ProcId),
code_util__make_entry_label_from_rtti(RttiProcLabel, Immed, ProcAddr).
code_util__make_entry_label_from_rtti(RttiProcLabel, Immed, ProcAddr) :-
(
(
RttiProcLabel^is_imported = yes
;
RttiProcLabel^is_pseudo_imported = yes,
% only the (in, in) mode of unification is imported
hlds_pred__in_in_unification_proc_id(
RttiProcLabel^proc_id)
)
->
ProcLabel = make_proc_label_from_rtti(RttiProcLabel),
ProcAddr = imported(ProcLabel)
;
code_util__make_local_entry_label_from_rtti(RttiProcLabel,
Immed, Label),
ProcAddr = label(Label)
).
code_util__make_local_entry_label(ModuleInfo, PredId, ProcId, Immed, Label) :-
RttiProcLabel = rtti__make_rtti_proc_label(ModuleInfo, PredId, ProcId),
code_util__make_local_entry_label_from_rtti(RttiProcLabel,
Immed, Label).
:- pred code_util__make_local_entry_label_from_rtti(rtti_proc_label, immed,
label).
:- mode code_util__make_local_entry_label_from_rtti(in, in, out) is det.
code_util__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^is_exported = yes ->
Label = exported(ProcLabel)
;
Label = local(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, pred_id, proc_id,
pred_id, proc_id, proc_label, label).
:- mode choose_local_label_type(in, in, in, in, in, in, 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 are usable only within
% the current C module, since it is likely
% to be faster.
(
ProcsPerFunc = 0
;
PredId = CurPredId,
ProcId = CurProcId
)
->
Label = c_local(ProcLabel)
;
Label = local(ProcLabel)
).
%-----------------------------------------------------------------------------%
code_util__make_internal_label(ModuleInfo, PredId, ProcId, LabelNum, Label) :-
ProcLabel = make_proc_label(ModuleInfo, PredId, ProcId),
Label = local(LabelNum, ProcLabel).
code_util__extract_proc_label_from_code_addr(CodeAddr, ProcLabel) :-
( code_util__proc_label_from_code_addr(CodeAddr, ProcLabelPrime) ->
ProcLabel = ProcLabelPrime
;
error("code_util__extract_label_from_code_addr failed")
).
:- pred code_util__proc_label_from_code_addr(code_addr::in,
proc_label::out) is semidet.
code_util__proc_label_from_code_addr(CodeAddr, ProcLabel) :-
(
CodeAddr = label(Label),
code_util__extract_proc_label_from_label(Label, ProcLabel)
;
CodeAddr = imported(ProcLabel)
).
code_util__extract_proc_label_from_label(local(_, ProcLabel), ProcLabel).
code_util__extract_proc_label_from_label(c_local(ProcLabel), ProcLabel).
code_util__extract_proc_label_from_label(local(ProcLabel), ProcLabel).
code_util__extract_proc_label_from_label(exported(ProcLabel), ProcLabel).
%-----------------------------------------------------------------------------%
code_util__arg_loc_to_register(ArgLoc, reg(r, ArgLoc)).
%-----------------------------------------------------------------------------%
code_util__max_mentioned_reg(Lvals, MaxRegNum) :-
code_util__max_mentioned_reg_2(Lvals, 0, MaxRegNum).
:- pred code_util__max_mentioned_reg_2(list(lval)::in, int::in, int::out)
is det.
code_util__max_mentioned_reg_2([], MaxRegNum, MaxRegNum).
code_util__max_mentioned_reg_2([Lval | Lvals], MaxRegNum0, MaxRegNum) :-
( Lval = reg(r, N) ->
int__max(MaxRegNum0, N, MaxRegNum1)
;
MaxRegNum1 = MaxRegNum0
),
code_util__max_mentioned_reg_2(Lvals, MaxRegNum1, MaxRegNum).
%-----------------------------------------------------------------------------%
code_util__goal_may_allocate_heap(Goal) :-
code_util__goal_may_allocate_heap(Goal, yes).
code_util__goal_list_may_allocate_heap(Goals) :-
code_util__goal_list_may_allocate_heap(Goals, yes).
:- pred code_util__goal_may_allocate_heap(hlds_goal::in, bool::out) is det.
code_util__goal_may_allocate_heap(Goal - _GoalInfo, May) :-
code_util__goal_may_allocate_heap_2(Goal, May).
:- pred code_util__goal_may_allocate_heap_2(hlds_goal_expr::in, bool::out)
is det.
code_util__goal_may_allocate_heap_2(generic_call(_, _, _, _), yes).
code_util__goal_may_allocate_heap_2(call(_, _, _, Builtin, _, _), May) :-
( Builtin = inline_builtin ->
May = no
;
May = yes
).
code_util__goal_may_allocate_heap_2(unify(_, _, _, Unification, _), May) :-
( Unification = construct(_,_,Args,_,_,_,_), Args = [_|_] ->
May = yes
;
May = no
).
% We cannot safely say that a foreign code fragment does not
% allocate memory without knowing all the #defined macros that
% expand to incr_hp and variants thereof.
% XXX although you could make it an attribute of the foreign code and
% trust the programmer
code_util__goal_may_allocate_heap_2(foreign_proc(_,_,_,_,_,_,_), yes).
code_util__goal_may_allocate_heap_2(some(_Vars, _, Goal), May) :-
code_util__goal_may_allocate_heap(Goal, May).
code_util__goal_may_allocate_heap_2(not(Goal), May) :-
code_util__goal_may_allocate_heap(Goal, May).
code_util__goal_may_allocate_heap_2(conj(Goals), May) :-
code_util__goal_list_may_allocate_heap(Goals, May).
code_util__goal_may_allocate_heap_2(par_conj(_), yes).
code_util__goal_may_allocate_heap_2(disj(Goals), May) :-
code_util__goal_list_may_allocate_heap(Goals, May).
code_util__goal_may_allocate_heap_2(switch(_Var, _Det, Cases), May) :-
code_util__cases_may_allocate_heap(Cases, May).
code_util__goal_may_allocate_heap_2(if_then_else(_Vars, C, T, E), May) :-
( code_util__goal_may_allocate_heap(C, yes) ->
May = yes
; code_util__goal_may_allocate_heap(T, yes) ->
May = yes
;
code_util__goal_may_allocate_heap(E, May)
).
code_util__goal_may_allocate_heap_2(shorthand(ShorthandGoal), May) :-
code_util__goal_may_allocate_heap_2_shorthand(ShorthandGoal, May).
:- pred code_util__goal_may_allocate_heap_2_shorthand(shorthand_goal_expr::in,
bool::out) is det.
code_util__goal_may_allocate_heap_2_shorthand(bi_implication(G1, G2), May) :-
( code_util__goal_may_allocate_heap(G1, yes) ->
May = yes
;
code_util__goal_may_allocate_heap(G2, May)
).
:- pred code_util__goal_list_may_allocate_heap(list(hlds_goal)::in, bool::out)
is det.
code_util__goal_list_may_allocate_heap([], no).
code_util__goal_list_may_allocate_heap([Goal | Goals], May) :-
( code_util__goal_may_allocate_heap(Goal, yes) ->
May = yes
;
code_util__goal_list_may_allocate_heap(Goals, May)
).
:- pred code_util__cases_may_allocate_heap(list(case)::in, bool::out) is det.
code_util__cases_may_allocate_heap([], no).
code_util__cases_may_allocate_heap([case(_, Goal) | Cases], May) :-
( code_util__goal_may_allocate_heap(Goal, yes) ->
May = yes
;
code_util__cases_may_allocate_heap(Cases, May)
).
%-----------------------------------------------------------------------------%
code_util__goal_may_alloc_temp_frame(Goal) :-
code_util__goal_may_alloc_temp_frame(Goal, yes).
:- pred code_util__goal_may_alloc_temp_frame(hlds_goal::in, bool::out) is det.
code_util__goal_may_alloc_temp_frame(Goal - _GoalInfo, May) :-
code_util__goal_may_alloc_temp_frame_2(Goal, May).
:- pred code_util__goal_may_alloc_temp_frame_2(hlds_goal_expr::in, bool::out)
is det.
code_util__goal_may_alloc_temp_frame_2(generic_call(_, _, _, _), no).
code_util__goal_may_alloc_temp_frame_2(call(_, _, _, _, _, _), no).
code_util__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.
code_util__goal_may_alloc_temp_frame_2(foreign_proc(_,_,_,_,_,_,_),
yes).
code_util__goal_may_alloc_temp_frame_2(some(_Vars, _, Goal), May) :-
Goal = _ - GoalInfo,
goal_info_get_code_model(GoalInfo, CodeModel),
( CodeModel = model_non ->
May = yes
;
code_util__goal_may_alloc_temp_frame(Goal, May)
).
code_util__goal_may_alloc_temp_frame_2(not(Goal), May) :-
code_util__goal_may_alloc_temp_frame(Goal, May).
code_util__goal_may_alloc_temp_frame_2(conj(Goals), May) :-
code_util__goal_list_may_alloc_temp_frame(Goals, May).
code_util__goal_may_alloc_temp_frame_2(par_conj(Goals), May) :-
code_util__goal_list_may_alloc_temp_frame(Goals, May).
code_util__goal_may_alloc_temp_frame_2(disj(Goals), May) :-
code_util__goal_list_may_alloc_temp_frame(Goals, May).
code_util__goal_may_alloc_temp_frame_2(switch(_Var, _Det, Cases), May) :-
code_util__cases_may_alloc_temp_frame(Cases, May).
code_util__goal_may_alloc_temp_frame_2(if_then_else(_Vars, C, T, E), May) :-
( code_util__goal_may_alloc_temp_frame(C, yes) ->
May = yes
; code_util__goal_may_alloc_temp_frame(T, yes) ->
May = yes
;
code_util__goal_may_alloc_temp_frame(E, May)
).
code_util__goal_may_alloc_temp_frame_2(shorthand(ShorthandGoal), May) :-
code_util__goal_may_alloc_temp_frame_2_shorthand(ShorthandGoal,May).
:- pred code_util__goal_may_alloc_temp_frame_2_shorthand(
shorthand_goal_expr::in, bool::out) is det.
code_util__goal_may_alloc_temp_frame_2_shorthand(bi_implication(G1, G2),
May) :-
( code_util__goal_may_alloc_temp_frame(G1, yes) ->
May = yes
;
code_util__goal_may_alloc_temp_frame(G2, May)
).
:- pred code_util__goal_list_may_alloc_temp_frame(list(hlds_goal)::in,
bool::out) is det.
code_util__goal_list_may_alloc_temp_frame([], no).
code_util__goal_list_may_alloc_temp_frame([Goal | Goals], May) :-
( code_util__goal_may_alloc_temp_frame(Goal, yes) ->
May = yes
;
code_util__goal_list_may_alloc_temp_frame(Goals, May)
).
:- pred code_util__cases_may_alloc_temp_frame(list(case)::in, bool::out)
is det.
code_util__cases_may_alloc_temp_frame([], no).
code_util__cases_may_alloc_temp_frame([case(_, Goal) | Cases], May) :-
( code_util__goal_may_alloc_temp_frame(Goal, yes) ->
May = yes
;
code_util__cases_may_alloc_temp_frame(Cases, May)
).
%-----------------------------------------------------------------------------%
% Negate a condition.
% This is used mostly just to make the generated code more readable.
code_util__neg_rval(Rval, NegRval) :-
( code_util__neg_rval_2(Rval, NegRval0) ->
NegRval = NegRval0
;
NegRval = unop(not, Rval)
).
:- pred code_util__neg_rval_2(rval, rval).
:- mode code_util__neg_rval_2(in, out) is semidet.
code_util__neg_rval_2(const(Const), const(NegConst)) :-
(
Const = true, NegConst = false
;
Const = false, NegConst = true
).
code_util__neg_rval_2(unop(not, Rval), Rval).
code_util__neg_rval_2(binop(Op, X, Y), binop(NegOp, X, Y)) :-
code_util__neg_op(Op, NegOp).
:- pred code_util__neg_op(binary_op, binary_op).
:- mode code_util__neg_op(in, out) is semidet.
code_util__neg_op(eq, ne).
code_util__neg_op(ne, eq).
code_util__neg_op(<, >=).
code_util__neg_op(<=, >).
code_util__neg_op(>, <=).
code_util__neg_op(>=, <).
code_util__neg_op(str_eq, str_ne).
code_util__neg_op(str_ne, str_eq).
code_util__neg_op(str_lt, str_ge).
code_util__neg_op(str_le, str_gt).
code_util__neg_op(str_gt, str_le).
code_util__neg_op(str_ge, str_lt).
code_util__neg_op(float_eq, float_ne).
code_util__neg_op(float_ne, float_eq).
code_util__neg_op(float_lt, float_ge).
code_util__neg_op(float_le, float_gt).
code_util__neg_op(float_gt, float_le).
code_util__neg_op(float_ge, float_lt).
code_util__negate_the_test([], _) :-
error("code_util__negate_the_test on empty list").
code_util__negate_the_test([Instr0 | Instrs0], Instrs) :-
( Instr0 = if_val(Test, Target) - Comment ->
code_util__neg_rval(Test, NewTest),
Instrs = [if_val(NewTest, Target) - Comment]
;
code_util__negate_the_test(Instrs0, Instrs1),
Instrs = [Instr0 | Instrs1]
).
%-----------------------------------------------------------------------------%
code_util__cons_id_to_tag(int_const(X), _, _, int_constant(X)).
code_util__cons_id_to_tag(float_const(X), _, _, float_constant(X)).
code_util__cons_id_to_tag(string_const(X), _, _, string_constant(X)).
code_util__cons_id_to_tag(code_addr_const(P,M), _, _, code_addr_constant(P,M)).
code_util__cons_id_to_tag(pred_const(P,M,E), _, _, pred_closure_tag(P,M,E)).
code_util__cons_id_to_tag(type_ctor_info_const(M,T,A), _, _,
type_ctor_info_constant(M,T,A)).
code_util__cons_id_to_tag(base_typeclass_info_const(M,C,_,N), _, _,
base_typeclass_info_constant(M,C,N)).
code_util__cons_id_to_tag(tabling_pointer_const(PredId,ProcId), _, _,
tabling_pointer_constant(PredId,ProcId)).
code_util__cons_id_to_tag(deep_profiling_proc_static(PPId), _, _,
deep_profiling_proc_static_tag(PPId)).
code_util__cons_id_to_tag(table_io_decl(PPId), _, _, table_io_decl_tag(PPId)).
code_util__cons_id_to_tag(cons(Name, Arity), Type, ModuleInfo, Tag) :-
(
% handle the `character' type specially
Type = term__functor(term__atom("character"), [], _),
Name = unqualified(ConsName),
string__char_to_string(Char, ConsName)
->
char__to_int(Char, CharCode),
Tag = int_constant(CharCode)
;
% Tuples do not need a tag. Note that unary tuples are not
% treated as no_tag types. There's no reason why they
% couldn't be, it's just not worth the effort.
type_is_tuple(Type, _)
->
Tag = single_functor
;
% Use the type to determine the type_ctor
( type_to_ctor_and_args(Type, TypeCtor0, _) ->
TypeCtor = TypeCtor0
;
% the type-checker should ensure that this never happens
error("code_util__cons_id_to_tag: invalid type")
),
% Given the type_ctor, lookup up the constructor tag
% table for that type
module_info_types(ModuleInfo, TypeTable),
map__lookup(TypeTable, TypeCtor, TypeDefn),
hlds_data__get_type_defn_body(TypeDefn, TypeBody),
(
TypeBody = du_type(_, ConsTable0, _, _, _, _)
->
ConsTable = ConsTable0
;
% this should never happen
error(
"code_util__cons_id_to_tag: type is not d.u. type?"
)
),
% Finally look up the cons_id in the table
map__lookup(ConsTable, cons(Name, Arity), Tag)
).
%-----------------------------------------------------------------------------%
code_util__cannot_stack_flush(GoalExpr - _) :-
code_util__cannot_stack_flush_2(GoalExpr).
:- pred code_util__cannot_stack_flush_2(hlds_goal_expr).
:- mode code_util__cannot_stack_flush_2(in) is semidet.
code_util__cannot_stack_flush_2(unify(_, _, _, Unify, _)) :-
Unify \= complicated_unify(_, _, _).
code_util__cannot_stack_flush_2(call(_, _, _, BuiltinState, _, _)) :-
BuiltinState = inline_builtin.
code_util__cannot_stack_flush_2(conj(Goals)) :-
code_util__cannot_stack_flush_goals(Goals).
code_util__cannot_stack_flush_2(switch(_, _, Cases)) :-
code_util__cannot_stack_flush_cases(Cases).
code_util__cannot_stack_flush_2(not(unify(_, _, _, Unify, _) - _)) :-
Unify \= complicated_unify(_, _, _).
:- pred code_util__cannot_stack_flush_goals(list(hlds_goal)).
:- mode code_util__cannot_stack_flush_goals(in) is semidet.
code_util__cannot_stack_flush_goals([]).
code_util__cannot_stack_flush_goals([Goal | Goals]) :-
code_util__cannot_stack_flush(Goal),
code_util__cannot_stack_flush_goals(Goals).
:- pred code_util__cannot_stack_flush_cases(list(case)).
:- mode code_util__cannot_stack_flush_cases(in) is semidet.
code_util__cannot_stack_flush_cases([]).
code_util__cannot_stack_flush_cases([case(_, Goal) | Cases]) :-
code_util__cannot_stack_flush(Goal),
code_util__cannot_stack_flush_cases(Cases).
%-----------------------------------------------------------------------------%
code_util__cannot_flush(GoalExpr - _) :-
code_util__cannot_flush_2(GoalExpr).
:- pred code_util__cannot_flush_2(hlds_goal_expr).
:- mode code_util__cannot_flush_2(in) is semidet.
code_util__cannot_flush_2(unify(_, _, _, Unify, _)) :-
Unify \= complicated_unify(_, _, _).
code_util__cannot_flush_2(call(_, _, _, BuiltinState, _, _)) :-
BuiltinState = inline_builtin.
code_util__cannot_flush_2(conj(Goals)) :-
code_util__cannot_flush_goals(Goals).
:- pred code_util__cannot_flush_goals(list(hlds_goal)).
:- mode code_util__cannot_flush_goals(in) is semidet.
code_util__cannot_flush_goals([]).
code_util__cannot_flush_goals([Goal | Goals]) :-
code_util__cannot_flush(Goal),
code_util__cannot_flush_goals(Goals).
%-----------------------------------------------------------------------------%
code_util__cannot_fail_before_stack_flush(GoalExpr - GoalInfo) :-
goal_info_get_determinism(GoalInfo, Detism),
determinism_components(Detism, CanFail, _),
( CanFail = cannot_fail ->
true
;
code_util__cannot_fail_before_stack_flush_2(GoalExpr)
).
:- pred code_util__cannot_fail_before_stack_flush_2(hlds_goal_expr).
:- mode code_util__cannot_fail_before_stack_flush_2(in) is semidet.
code_util__cannot_fail_before_stack_flush_2(conj(Goals)) :-
code_util__cannot_fail_before_stack_flush_conj(Goals).
:- pred code_util__cannot_fail_before_stack_flush_conj(list(hlds_goal)).
:- mode code_util__cannot_fail_before_stack_flush_conj(in) is semidet.
code_util__cannot_fail_before_stack_flush_conj([]).
code_util__cannot_fail_before_stack_flush_conj([Goal | Goals]) :-
Goal = GoalExpr - GoalInfo,
(
(
GoalExpr = call(_, _, _, BuiltinState, _, _),
BuiltinState \= inline_builtin
;
GoalExpr = generic_call(_, _, _, _)
)
->
true
;
goal_info_get_determinism(GoalInfo, Detism),
determinism_components(Detism, cannot_fail, _)
->
code_util__cannot_fail_before_stack_flush_conj(Goals)
;
fail
).
%-----------------------------------------------------------------------------%
code_util__count_recursive_calls(Goal - _, PredId, ProcId, Min, Max) :-
code_util__count_recursive_calls_2(Goal, PredId, ProcId, Min, Max).
:- pred code_util__count_recursive_calls_2(hlds_goal_expr, pred_id, proc_id,
int, int).
:- mode code_util__count_recursive_calls_2(in, in, in, out, out) is det.
code_util__count_recursive_calls_2(not(Goal), PredId, ProcId, Min, Max) :-
code_util__count_recursive_calls(Goal, PredId, ProcId, Min, Max).
code_util__count_recursive_calls_2(some(_, _, Goal),
PredId, ProcId, Min, Max) :-
code_util__count_recursive_calls(Goal, PredId, ProcId, Min, Max).
code_util__count_recursive_calls_2(unify(_, _, _, _, _), _, _, 0, 0).
code_util__count_recursive_calls_2(generic_call(_, _, _, _), _, _,
0, 0).
code_util__count_recursive_calls_2(foreign_proc(_, _, _, _, _, _, _),
_, _, 0, 0).
code_util__count_recursive_calls_2(call(CallPredId, CallProcId, _, _, _, _),
PredId, ProcId, Count, Count) :-
(
PredId = CallPredId,
ProcId = CallProcId
->
Count = 1
;
Count = 0
).
code_util__count_recursive_calls_2(conj(Goals), PredId, ProcId, Min, Max) :-
code_util__count_recursive_calls_conj(Goals, PredId, ProcId, 0, 0,
Min, Max).
code_util__count_recursive_calls_2(par_conj(Goals), PredId, ProcId,
Min, Max) :-
code_util__count_recursive_calls_conj(Goals, PredId, ProcId, 0, 0,
Min, Max).
code_util__count_recursive_calls_2(disj(Goals), PredId, ProcId, Min, Max) :-
code_util__count_recursive_calls_disj(Goals, PredId, ProcId, Min, Max).
code_util__count_recursive_calls_2(switch(_, _, Cases), PredId, ProcId,
Min, Max) :-
code_util__count_recursive_calls_cases(Cases, PredId, ProcId, Min, Max).
code_util__count_recursive_calls_2(if_then_else(_, Cond, Then, Else),
PredId, ProcId, Min, Max) :-
code_util__count_recursive_calls(Cond, PredId, ProcId, CMin, CMax),
code_util__count_recursive_calls(Then, PredId, ProcId, TMin, TMax),
code_util__count_recursive_calls(Else, PredId, ProcId, EMin, EMax),
CTMin is CMin + TMin,
CTMax is CMax + TMax,
int__min(CTMin, EMin, Min),
int__max(CTMax, EMax, Max).
code_util__count_recursive_calls_2(shorthand(_),
_, _, _, _) :-
% these should have been expanded out by now
error("code_util__count_recursive_calls_2: unexpected shorthand").
:- pred code_util__count_recursive_calls_conj(list(hlds_goal),
pred_id, proc_id, int, int, int, int).
:- mode code_util__count_recursive_calls_conj(in, in, in, in, in, out, out)
is det.
code_util__count_recursive_calls_conj([], _, _, Min, Max, Min, Max).
code_util__count_recursive_calls_conj([Goal | Goals], PredId, ProcId,
Min0, Max0, Min, Max) :-
code_util__count_recursive_calls(Goal, PredId, ProcId, Min1, Max1),
Min2 is Min0 + Min1,
Max2 is Max0 + Max1,
code_util__count_recursive_calls_conj(Goals, PredId, ProcId,
Min2, Max2, Min, Max).
:- pred code_util__count_recursive_calls_disj(list(hlds_goal),
pred_id, proc_id, int, int).
:- mode code_util__count_recursive_calls_disj(in, in, in, out, out) is det.
code_util__count_recursive_calls_disj([], _, _, 0, 0).
code_util__count_recursive_calls_disj([Goal | Goals], PredId, ProcId,
Min, Max) :-
( Goals = [] ->
code_util__count_recursive_calls(Goal, PredId, ProcId,
Min, Max)
;
code_util__count_recursive_calls(Goal, PredId, ProcId,
Min0, Max0),
code_util__count_recursive_calls_disj(Goals, PredId, ProcId,
Min1, Max1),
int__min(Min0, Min1, Min),
int__max(Max0, Max1, Max)
).
:- pred code_util__count_recursive_calls_cases(list(case),
pred_id, proc_id, int, int).
:- mode code_util__count_recursive_calls_cases(in, in, in, out, out) is det.
code_util__count_recursive_calls_cases([], _, _, _, _) :-
error("empty cases in code_util__count_recursive_calls_cases").
code_util__count_recursive_calls_cases([case(_, Goal) | Cases], PredId, ProcId,
Min, Max) :-
( Cases = [] ->
code_util__count_recursive_calls(Goal, PredId, ProcId,
Min, Max)
;
code_util__count_recursive_calls(Goal, PredId, ProcId,
Min0, Max0),
code_util__count_recursive_calls_cases(Cases, PredId, ProcId,
Min1, Max1),
int__min(Min0, Min1, Min),
int__max(Max0, Max1, Max)
).
%-----------------------------------------------------------------------------%
code_util__lvals_in_lvals([], []).
code_util__lvals_in_lvals([First | Rest], Lvals) :-
code_util__lvals_in_lval(First, FirstLvals),
code_util__lvals_in_lvals(Rest, RestLvals),
list__append(FirstLvals, RestLvals, Lvals).
code_util__lvals_in_rval(lval(Lval), [Lval | Lvals]) :-
code_util__lvals_in_lval(Lval, Lvals).
code_util__lvals_in_rval(var(_), []).
code_util__lvals_in_rval(create(_, _, _, _, _, _, _), []).
code_util__lvals_in_rval(mkword(_, Rval), Lvals) :-
code_util__lvals_in_rval(Rval, Lvals).
code_util__lvals_in_rval(const(_), []).
code_util__lvals_in_rval(unop(_, Rval), Lvals) :-
code_util__lvals_in_rval(Rval, Lvals).
code_util__lvals_in_rval(binop(_, Rval1, Rval2), Lvals) :-
code_util__lvals_in_rval(Rval1, Lvals1),
code_util__lvals_in_rval(Rval2, Lvals2),
list__append(Lvals1, Lvals2, Lvals).
code_util__lvals_in_rval(mem_addr(MemRef), Lvals) :-
code_util__lvals_in_mem_ref(MemRef, Lvals).
code_util__lvals_in_lval(reg(_, _), []).
code_util__lvals_in_lval(stackvar(_), []).
code_util__lvals_in_lval(framevar(_), []).
code_util__lvals_in_lval(succip, []).
code_util__lvals_in_lval(maxfr, []).
code_util__lvals_in_lval(curfr, []).
code_util__lvals_in_lval(succip(Rval), Lvals) :-
code_util__lvals_in_rval(Rval, Lvals).
code_util__lvals_in_lval(redofr(Rval), Lvals) :-
code_util__lvals_in_rval(Rval, Lvals).
code_util__lvals_in_lval(redoip(Rval), Lvals) :-
code_util__lvals_in_rval(Rval, Lvals).
code_util__lvals_in_lval(succfr(Rval), Lvals) :-
code_util__lvals_in_rval(Rval, Lvals).
code_util__lvals_in_lval(prevfr(Rval), Lvals) :-
code_util__lvals_in_rval(Rval, Lvals).
code_util__lvals_in_lval(hp, []).
code_util__lvals_in_lval(sp, []).
code_util__lvals_in_lval(field(_, Rval1, Rval2), Lvals) :-
code_util__lvals_in_rval(Rval1, Lvals1),
code_util__lvals_in_rval(Rval2, Lvals2),
list__append(Lvals1, Lvals2, Lvals).
code_util__lvals_in_lval(lvar(_), []).
code_util__lvals_in_lval(temp(_, _), []).
code_util__lvals_in_lval(mem_ref(Rval), Lvals) :-
code_util__lvals_in_rval(Rval, Lvals).
:- pred code_util__lvals_in_mem_ref(mem_ref, list(lval)).
:- mode code_util__lvals_in_mem_ref(in, out) is det.
code_util__lvals_in_mem_ref(stackvar_ref(_), []).
code_util__lvals_in_mem_ref(framevar_ref(_), []).
code_util__lvals_in_mem_ref(heap_ref(Rval, _, _), Lvals) :-
code_util__lvals_in_rval(Rval, Lvals).
%-----------------------------------------------------------------------------%