mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-14 05:12:33 +00:00
Estimated hours taken: 400
Branches: main
Implement the infrastructure for term size profiling. This means adding two
new grade components, tsw and tsc, and implementing them in the LLDS code
generator. In grades including tsw (term size words), each term is augmented
with an extra word giving the number of heap words it contains; in grades
including tsc (term size cells), each term is augmented with an extra word
giving the number of heap cells it contains. The extra word is at the start,
at offset -1, to leave almost all of the machinery for accessing the heap
unchanged.
For now, the only way to access term sizes is with a new mdb command,
"term_size <varspec>". Later, we will use term sizes in conjunction with
deep profiling to do experimental complexity analysis, but that requires
a lot more research. This diff is a necessary first step.
The implementation of term size profiling consists of three main parts:
- a source-to-source transform that computes the size of each heap cell
when it is constructed (and increments it in the rare cases when a free
argument of an existing heap cell is bound),
- a relatively small change to the code generator that reserves the extra
slot in new heap cells, and
- extensions to the facilities for creating cells from C code to record
the extra information we now need.
The diff overhauls polymorphism.m to make the source-to-source transform
possible. This overhaul includes separating type_ctor_infos and type_infos
as strictly as possible from each other, converting type_ctor_infos into
type_infos only as necessary. It also includes separating type_ctor_infos,
type_infos, base_typeclass_infos and typeclass_infos (as well as voids,
for clarity) from plain user-defined type constructors in type categorizations.
This change needs this separation because values of those four types do not
have size slots, but they ought to be treated specially in other situations
as well (e.g. by tabling).
The diff adds a new mdb command, term_size. It also replaces the proc_body
mdb command with new ways of using the existing print and browse commands
("print proc_body" and "browse proc_body") in order to make looking at
procedure bodies more controllable. This was useful in debugging the effect
of term size profiling on some test case outputs. It is not strictly tied
to term size profiling, but turns out to be difficult to disentangle.
compiler/size_prof.m:
A new module implementing the source-to-source transform.
compiler/notes/compiler_design.html:
Mention the new module.
compiler/transform_hlds.m:
Include size_prof as a submodule of transform_hlds.
compiler/mercury_compile.m:
If term size profiling is enabled, invoke its source-to-source
transform.
compiler/hlds_goal.m:
Extend construction unifications with an optional slot for recording
the size of the term if the size is a constant, or the identity of the
variable holding the size, if the size is not constant. This is
needed by the source-to-source transform.
compiler/quantification.m:
Treat the variable reference that may be in this slot as a nonlocal
variable of construction unifications, since the code generator needs
this.
compiler/compile_target_code.m:
Handle the new grade components.
compiler/options.m:
Implement the options that control term size profiling.
doc/user_guide.texi:
Document the options and grade components that control term size
profiling, and the term_size mdb command. The documentation is
commented out for now.
Modify the wording of the 'u' HLDS dump flag to include other details
of unifications (e.g. term size info) rather than just unification
categories.
Document the new alternatives of the print and browse commands. Since
they are for developers only, the documentation is commented out.
compiler/handle_options.m:
Handle the implications of term size profiling grades.
Add a -D flag value to print HLDS components relevant to HLDS
transformations.
compiler/modules.m:
Import the new builtin library module that implements the operations
needed by term size profiling automatically in term size profiling
grades.
Switch the predicate involved to use state var syntax.
compiler/prog_util.m:
Add predicates and functions that return the sym_names of the modules
needed by term size profiling.
compiler/code_info.m:
compiler/unify_gen.m:
compiler/var_locn.m:
Reserve an extra slot in heap cells and fill them in in unifications
marked by size_prof.
compiler/builtin_ops.m:
Add term_size_prof_builtin.term_size_plus as a builtin, with the same
implementation as int.+.
compiler/make_hlds.m:
Disable warnings about clauses for builtins while the change to
builtin_ops is bootstrapped.
compiler/polymorphism.m:
Export predicates that generate goals to create type_infos and
type_ctor_infos to add_to_construct.m. Rewrite their documentation
to make it more detailed.
Make orders of arguments amenable to the use of state variable syntax.
Consolidate knowledge of which type categories have builtin unify and
compare predicates in one place.
Add code to leave the types of type_ctor_infos alone: instead of
changing their types to type_info when used as arguments of other
type_infos, create a new variable of type type_info instead, and
use an unsafe_cast. This would make the HLDS closer to being type
correct, but this new code is currently commented out, for two
reasons. First, common.m is currently not smart enough to figure out
that if X and Y are equal, then similar unsafe_casts of X and Y
are also equal, and this causes the compiler do not detect some
duplicate calls it used to detect. Second, the code generators
are also not smart enough to know that if Z is an unsafe_cast of X,
then X and Z do not need separate stack slots, but can use the same
slot.
compiler/type_util.m:
Add utility predicates for returning the types of type_infos and
type_ctor_infos, for use by new code in polymorphism.m.
Move some utility predicates here from other modules, since they
are now used by more than one module.
Rename the type `builtin_type' as `type_category', to better reflect
what it does. Extend it to put the type_info, type_ctor_info,
typeclass_info, base_typeclass_info and void types into categories
of their own: treating these types as if they were a user-defined
type (which is how they used to be classified) is not always correct.
Rename the functor polymorphic_type to variable_type, since types
such as list(T) are polymorphic, but they fall into the user-defined
category. Rename user_type as user_ctor_type, since list(int) is not
wholly user-defined but falls into this category. Rename pred_type
as higher_order_type, since it also encompasses functions.
Replace code that used to check for a few of the alternatives
of this type with code that does a full switch on the type,
to ensure that they are updated if the type definition ever
changes again.
compiler/pseudo_type_info.m:
Delete a predicate whose updated implementation is now in type_util.m.
compiler/mlds_to_c.m:
compiler/mlds_to_gcc.m:
compiler/mlds_to_il.m:
compiler/mlds_to_java.m:
Still treat type_infos, type_ctor_infos, typeclass_infos and
base_typeclass_infos as user-defined types, but prepare for when
they won't be.
compiler/hlds_pred.m:
Require interface typeinfo liveness when term size profiling is
enabled.
Add term_size_profiling_builtin.increase_size as a
no_type_info_builtin.
compiler/hlds_out.m:
Print the size annotations on unifications if HLDS dump flags call
for unification details. (The flag test is in the caller of the
modified predicate.)
compiler/llds.m:
Extend incr_hp instructions and data_addr_consts with optional fields
that allow the code generator to refer to N words past the start of
a static or dynamic cell. Term size profiling uses this with N=1.
compiler/llds_out.m:
When allocating memory on the heap, use the macro variants that
specify an optional offset, and specify the offset when required.
compiler/bytecode_gen.m:
compiler/dense_switch.m:
compiler/dupelim.m:
compiler/exprn_aux.m:
compiler/goal_form.m:
compiler/goal_util.m:
compiler/higher_order.m:
compiler/inst_match.m:
compiler/intermod.m:
compiler/jumpopt.m:
compiler/lambda.m:
compiler/livemap.m:
compiler/ll_pseudo_type_info.m:
compiler/lookup_switch.m:
compiler/magic_util.m:
compiler/middle_rec.m:
compiler/ml_code_util.m:
compiler/ml_switch_gen.m:
compiler/ml_unify_gen.m:
compiler/mlds.m:
compiler/mlds_to_c.m:
compiler/mlds_to_gcc.m:
compiler/mlds_to_il.m:
compiler/mlds_to_java.m:
compiler/modecheck_unify.m:
compiler/opt_debug.m:
compiler/opt_util.m:
compiler/par_conj_gen.m:
compiler/post_typecheck.m:
compiler/reassign.m:
compiler/rl.m:
compiler/rl_key.m:
compiler/special_pred.m:
compiler/stack_layout.m:
compiler/static_term.m:
compiler/string_switch.m:
compiler/switch_gen.m:
compiler/switch_util.m:
compiler/table_gen.m:
compiler/term_util.m:
compiler/type_ctor_info.m:
compiler/unused_args.m:
compiler/use_local_vars.m:
Minor updates to conform to the changes above.
library/term_size_prof_builtin.m:
New module containing helper predicates for term size profiling.
size_prof.m generates call to these predicates.
library/library.m:
Include the new module in the library.
doc/Mmakefile:
Do not include the term_size_prof_builtin module in the library
documentation.
library/array.m:
library/benchmarking.m:
library/construct.m:
library/deconstruct.m:
library/io.m:
library/sparse_bitset.m:
library/store.m:
library/string.m:
Replace all uses of MR_incr_hp with MR_offset_incr_hp, to ensure
that we haven't overlooked any places where offsets may need to be
specified.
Fix formatting of foreign_procs.
Use new macros defined by the runtime system when constructing
terms (which all happen to be lists) in C code. These new macros
specify the types of the cell arguments, allowing the implementation
to figure out the size of the new cell based on the sizes of its
fields.
library/private_builtin.m:
Define some constant type_info structures for use by these macros.
They cannot be defined in the runtime, since they refer to types
defined in the library (list.list and std_util.univ).
util/mkinit.c:
Make the addresses of these type_info structures available to the
runtime.
runtime/mercury_init.h:
Declare these type_info structures, for use in mkinit-generated
*_init.c files.
runtime/mercury_wrapper.[ch]:
Declare and define the variables that hold these addresses, for use
in the new macros for constructing typed lists.
Since term size profiling can refer to a memory cell by a pointer
that is offset by one word, register the extra offsets with the Boehm
collector if is being used.
Document the incompatibility of MR_HIGHTAGS and the Boehm collector.
runtime/mercury_tags.h:
Define new macros for constructing typed lists.
Provide macros for preserving the old interface presented by this file
to the extent possible. Uses of the old MR_list_cons macro will
continue to work in grades without term size profiling. In term
size profiling grades, their use will get a C compiler error.
Fix a bug caused by a missing backslash.
runtime/mercury_heap.h:
Change the basic macros for allocating new heap cells to take
an optional offset argument. If this is nonzero, the macros
increment the returned address by the given number of words.
Term size profiling specifies offset=1, reserving the extra
word at the start (which is ignored by all components of the
system except term size profiling) for holding the size of the term.
Provide macros for preserving the old interface presented by this file
to the extent possible. Since the old MR_create[123] and MR_list_cons
macros did not specify type information, they had to be changed
to take additional arguments. This affects only hand-written C code.
Call new diagnostic macros that can help debug heap allocations.
Document why the macros in this files must expand to expressions
instead of statements, evn though the latter would be preferable
(e.g. by allowing them to declare and use local variables without
depending on gcc extensions).
runtime/mercury_debug.[ch]:
Add diagnostic macros to debug heap allocations, and the functions
behind them if MR_DEBUG_HEAP_ALLOC is defined.
Update the debugging routines for hand-allocated cells to print the
values of the term size slot as well as the other slots in the relevant
grades.
runtime/mercury_string.h:
Provide some needed variants of the macro for copying strings.
runtime/mercury_deconstruct_macros.h:
runtime/mercury_type_info.c:
Supply type information when constructing terms.
runtime/mercury_deep_copy_body.h:
Preserve the term size slot when copying terms.
runtime/mercury_deep_copy_body.h:
runtime/mercury_ho_call.c:
runtime/mercury_ml_expand_body.h:
Use MR_offset_incr_hp instead of MR_incr_hp to ensure that all places
that allocate cells also allocate space for the term size slot if
necessary.
Reduce code duplication by using a now standard macro for copying
strings.
runtime/mercury_grade.h:
Handle the two new grade components.
runtime/mercury_conf_param.h:
Document the C macros used to control the two new grade components,
as well as MR_DEBUG_HEAP_ALLOC.
Detect incompatibilities between high level code and profiling.
runtime/mercury_term_size.[ch]:
A new module to house a function to find and return term sizes
stored in heap cells.
runtime/mercury_proc_id.h:
runtime/mercury_univ.h:
New header files. mercury_proc_id.h contains the (unchanged)
definition of MR_Proc_Id, while mercury_univ.h contains the
definitions of the macros for manipulating univs that used to be
in mercury_type_info.h, updated to use the new macros for allocating
memory.
In the absence of these header files, the following circularity
would ensue:
mercury_deep_profiling.h includes mercury_stack_layout.h
- needs definition of MR_Proc_Id
mercury_stack_layout.h needs mercury_type_info.h
- needs definition of MR_PseudoTypeInfo
mercury_type_info.h needs mercury_heap.h
- needs heap allocation macros for MR_new_univ_on_hp
mercury_heap.h includes mercury_deep_profiling.h
- needs MR_current_call_site_dynamic for recording allocations
Breaking the circular dependency in two places, not just one, is to
minimize similar problems in the future.
runtime/mercury_stack_layout.h:
Delete the definition of MR_Proc_Id, which is now in mercury_proc_id.h.
runtime/mercury_type_info.h:
Delete the macros for manipulating univs, which are now in
mercury_univ.h.
runtime/Mmakefile:
Mention the new files.
runtime/mercury_imp.h:
runtime/mercury.h:
runtime/mercury_construct.c:
runtime/mercury_deep_profiling.h:
Include the new files at appropriate points.
runtime/mercury.c:
Change the names of the functions that create heap cells for
hand-written code, since the interface to hand-written code has
changed to include type information.
runtime/mercury_tabling.h:
Delete some unused macros.
runtime/mercury_trace_base.c:
runtime/mercury_type_info.c:
Use the new macros supplying type information when constructing lists.
scripts/canonical_grade_options.sh-subr:
Fix an undefined sh variable bug that could cause error messages
to come out without identifying the program they were from.
scripts/init_grade_options.sh-subr:
scripts/parse_grade_options.sh-subr:
scripts/canonical_grade_options.sh-subr:
scripts/mgnuc.in:
Handle the new grade components and the options controlling them.
trace/mercury_trace_internal.c:
Implement the mdb command "term_size <varspec>", which is like
"print <varspec>", but prints the size of a term instead of its value.
In non-term-size-profiling grades, it prints an error message.
Replace the "proc_body" command with optional arguments to the "print"
and "browse" commands.
doc/user_guide.tex:
Add documentation of the term_size mdb command. Since the command is
for implementors only, and works only in grades that are not yet ready
for public consumption, the documentation is commented out.
Add documentation of the new arguments of the print and browse mdb
commands. Since they are for implementors only, the documentation
is commented out.
trace/mercury_trace_vars.[ch]:
Add the functions needed to implement the term_size command, and
factor out the code common to the "size" and "print"/"browse" commands.
Decide whether to print the name of a variable before invoking the
supplied print or browse predicate on it based on a flag design for
this purpose, instead of overloading the meaning of the output FILE *
variable. This arrangement is much clearer.
trace/mercury_trace_browse.c:
trace/mercury_trace_external.c:
trace/mercury_trace_help.c:
Supply type information when constructing terms.
browser/program_representation.m:
Since the new library module term_size_prof_builtin never generates
any events, mark it as such, so that the declarative debugger doesn't
expect it to generate any.
Do the same for the deep profiling builtin module.
tests/debugger/term_size_words.{m,inp,exp}:
tests/debugger/term_size_cells.{m,inp,exp}:
Two new test cases, each testing one of the new grades.
tests/debugger/Mmakefile:
Enable the two new test cases in their grades.
Disable the tests sensitive to stack frame sizes in term size profiling
grades.
tests/debugger/completion.exp:
Add the new "term_size" mdb command to the list of command completions,
and delete "proc_body".
tests/debugger/declarative/dependency.{inp,exp}:
Use "print proc_body" instead of "proc_body".
tests/hard_coded/nondet_c.m:
tests/hard_coded/pragma_inline.m:
Use MR_offset_incr_hp instead of MR_incr_hp to ensure that all places
that allocate cells also allocate space for the term size slot if
necessary.
tests/valid/Mmakefile:
Disable the IL tests in term size profiling grades, since the term size
profiling primitives haven't been (and probably won't be) implemented
for the MLDS backends, and handle_options causes a compiler abort
for grades that combine term size profiling and any one of IL, Java
and high level C.
2088 lines
76 KiB
Mathematica
2088 lines
76 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.
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Utilities for LLDS to LLDS peephole optimization.
|
|
|
|
% Main author: zs.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module ll_backend__opt_util.
|
|
|
|
:- interface.
|
|
|
|
:- import_module ll_backend__llds.
|
|
|
|
:- import_module bool, map, list, std_util.
|
|
|
|
:- type instrmap == map(label, instruction).
|
|
:- type lvalmap == map(label, maybe(instruction)).
|
|
:- type tailmap == map(label, list(instruction)).
|
|
:- type succmap == map(label, bool).
|
|
|
|
:- pred opt_util__get_prologue(list(instruction), instruction,
|
|
list(instruction), list(instruction)).
|
|
:- mode opt_util__get_prologue(in, out, out, out) is det.
|
|
|
|
:- pred opt_util__gather_comments(list(instruction),
|
|
list(instruction), list(instruction)).
|
|
:- mode opt_util__gather_comments(in, out, out) is det.
|
|
|
|
:- pred opt_util__gather_comments_livevals(list(instruction),
|
|
list(instruction), list(instruction)).
|
|
:- mode opt_util__gather_comments_livevals(in, out, out) is det.
|
|
|
|
:- pred opt_util__skip_comments(list(instruction), list(instruction)).
|
|
% :- mode opt_util__skip_comments(di, uo) is det.
|
|
:- mode opt_util__skip_comments(in, out) is det.
|
|
|
|
:- pred opt_util__skip_comments_livevals(list(instruction), list(instruction)).
|
|
:- mode opt_util__skip_comments_livevals(in, out) is det.
|
|
|
|
:- pred opt_util__skip_comments_labels(list(instruction), list(instruction)).
|
|
:- mode opt_util__skip_comments_labels(in, out) is det.
|
|
|
|
:- pred opt_util__skip_comments_livevals_labels(list(instruction),
|
|
list(instruction)).
|
|
:- mode opt_util__skip_comments_livevals_labels(in, out) is det.
|
|
|
|
% Find the next assignment to the redoip of the frame whose address
|
|
% is given by the base addresses in the second argument, provided
|
|
% it is guaranteed to be reached from here.
|
|
|
|
:- pred opt_util__next_assign_to_redoip(list(instruction), list(lval),
|
|
list(instruction), code_addr, list(instruction), list(instruction)).
|
|
:- mode opt_util__next_assign_to_redoip(in, in, in, out, out, out) is semidet.
|
|
|
|
% See if these instructions touch nondet stack controls, i.e.
|
|
% the virtual machine registers that point to the nondet stack
|
|
% (curfr and maxfr) and the fixed slots in nondet stack frames.
|
|
|
|
:- pred opt_util__touches_nondet_ctrl(list(instruction), bool).
|
|
:- mode opt_util__touches_nondet_ctrl(in, out) is det.
|
|
|
|
% Find the instructions up to and including
|
|
% the next one that cannot fall through
|
|
|
|
:- pred opt_util__find_no_fallthrough(list(instruction), list(instruction)).
|
|
:- mode opt_util__find_no_fallthrough(in, out) is det.
|
|
|
|
% Find the first label in the instruction stream.
|
|
|
|
:- pred opt_util__find_first_label(list(instruction), label).
|
|
:- mode opt_util__find_first_label(in, out) is det.
|
|
|
|
% Skip to the next label, returning the code before the label,
|
|
% and the label together with the code after the label.
|
|
|
|
:- pred opt_util__skip_to_next_label(list(instruction),
|
|
list(instruction), list(instruction)).
|
|
% :- mode opt_util__skip_to_next_label(di, uo, uo) is det.
|
|
:- mode opt_util__skip_to_next_label(in, out, out) is det.
|
|
|
|
% Check whether the named label follows without any intervening code.
|
|
% If yes, return the instructions after the label.
|
|
|
|
:- pred opt_util__is_this_label_next(label, list(instruction),
|
|
list(instruction)).
|
|
:- mode opt_util__is_this_label_next(in, in, out) is semidet.
|
|
|
|
% Is a proceed instruction (i.e. a goto(succip) instruction)
|
|
% next in the instruction list, possibly preceded by a restoration
|
|
% of succip and a det stack frame removal? If yes, return the
|
|
% instructions up to the proceed.
|
|
|
|
:- pred opt_util__is_proceed_next(list(instruction), list(instruction)).
|
|
:- mode opt_util__is_proceed_next(in, out) is semidet.
|
|
|
|
% Is a proceed instruction (i.e. a goto(succip) instruction)
|
|
% next in the instruction list, possibly preceded by an assignment
|
|
% to r1, a restoration of succip and a det stack frame removal?
|
|
% If yes, return the instructions up to the proceed.
|
|
|
|
:- pred opt_util__is_sdproceed_next(list(instruction), list(instruction)).
|
|
:- mode opt_util__is_sdproceed_next(in, out) is semidet.
|
|
|
|
% Same as the previous predicate, but also return whether it is
|
|
% a success or a fail.
|
|
|
|
:- pred opt_util__is_sdproceed_next_sf(list(instruction), list(instruction),
|
|
bool).
|
|
:- mode opt_util__is_sdproceed_next_sf(in, out, out) is semidet.
|
|
|
|
% Is a succeed instruction (i.e. a goto(do_succeed(_)) instruction)
|
|
% next in the instruction list? If yes, return the instructions
|
|
% up to and including the succeed.
|
|
|
|
:- pred opt_util__is_succeed_next(list(instruction), list(instruction)).
|
|
:- mode opt_util__is_succeed_next(in, out) is semidet.
|
|
|
|
% Is the following code a test of r1, followed in both continuations
|
|
% by a semidet proceed? Is the code in both continuations the same,
|
|
% modulo livevals annotations and the value assigned to r1? Is MR_TRUE
|
|
% assigned to r1 in the success continuation and MR_FALSE in the failure
|
|
% continuation? If the answer is yes to all these questions, return
|
|
% the code shared by the two continuations.
|
|
|
|
:- pred opt_util__is_forkproceed_next(list(instruction), tailmap,
|
|
list(instruction)).
|
|
:- mode opt_util__is_forkproceed_next(in, in, out) is semidet.
|
|
|
|
% Remove the assignment to r1 from the list returned by
|
|
% opt_util__is_sdproceed_next.
|
|
|
|
:- pred opt_util__filter_out_r1(list(instruction), maybe(rval_const),
|
|
list(instruction)).
|
|
:- mode opt_util__filter_out_r1(in, out, out) is det.
|
|
|
|
% Does the following code consist of straighline instructions
|
|
% that do not modify nondet frame linkages, plus possibly
|
|
% if_val(..., dofail), and then a succeed?
|
|
% If yes, then return all the instructions up to the succeed,
|
|
% and all the following instructions.
|
|
|
|
:- pred opt_util__straight_alternative(list(instruction), list(instruction),
|
|
list(instruction)).
|
|
:- mode opt_util__straight_alternative(in, out, out) is semidet.
|
|
|
|
% Find and return the initial sequence of instructions that do not
|
|
% refer to stackvars and do not branch.
|
|
|
|
:- pred opt_util__no_stack_straight_line(list(instruction),
|
|
list(instruction), list(instruction)).
|
|
:- mode opt_util__no_stack_straight_line(in, out, out) is det.
|
|
|
|
% Remove the labels from a block of code for jumpopt.
|
|
|
|
:- pred opt_util__filter_out_labels(list(instruction), list(instruction)).
|
|
:- mode opt_util__filter_out_labels(in, out) is det.
|
|
|
|
% Remove any livevals instructions that do not precede an instruction
|
|
% that needs one.
|
|
|
|
:- pred opt_util__filter_out_bad_livevals(list(instruction), list(instruction)).
|
|
:- mode opt_util__filter_out_bad_livevals(in, out) is det.
|
|
|
|
% Remove the livevals instruction from the list returned by
|
|
% opt_util__is_proceed_next.
|
|
|
|
:- pred opt_util__filter_out_livevals(list(instruction), list(instruction)).
|
|
:- mode opt_util__filter_out_livevals(in, out) is det.
|
|
|
|
% Get just the livevals instructions from a list of instructions.
|
|
|
|
:- pred opt_util__filter_in_livevals(list(instruction), list(instruction)).
|
|
:- mode opt_util__filter_in_livevals(in, out) is det.
|
|
|
|
% See if the condition of an if-then-else is constant,
|
|
% and if yes, whether the branch will be taken or not.
|
|
|
|
:- pred opt_util__is_const_condition(rval, bool).
|
|
:- mode opt_util__is_const_condition(in, out) is semidet.
|
|
|
|
% Check whether an instruction can possibly branch away.
|
|
|
|
:- pred opt_util__can_instr_branch_away(instr, bool).
|
|
:- mode opt_util__can_instr_branch_away(in, out) is det.
|
|
|
|
% Check whether an instruction can possibly fall through
|
|
% to the next instruction without using its label.
|
|
|
|
:- pred opt_util__can_instr_fall_through(instr, bool).
|
|
:- mode opt_util__can_instr_fall_through(in, out) is det.
|
|
|
|
% Check whether a code_addr, when the target of a goto, represents
|
|
% either a call or a proceed/succeed; if so, it is the end of an
|
|
% extended basic block and needs a livevals in front of it.
|
|
|
|
:- pred opt_util__livevals_addr(code_addr, bool).
|
|
:- mode opt_util__livevals_addr(in, out) is det.
|
|
|
|
% Determine all the labels and code addresses which are referenced
|
|
% by an instruction. The code addresses that are labels are returned
|
|
% in both output arguments.
|
|
|
|
:- pred opt_util__instr_labels(instr, list(label), list(code_addr)).
|
|
:- mode opt_util__instr_labels(in, out, out) is det.
|
|
|
|
% Determine all the labels and code addresses which are referenced
|
|
% by a list of instructions.
|
|
|
|
:- pred opt_util__instr_list_labels(list(instruction),
|
|
list(label), list(code_addr)).
|
|
:- mode opt_util__instr_list_labels(in, out, out) is det.
|
|
|
|
% Given an instruction, find the set of labels to which it can cause
|
|
% control to transfer. In the case of calls, this includes transfer
|
|
% via return from the called procedure.
|
|
|
|
:- pred opt_util__possible_targets(instr, list(label)).
|
|
:- mode opt_util__possible_targets(in, out) is det.
|
|
|
|
% Find the maximum temp variable number used.
|
|
|
|
:- pred opt_util__count_temps_instr_list(list(instruction), int, int, int, int).
|
|
:- mode opt_util__count_temps_instr_list(in, in, out, in, out) is det.
|
|
|
|
:- pred opt_util__count_temps_instr(instr, int, int, int, int).
|
|
:- mode opt_util__count_temps_instr(in, in, out, in, out) is det.
|
|
|
|
% See whether an lval references any stackvars.
|
|
|
|
:- pred opt_util__lval_refers_stackvars(lval, bool).
|
|
:- mode opt_util__lval_refers_stackvars(in, out) is det.
|
|
|
|
% See whether an rval references any stackvars.
|
|
|
|
:- pred opt_util__rval_refers_stackvars(rval, bool).
|
|
:- mode opt_util__rval_refers_stackvars(in, out) is det.
|
|
|
|
% See whether a list of maybe rvals references any stackvars.
|
|
|
|
:- pred opt_util__rvals_refer_stackvars(list(maybe(rval)), bool).
|
|
:- mode opt_util__rvals_refer_stackvars(in, out) is det.
|
|
|
|
% See whether instructions until the next decr_sp (if any) refer to
|
|
% any stackvars or branch away. If not, return the instructions up to
|
|
% the decr_sp. A restoration of succip from the bottom stack slot
|
|
% is allowed; this instruction is not returned in the output.
|
|
% The same thing applies to assignments to detstackvars; these are
|
|
% not useful if we throw away the stack frame.
|
|
|
|
:- pred opt_util__no_stackvars_til_decr_sp(list(instruction), int,
|
|
list(instruction), list(instruction)).
|
|
% :- mode opt_util__no_stackvars_til_decr_sp(di, in, uo, uo) is semidet.
|
|
:- mode opt_util__no_stackvars_til_decr_sp(in, in, out, out) is semidet.
|
|
|
|
% See whether a list of instructions references any stackvars.
|
|
|
|
:- pred opt_util__block_refers_stackvars(list(instruction), bool).
|
|
:- mode opt_util__block_refers_stackvars(in, out) is det.
|
|
|
|
% Format a label for verbose messages during compilation
|
|
|
|
:- pred opt_util__format_label(label, string).
|
|
:- mode opt_util__format_label(in, out) is det.
|
|
|
|
% Find out if an instruction sequence has both incr_sp and decr_sp.
|
|
|
|
:- pred opt_util__has_both_incr_decr_sp(list(instruction)).
|
|
:- mode opt_util__has_both_incr_decr_sp(in) is semidet.
|
|
|
|
% Find out what rvals, if any, are needed to access an lval.
|
|
|
|
:- pred opt_util__lval_access_rvals(lval, list(rval)).
|
|
:- mode opt_util__lval_access_rvals(in, out) is det.
|
|
|
|
% See whether an rval is free of references to a given lval.
|
|
|
|
:- pred opt_util__rval_free_of_lval(rval, lval).
|
|
:- mode opt_util__rval_free_of_lval(in, in) is semidet.
|
|
|
|
% See whether a list of rvals is free of references to a given lval.
|
|
|
|
:- pred opt_util__rvals_free_of_lval(list(rval), lval).
|
|
:- mode opt_util__rvals_free_of_lval(in, in) is semidet.
|
|
|
|
% Count the number of hp increments in a block of code.
|
|
|
|
:- pred opt_util__count_incr_hp(list(instruction), int).
|
|
:- mode opt_util__count_incr_hp(in, out) is det.
|
|
|
|
% Whenever the input list of instructions contains two livevals
|
|
% pseudo-ops without an intervening no-fall-through instruction,
|
|
% ensure that the first of these registers as live every lval
|
|
% that is live in the second, except those that are assigned to
|
|
% by intervening instructions. This makes the shadowing of the
|
|
% second livevals by the first benign.
|
|
|
|
:- pred opt_util__propagate_livevals(list(instruction), list(instruction)).
|
|
:- mode opt_util__propagate_livevals(in, out) is det.
|
|
|
|
% Replace references to one set of local labels with references
|
|
% to another set, in one instruction or a list of instructions.
|
|
% Control references (those that can cause a transfer of control
|
|
% from the instruction they occur in to the replaced label, either
|
|
% directly or via return from a called procedure) are always replaced;
|
|
% references that treat the label as data are replaced iff the third
|
|
% argument is set to "yes".
|
|
|
|
:- pred opt_util__replace_labels_instr(instr::in, map(label, label)::in,
|
|
bool::in, instr::out) is det.
|
|
|
|
:- pred opt_util__replace_labels_instruction(instruction::in,
|
|
map(label, label)::in, bool::in, instruction::out) is det.
|
|
|
|
:- pred opt_util__replace_labels_instruction_list(list(instruction)::in,
|
|
map(label, label)::in, bool::in, list(instruction)::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module backend_libs__builtin_ops.
|
|
:- import_module backend_libs__proc_label.
|
|
:- import_module hlds__hlds_pred.
|
|
:- import_module hlds__special_pred.
|
|
:- import_module ll_backend__exprn_aux.
|
|
:- import_module ll_backend__llds_out.
|
|
:- import_module parse_tree__prog_data.
|
|
|
|
:- import_module int, string, set, require.
|
|
|
|
opt_util__get_prologue(Instrs0, LabelInstr, Comments, Instrs) :-
|
|
opt_util__gather_comments(Instrs0, Comments1, Instrs1),
|
|
(
|
|
Instrs1 = [Instr1 | Instrs2],
|
|
Instr1 = label(_) - _
|
|
->
|
|
LabelInstr = Instr1,
|
|
opt_util__gather_comments(Instrs2, Comments2, Instrs),
|
|
list__append(Comments1, Comments2, Comments)
|
|
;
|
|
error("procedure does not begin with label")
|
|
).
|
|
|
|
opt_util__gather_comments(Instrs0, Comments, Instrs) :-
|
|
(
|
|
Instrs0 = [Instr0 | Instrs1],
|
|
Instr0 = comment(_) - _
|
|
->
|
|
opt_util__gather_comments(Instrs1, Comments0, Instrs),
|
|
Comments = [Instr0 | Comments0]
|
|
;
|
|
Instrs = Instrs0,
|
|
Comments = []
|
|
).
|
|
|
|
opt_util__gather_comments_livevals(Instrs0, Comments, Instrs) :-
|
|
(
|
|
Instrs0 = [Instr0 | Instrs1],
|
|
( Instr0 = comment(_) - _ ; Instr0 = livevals(_) - _ )
|
|
->
|
|
opt_util__gather_comments_livevals(Instrs1, Comments0, Instrs),
|
|
Comments = [Instr0 | Comments0]
|
|
;
|
|
Instrs = Instrs0,
|
|
Comments = []
|
|
).
|
|
|
|
% Given a list of instructions, skip past any comment instructions
|
|
% at the start and return the remaining instructions.
|
|
% We do this because comment instructions get in the way of
|
|
% peephole optimization.
|
|
|
|
opt_util__skip_comments(Instrs0, Instrs) :-
|
|
( Instrs0 = [comment(_) - _ | Instrs1] ->
|
|
opt_util__skip_comments(Instrs1, Instrs)
|
|
;
|
|
Instrs = Instrs0
|
|
).
|
|
|
|
opt_util__skip_comments_livevals(Instrs0, Instrs) :-
|
|
( Instrs0 = [comment(_) - _ | Instrs1] ->
|
|
opt_util__skip_comments(Instrs1, Instrs)
|
|
; Instrs0 = [livevals(_) - _ | Instrs1] ->
|
|
opt_util__skip_comments_livevals(Instrs1, Instrs)
|
|
;
|
|
Instrs = Instrs0
|
|
).
|
|
|
|
opt_util__skip_comments_labels(Instrs0, Instrs) :-
|
|
( Instrs0 = [comment(_) - _ | Instrs1] ->
|
|
opt_util__skip_comments_labels(Instrs1, Instrs)
|
|
; Instrs0 = [label(_) - _ | Instrs1] ->
|
|
opt_util__skip_comments_labels(Instrs1, Instrs)
|
|
;
|
|
Instrs = Instrs0
|
|
).
|
|
|
|
opt_util__skip_comments_livevals_labels(Instrs0, Instrs) :-
|
|
( Instrs0 = [comment(_) - _ | Instrs1] ->
|
|
opt_util__skip_comments_livevals_labels(Instrs1, Instrs)
|
|
; Instrs0 = [livevals(_) - _ | Instrs1] ->
|
|
opt_util__skip_comments_livevals_labels(Instrs1, Instrs)
|
|
; Instrs0 = [label(_) - _ | Instrs1] ->
|
|
opt_util__skip_comments_livevals_labels(Instrs1, Instrs)
|
|
;
|
|
Instrs = Instrs0
|
|
).
|
|
|
|
opt_util__next_assign_to_redoip([Instr | Instrs], AllowedBases,
|
|
RevSkip, Redoip, Skip, Rest) :-
|
|
Instr = Uinstr - _Comment,
|
|
(
|
|
Uinstr = assign(redoip(lval(Fr)),
|
|
const(code_addr_const(Redoip0))),
|
|
list__member(Fr, AllowedBases)
|
|
->
|
|
Redoip = Redoip0,
|
|
list__reverse(RevSkip, Skip),
|
|
Rest = Instrs
|
|
;
|
|
Uinstr = mkframe(_, _)
|
|
->
|
|
fail
|
|
;
|
|
opt_util__can_instr_branch_away(Uinstr, Canbranchaway),
|
|
( Canbranchaway = no ->
|
|
opt_util__next_assign_to_redoip(Instrs, AllowedBases,
|
|
[Instr | RevSkip], Redoip, Skip, Rest)
|
|
;
|
|
fail
|
|
)
|
|
).
|
|
|
|
opt_util__find_no_fallthrough([], []).
|
|
opt_util__find_no_fallthrough([Instr0 | Instrs0], Instrs) :-
|
|
(
|
|
Instr0 = Uinstr0 - _,
|
|
opt_util__can_instr_fall_through(Uinstr0, no)
|
|
->
|
|
Instrs = [Instr0]
|
|
;
|
|
opt_util__find_no_fallthrough(Instrs0, Instrs1),
|
|
Instrs = [Instr0 | Instrs1]
|
|
).
|
|
|
|
opt_util__find_first_label([], _) :-
|
|
error("cannot find first label").
|
|
opt_util__find_first_label([Instr0 | Instrs0], Label) :-
|
|
( Instr0 = label(LabelPrime) - _ ->
|
|
Label = LabelPrime
|
|
;
|
|
opt_util__find_first_label(Instrs0, Label)
|
|
).
|
|
|
|
opt_util__skip_to_next_label([], [], []).
|
|
opt_util__skip_to_next_label([Instr0 | Instrs0], Before, Remain) :-
|
|
( Instr0 = label(_) - _ ->
|
|
Before = [],
|
|
Remain = [Instr0 | Instrs0]
|
|
;
|
|
opt_util__skip_to_next_label(Instrs0, Before1, Remain),
|
|
Before = [Instr0 | Before1]
|
|
).
|
|
|
|
opt_util__is_this_label_next(Label, [Instr | Moreinstr], Remainder) :-
|
|
Instr = Uinstr - _Comment,
|
|
( Uinstr = comment(_) ->
|
|
opt_util__is_this_label_next(Label, Moreinstr, Remainder)
|
|
; Uinstr = livevals(_) ->
|
|
% this is questionable
|
|
opt_util__is_this_label_next(Label, Moreinstr, Remainder)
|
|
; Uinstr = label(NextLabel) ->
|
|
( Label = NextLabel ->
|
|
Remainder = Moreinstr
|
|
;
|
|
opt_util__is_this_label_next(Label, Moreinstr,
|
|
Remainder)
|
|
)
|
|
;
|
|
fail
|
|
).
|
|
|
|
opt_util__is_proceed_next(Instrs0, InstrsBetween) :-
|
|
opt_util__skip_comments_labels(Instrs0, Instrs1),
|
|
Instrs1 = [Instr1 | Instrs2],
|
|
( Instr1 = assign(succip, lval(stackvar(_))) - _ ->
|
|
Instr1use = Instr1,
|
|
opt_util__skip_comments_labels(Instrs2, Instrs3)
|
|
;
|
|
Instr1use = comment("no succip restoration") - "",
|
|
Instrs3 = Instrs1
|
|
),
|
|
Instrs3 = [Instr3 | Instrs4],
|
|
( Instr3 = decr_sp(_) - _ ->
|
|
Instr3use = Instr3,
|
|
opt_util__skip_comments_labels(Instrs4, Instrs5)
|
|
;
|
|
Instr3use = comment("no sp restoration") - "",
|
|
Instrs5 = Instrs3
|
|
),
|
|
Instrs5 = [Instr5 | Instrs6],
|
|
Instr5 = livevals(_) - _,
|
|
opt_util__skip_comments_labels(Instrs6, Instrs7),
|
|
Instrs7 = [Instr7 | _],
|
|
Instr7 = goto(succip) - _,
|
|
InstrsBetween = [Instr1use, Instr3use, Instr5].
|
|
|
|
opt_util__is_sdproceed_next(Instrs0, InstrsBetween) :-
|
|
opt_util__is_sdproceed_next_sf(Instrs0, InstrsBetween, _).
|
|
|
|
opt_util__is_sdproceed_next_sf(Instrs0, InstrsBetween, Success) :-
|
|
opt_util__skip_comments_labels(Instrs0, Instrs1),
|
|
Instrs1 = [Instr1 | Instrs2],
|
|
( Instr1 = assign(succip, lval(stackvar(_))) - _ ->
|
|
Instr1use = Instr1,
|
|
opt_util__skip_comments_labels(Instrs2, Instrs3)
|
|
;
|
|
Instr1use = comment("no succip restoration") - "",
|
|
Instrs3 = Instrs1
|
|
),
|
|
Instrs3 = [Instr3 | Instrs4],
|
|
( Instr3 = decr_sp(_) - _ ->
|
|
Instr3use = Instr3,
|
|
opt_util__skip_comments_labels(Instrs4, Instrs5)
|
|
;
|
|
Instr3use = comment("no sp restoration") - "",
|
|
Instrs5 = Instrs3
|
|
),
|
|
Instrs5 = [Instr5 | Instrs6],
|
|
Instr5 = assign(reg(r, 1), const(R1val)) - _,
|
|
(
|
|
R1val = true,
|
|
Success = yes
|
|
;
|
|
R1val = false,
|
|
Success = no
|
|
),
|
|
opt_util__skip_comments_labels(Instrs6, Instrs7),
|
|
Instrs7 = [Instr7 | Instrs8],
|
|
Instr7 = livevals(_) - _,
|
|
opt_util__skip_comments_labels(Instrs8, Instrs9),
|
|
Instrs9 = [Instr9 | _],
|
|
Instr9 = goto(succip) - _,
|
|
InstrsBetween = [Instr1use, Instr3use, Instr5, Instr7].
|
|
|
|
opt_util__is_succeed_next(Instrs0, InstrsBetweenIncl) :-
|
|
opt_util__skip_comments_labels(Instrs0, Instrs1),
|
|
Instrs1 = [Instr1 | Instrs2],
|
|
Instr1 = livevals(_) - _,
|
|
opt_util__skip_comments_labels(Instrs2, Instrs3),
|
|
Instrs3 = [Instr3 | _],
|
|
Instr3 = goto(do_succeed(_)) - _,
|
|
InstrsBetweenIncl = [Instr1, Instr3].
|
|
|
|
opt_util__is_forkproceed_next(Instrs0, Sdprocmap, Between) :-
|
|
opt_util__skip_comments_labels(Instrs0, Instrs1),
|
|
Instrs1 = [Instr1 | Instrs2],
|
|
( Instr1 = if_val(lval(reg(r, 1)), label(JumpLabel)) - _ ->
|
|
map__search(Sdprocmap, JumpLabel, BetweenJump),
|
|
opt_util__is_sdproceed_next(Instrs2, BetweenFall),
|
|
opt_util__filter_out_r1(BetweenJump, yes(true), BetweenTrue0),
|
|
opt_util__filter_out_livevals(BetweenTrue0, Between),
|
|
opt_util__filter_out_r1(BetweenFall, yes(false), BetweenFalse0),
|
|
opt_util__filter_out_livevals(BetweenFalse0, Between)
|
|
; Instr1 = if_val(unop(not, lval(reg(r, 1))), label(JumpLabel)) - _ ->
|
|
map__search(Sdprocmap, JumpLabel, BetweenJump),
|
|
opt_util__is_sdproceed_next(Instrs2, BetweenFall),
|
|
opt_util__filter_out_r1(BetweenJump, yes(false), BetweenFalse0),
|
|
opt_util__filter_out_livevals(BetweenFalse0, Between),
|
|
opt_util__filter_out_r1(BetweenFall, yes(true), BetweenTrue0),
|
|
opt_util__filter_out_livevals(BetweenTrue0, Between)
|
|
;
|
|
fail
|
|
).
|
|
|
|
opt_util__filter_out_r1([], no, []).
|
|
opt_util__filter_out_r1([Instr0 | Instrs0], Success, Instrs) :-
|
|
opt_util__filter_out_r1(Instrs0, Success0, Instrs1),
|
|
( Instr0 = assign(reg(r, 1), const(Success1)) - _ ->
|
|
Instrs = Instrs1,
|
|
Success = yes(Success1)
|
|
;
|
|
Instrs = [Instr0 | Instrs1],
|
|
Success = Success0
|
|
).
|
|
|
|
opt_util__straight_alternative(Instrs0, Between, After) :-
|
|
opt_util__straight_alternative_2(Instrs0, [], BetweenRev, After),
|
|
list__reverse(BetweenRev, Between).
|
|
|
|
:- pred opt_util__straight_alternative_2(list(instruction), list(instruction),
|
|
list(instruction), list(instruction)).
|
|
:- mode opt_util__straight_alternative_2(in, in, out, out) is semidet.
|
|
|
|
opt_util__straight_alternative_2([Instr0 | Instrs0], Between0, Between,
|
|
After) :-
|
|
Instr0 = Uinstr0 - _,
|
|
(
|
|
(
|
|
opt_util__can_instr_branch_away(Uinstr0, no),
|
|
opt_util__touches_nondet_ctrl_instr(Uinstr0, no)
|
|
;
|
|
Uinstr0 = if_val(_, CodeAddr),
|
|
( CodeAddr = do_fail ; CodeAddr = do_redo )
|
|
)
|
|
->
|
|
opt_util__straight_alternative_2(Instrs0, [Instr0 | Between0],
|
|
Between, After)
|
|
;
|
|
Uinstr0 = goto(do_succeed(no))
|
|
->
|
|
Between = Between0,
|
|
After = Instrs0
|
|
;
|
|
fail
|
|
).
|
|
|
|
opt_util__no_stack_straight_line(Instrs0, Shuffle, Instrs) :-
|
|
opt_util__no_stack_straight_line_2(Instrs0, [], RevShuffle, Instrs),
|
|
list__reverse(RevShuffle, Shuffle).
|
|
|
|
:- pred opt_util__no_stack_straight_line_2(list(instruction),
|
|
list(instruction), list(instruction), list(instruction)).
|
|
:- mode opt_util__no_stack_straight_line_2(in, in, out, out) is det.
|
|
|
|
opt_util__no_stack_straight_line_2([], After, After, []).
|
|
opt_util__no_stack_straight_line_2([Instr0 | Instrs0], After0, After, Instrs) :-
|
|
Instr0 = Uinstr - _,
|
|
(
|
|
(
|
|
Uinstr = comment(_)
|
|
;
|
|
Uinstr = livevals(_)
|
|
;
|
|
Uinstr = assign(Lval, Rval),
|
|
opt_util__lval_refers_stackvars(Lval, no),
|
|
opt_util__rval_refers_stackvars(Rval, no)
|
|
)
|
|
->
|
|
After1 = [Instr0 | After0],
|
|
opt_util__no_stack_straight_line_2(Instrs0, After1, After, Instrs)
|
|
;
|
|
After = After0,
|
|
Instrs = [Instr0 | Instrs0]
|
|
).
|
|
|
|
opt_util__lval_refers_stackvars(reg(_, _), no).
|
|
opt_util__lval_refers_stackvars(stackvar(_), yes).
|
|
opt_util__lval_refers_stackvars(framevar(_), yes).
|
|
opt_util__lval_refers_stackvars(succip, no).
|
|
opt_util__lval_refers_stackvars(maxfr, no).
|
|
opt_util__lval_refers_stackvars(curfr, no).
|
|
opt_util__lval_refers_stackvars(succfr(Rval), Refers) :-
|
|
opt_util__rval_refers_stackvars(Rval, Refers).
|
|
opt_util__lval_refers_stackvars(prevfr(Rval), Refers) :-
|
|
opt_util__rval_refers_stackvars(Rval, Refers).
|
|
opt_util__lval_refers_stackvars(redofr(Rval), Refers) :-
|
|
opt_util__rval_refers_stackvars(Rval, Refers).
|
|
opt_util__lval_refers_stackvars(redoip(Rval), Refers) :-
|
|
opt_util__rval_refers_stackvars(Rval, Refers).
|
|
opt_util__lval_refers_stackvars(succip(Rval), Refers) :-
|
|
opt_util__rval_refers_stackvars(Rval, Refers).
|
|
opt_util__lval_refers_stackvars(hp, no).
|
|
opt_util__lval_refers_stackvars(sp, no).
|
|
opt_util__lval_refers_stackvars(field(_, Rval, FieldNum), Refers) :-
|
|
opt_util__rval_refers_stackvars(Rval, Refers1),
|
|
opt_util__rval_refers_stackvars(FieldNum, Refers2),
|
|
bool__or(Refers1, Refers2, Refers).
|
|
opt_util__lval_refers_stackvars(lvar(_), _) :-
|
|
error("found lvar in lval_refers_stackvars").
|
|
opt_util__lval_refers_stackvars(temp(_, _), no).
|
|
opt_util__lval_refers_stackvars(mem_ref(Rval), Refers) :-
|
|
opt_util__rval_refers_stackvars(Rval, Refers).
|
|
|
|
:- pred opt_util__mem_ref_refers_stackvars(mem_ref, bool).
|
|
:- mode opt_util__mem_ref_refers_stackvars(in, out) is det.
|
|
|
|
opt_util__mem_ref_refers_stackvars(stackvar_ref(_), yes).
|
|
opt_util__mem_ref_refers_stackvars(framevar_ref(_), yes).
|
|
opt_util__mem_ref_refers_stackvars(heap_ref(Rval, _, _), Refers) :-
|
|
opt_util__rval_refers_stackvars(Rval, Refers).
|
|
|
|
opt_util__rval_refers_stackvars(lval(Lval), Refers) :-
|
|
opt_util__lval_refers_stackvars(Lval, Refers).
|
|
opt_util__rval_refers_stackvars(var(_), _) :-
|
|
error("found var in rval_refers_stackvars").
|
|
opt_util__rval_refers_stackvars(mkword(_, Rval), Refers) :-
|
|
opt_util__rval_refers_stackvars(Rval, Refers).
|
|
opt_util__rval_refers_stackvars(const(_), no).
|
|
opt_util__rval_refers_stackvars(unop(_, Rval), Refers) :-
|
|
opt_util__rval_refers_stackvars(Rval, Refers).
|
|
opt_util__rval_refers_stackvars(binop(_, Rval1, Rval2), Refers) :-
|
|
opt_util__rval_refers_stackvars(Rval1, Refers1),
|
|
opt_util__rval_refers_stackvars(Rval2, Refers2),
|
|
bool__or(Refers1, Refers2, Refers).
|
|
opt_util__rval_refers_stackvars(mem_addr(MemRef), Refers) :-
|
|
opt_util__mem_ref_refers_stackvars(MemRef, Refers).
|
|
|
|
% XXX probably unused
|
|
opt_util__rvals_refer_stackvars([], no).
|
|
opt_util__rvals_refer_stackvars([MaybeRval | Tail], Refers) :-
|
|
(
|
|
(
|
|
MaybeRval = no
|
|
;
|
|
MaybeRval = yes(Rval),
|
|
opt_util__rval_refers_stackvars(Rval, no)
|
|
)
|
|
->
|
|
opt_util__rvals_refer_stackvars(Tail, Refers)
|
|
;
|
|
Refers = yes
|
|
).
|
|
|
|
opt_util__no_stackvars_til_decr_sp([Instr0 | Instrs0], FrameSize,
|
|
Between, Remain) :-
|
|
Instr0 = Uinstr0 - _,
|
|
(
|
|
Uinstr0 = comment(_),
|
|
opt_util__no_stackvars_til_decr_sp(Instrs0, FrameSize,
|
|
Between0, Remain),
|
|
Between = [Instr0 | Between0]
|
|
;
|
|
Uinstr0 = livevals(_),
|
|
opt_util__no_stackvars_til_decr_sp(Instrs0, FrameSize,
|
|
Between0, Remain),
|
|
Between = [Instr0 | Between0]
|
|
;
|
|
Uinstr0 = assign(Lval, Rval),
|
|
(
|
|
Lval = stackvar(_),
|
|
opt_util__rval_refers_stackvars(Rval, no)
|
|
->
|
|
opt_util__no_stackvars_til_decr_sp(Instrs0, FrameSize,
|
|
Between, Remain)
|
|
;
|
|
Lval = succip,
|
|
Rval = lval(stackvar(FrameSize)),
|
|
opt_util__skip_comments(Instrs0, Instrs1),
|
|
Instrs1 = [decr_sp(FrameSize) - _ | Instrs2]
|
|
->
|
|
Between = [],
|
|
Remain = Instrs2
|
|
;
|
|
opt_util__lval_refers_stackvars(Lval, no),
|
|
opt_util__rval_refers_stackvars(Rval, no),
|
|
opt_util__no_stackvars_til_decr_sp(Instrs0, FrameSize,
|
|
Between0, Remain),
|
|
Between = [Instr0 | Between0]
|
|
)
|
|
;
|
|
Uinstr0 = incr_hp(Lval, _, _, Rval, _),
|
|
opt_util__lval_refers_stackvars(Lval, no),
|
|
opt_util__rval_refers_stackvars(Rval, no),
|
|
opt_util__no_stackvars_til_decr_sp(Instrs0, FrameSize,
|
|
Between0, Remain),
|
|
Between = [Instr0 | Between0]
|
|
;
|
|
Uinstr0 = decr_sp(FrameSize),
|
|
Between = [],
|
|
Remain = Instrs0
|
|
).
|
|
|
|
opt_util__block_refers_stackvars([], no).
|
|
opt_util__block_refers_stackvars([Uinstr0 - _ | Instrs0], Need) :-
|
|
(
|
|
Uinstr0 = comment(_),
|
|
opt_util__block_refers_stackvars(Instrs0, Need)
|
|
;
|
|
Uinstr0 = livevals(_),
|
|
opt_util__block_refers_stackvars(Instrs0, Need)
|
|
;
|
|
Uinstr0 = block(_, _, BlockInstrs),
|
|
opt_util__block_refers_stackvars(BlockInstrs, Need)
|
|
;
|
|
Uinstr0 = assign(Lval, Rval),
|
|
opt_util__lval_refers_stackvars(Lval, Use1),
|
|
opt_util__rval_refers_stackvars(Rval, Use2),
|
|
bool__or(Use1, Use2, Use),
|
|
( Use = yes ->
|
|
Need = yes
|
|
;
|
|
opt_util__block_refers_stackvars(Instrs0, Need)
|
|
)
|
|
;
|
|
Uinstr0 = call(_, _, _, _, _, _),
|
|
Need = no
|
|
;
|
|
Uinstr0 = mkframe(_, _),
|
|
Need = no
|
|
;
|
|
Uinstr0 = label(_),
|
|
Need = no
|
|
;
|
|
Uinstr0 = goto(_),
|
|
Need = no
|
|
;
|
|
Uinstr0 = computed_goto(Rval, _),
|
|
opt_util__rval_refers_stackvars(Rval, Use),
|
|
( Use = yes ->
|
|
Need = yes
|
|
;
|
|
Need = no
|
|
)
|
|
;
|
|
Uinstr0 = c_code(_, _),
|
|
Need = no
|
|
;
|
|
Uinstr0 = if_val(Rval, _),
|
|
opt_util__rval_refers_stackvars(Rval, Use),
|
|
( Use = yes ->
|
|
Need = yes
|
|
;
|
|
Need = no
|
|
)
|
|
;
|
|
Uinstr0 = incr_hp(Lval, _, _, Rval, _),
|
|
opt_util__lval_refers_stackvars(Lval, Use1),
|
|
opt_util__rval_refers_stackvars(Rval, Use2),
|
|
bool__or(Use1, Use2, Use),
|
|
( Use = yes ->
|
|
Need = yes
|
|
;
|
|
opt_util__block_refers_stackvars(Instrs0, Need)
|
|
)
|
|
;
|
|
Uinstr0 = mark_hp(Lval),
|
|
opt_util__lval_refers_stackvars(Lval, Use),
|
|
( Use = yes ->
|
|
Need = yes
|
|
;
|
|
opt_util__block_refers_stackvars(Instrs0, Need)
|
|
)
|
|
;
|
|
Uinstr0 = restore_hp(Rval),
|
|
opt_util__rval_refers_stackvars(Rval, Use),
|
|
( Use = yes ->
|
|
Need = yes
|
|
;
|
|
opt_util__block_refers_stackvars(Instrs0, Need)
|
|
)
|
|
;
|
|
Uinstr0 = free_heap(Rval),
|
|
opt_util__rval_refers_stackvars(Rval, Use),
|
|
( Use = yes ->
|
|
Need = yes
|
|
;
|
|
opt_util__block_refers_stackvars(Instrs0, Need)
|
|
)
|
|
;
|
|
Uinstr0 = store_ticket(Lval),
|
|
opt_util__lval_refers_stackvars(Lval, Use),
|
|
( Use = yes ->
|
|
Need = yes
|
|
;
|
|
opt_util__block_refers_stackvars(Instrs0, Need)
|
|
)
|
|
;
|
|
Uinstr0 = reset_ticket(Rval, _Reason),
|
|
opt_util__rval_refers_stackvars(Rval, Use),
|
|
( Use = yes ->
|
|
Need = yes
|
|
;
|
|
opt_util__block_refers_stackvars(Instrs0, Need)
|
|
)
|
|
;
|
|
Uinstr0 = discard_ticket,
|
|
opt_util__block_refers_stackvars(Instrs0, Need)
|
|
;
|
|
Uinstr0 = prune_ticket,
|
|
opt_util__block_refers_stackvars(Instrs0, Need)
|
|
;
|
|
Uinstr0 = mark_ticket_stack(Lval),
|
|
opt_util__lval_refers_stackvars(Lval, Use),
|
|
( Use = yes ->
|
|
Need = yes
|
|
;
|
|
opt_util__block_refers_stackvars(Instrs0, Need)
|
|
)
|
|
;
|
|
Uinstr0 = prune_tickets_to(Rval),
|
|
opt_util__rval_refers_stackvars(Rval, Use),
|
|
( Use = yes ->
|
|
Need = yes
|
|
;
|
|
opt_util__block_refers_stackvars(Instrs0, Need)
|
|
)
|
|
;
|
|
% handled specially
|
|
Uinstr0 = incr_sp(_, _),
|
|
Need = no
|
|
;
|
|
% handled specially
|
|
Uinstr0 = decr_sp(_),
|
|
Need = no
|
|
;
|
|
Uinstr0 = pragma_c(_, _, _, _, _, _, _, _),
|
|
Need = no
|
|
;
|
|
Uinstr0 = init_sync_term(Lval, _),
|
|
opt_util__lval_refers_stackvars(Lval, Need)
|
|
;
|
|
Uinstr0 = fork(_, _, _),
|
|
Need = no
|
|
;
|
|
Uinstr0 = join_and_terminate(Lval),
|
|
opt_util__lval_refers_stackvars(Lval, Use),
|
|
( Use = yes ->
|
|
Need = yes
|
|
;
|
|
opt_util__block_refers_stackvars(Instrs0, Need)
|
|
)
|
|
;
|
|
Uinstr0 = join_and_continue(Lval, _),
|
|
opt_util__lval_refers_stackvars(Lval, Use),
|
|
( Use = yes ->
|
|
Need = yes
|
|
;
|
|
opt_util__block_refers_stackvars(Instrs0, Need)
|
|
)
|
|
).
|
|
|
|
opt_util__filter_out_labels([], []).
|
|
opt_util__filter_out_labels([Instr0 | Instrs0], Instrs) :-
|
|
opt_util__filter_out_labels(Instrs0, Instrs1),
|
|
( Instr0 = label(_) - _ ->
|
|
Instrs = Instrs1
|
|
;
|
|
Instrs = [Instr0 | Instrs1]
|
|
).
|
|
|
|
opt_util__filter_out_bad_livevals([], []).
|
|
opt_util__filter_out_bad_livevals([Instr0 | Instrs0], Instrs) :-
|
|
opt_util__filter_out_bad_livevals(Instrs0, Instrs1),
|
|
(
|
|
Instr0 = livevals(_) - _,
|
|
opt_util__skip_comments(Instrs1, Instrs2),
|
|
Instrs2 = [Uinstr2 - _ | _],
|
|
opt_util__can_use_livevals(Uinstr2, no)
|
|
->
|
|
Instrs = Instrs1
|
|
;
|
|
Instrs = [Instr0 | Instrs1]
|
|
).
|
|
|
|
opt_util__filter_out_livevals([], []).
|
|
opt_util__filter_out_livevals([Instr0 | Instrs0], Instrs) :-
|
|
opt_util__filter_out_livevals(Instrs0, Instrs1),
|
|
( Instr0 = livevals(_) - _ ->
|
|
Instrs = Instrs1
|
|
;
|
|
Instrs = [Instr0 | Instrs1]
|
|
).
|
|
|
|
opt_util__filter_in_livevals([], []).
|
|
opt_util__filter_in_livevals([Instr0 | Instrs0], Instrs) :-
|
|
opt_util__filter_in_livevals(Instrs0, Instrs1),
|
|
( Instr0 = livevals(_) - _ ->
|
|
Instrs = [Instr0 | Instrs1]
|
|
;
|
|
Instrs = Instrs1
|
|
).
|
|
|
|
% We recognize only a subset of all constant conditions.
|
|
% The time to extend this predicate is when the rest of the compiler
|
|
% generates more complicated constant conditions.
|
|
|
|
opt_util__is_const_condition(const(Const), Taken) :-
|
|
( Const = true ->
|
|
Taken = yes
|
|
; Const = false ->
|
|
Taken = no
|
|
;
|
|
error("non-boolean constant as if-then-else condition")
|
|
).
|
|
opt_util__is_const_condition(unop(Op, Rval1), Taken) :-
|
|
Op = (not),
|
|
opt_util__is_const_condition(Rval1, Taken1),
|
|
bool__not(Taken1, Taken).
|
|
opt_util__is_const_condition(binop(Op, Rval1, Rval2), Taken) :-
|
|
Op = eq,
|
|
Rval1 = Rval2,
|
|
Taken = yes.
|
|
|
|
opt_util__can_instr_branch_away(comment(_), no).
|
|
opt_util__can_instr_branch_away(livevals(_), no).
|
|
opt_util__can_instr_branch_away(block(_, _, _), yes).
|
|
opt_util__can_instr_branch_away(assign(_, _), no).
|
|
opt_util__can_instr_branch_away(call(_, _, _, _, _, _), yes).
|
|
opt_util__can_instr_branch_away(mkframe(_, _), no).
|
|
opt_util__can_instr_branch_away(label(_), no).
|
|
opt_util__can_instr_branch_away(goto(_), yes).
|
|
opt_util__can_instr_branch_away(computed_goto(_, _), yes).
|
|
opt_util__can_instr_branch_away(c_code(_, _), no).
|
|
opt_util__can_instr_branch_away(if_val(_, _), yes).
|
|
opt_util__can_instr_branch_away(incr_hp(_, _, _, _, _), no).
|
|
opt_util__can_instr_branch_away(mark_hp(_), no).
|
|
opt_util__can_instr_branch_away(restore_hp(_), no).
|
|
opt_util__can_instr_branch_away(free_heap(_), no).
|
|
opt_util__can_instr_branch_away(store_ticket(_), no).
|
|
opt_util__can_instr_branch_away(reset_ticket(_, _), no).
|
|
opt_util__can_instr_branch_away(discard_ticket, no).
|
|
opt_util__can_instr_branch_away(prune_ticket, no).
|
|
opt_util__can_instr_branch_away(mark_ticket_stack(_), no).
|
|
opt_util__can_instr_branch_away(prune_tickets_to(_), no).
|
|
opt_util__can_instr_branch_away(incr_sp(_, _), no).
|
|
opt_util__can_instr_branch_away(decr_sp(_), no).
|
|
opt_util__can_instr_branch_away(init_sync_term(_, _), no).
|
|
opt_util__can_instr_branch_away(fork(_, _, _), yes).
|
|
opt_util__can_instr_branch_away(join_and_terminate(_), no).
|
|
opt_util__can_instr_branch_away(join_and_continue(_, _), yes).
|
|
opt_util__can_instr_branch_away(pragma_c(_, Comps, _, _, _, _, _, _),
|
|
BranchAway) :-
|
|
opt_util__can_components_branch_away(Comps, BranchAway).
|
|
|
|
:- pred opt_util__can_components_branch_away(list(pragma_c_component), bool).
|
|
:- mode opt_util__can_components_branch_away(in, out) is det.
|
|
|
|
opt_util__can_components_branch_away([], no).
|
|
opt_util__can_components_branch_away([Component | Components], BranchAway) :-
|
|
opt_util__can_component_branch_away(Component, BranchAway1),
|
|
( BranchAway1 = yes ->
|
|
BranchAway = yes
|
|
;
|
|
opt_util__can_components_branch_away(Components, BranchAway)
|
|
).
|
|
|
|
:- pred opt_util__can_component_branch_away(pragma_c_component, bool).
|
|
:- mode opt_util__can_component_branch_away(in, out) is det.
|
|
|
|
% The input and output components get expanded to straight line code.
|
|
% Some of the raw_code components we generate for nondet pragma C codes
|
|
% invoke succeed(), which definitely does branch away.
|
|
% Also the raw_code components for semidet pragma C codes can
|
|
% branch to a label on failure.
|
|
% User-written C code cannot branch away because users do not know
|
|
% how to do that. (They can call other functions, but those functions
|
|
% will return, so control will still go to the instruction following
|
|
% this one. We the developers could write C code that branched away,
|
|
% but we are careful to preserve a declarative interface, and that
|
|
% is incompatible with branching away.)
|
|
|
|
opt_util__can_component_branch_away(pragma_c_inputs(_), no).
|
|
opt_util__can_component_branch_away(pragma_c_outputs(_), no).
|
|
opt_util__can_component_branch_away(pragma_c_raw_code(Code, _),
|
|
CanBranchAway) :-
|
|
( Code = "" -> CanBranchAway = no ; CanBranchAway = yes ).
|
|
opt_util__can_component_branch_away(pragma_c_user_code(_, _), no).
|
|
opt_util__can_component_branch_away(pragma_c_fail_to(_), yes).
|
|
opt_util__can_component_branch_away(pragma_c_noop, no).
|
|
|
|
opt_util__can_instr_fall_through(comment(_), yes).
|
|
opt_util__can_instr_fall_through(livevals(_), yes).
|
|
opt_util__can_instr_fall_through(block(_, _, Instrs), FallThrough) :-
|
|
opt_util__can_block_fall_through(Instrs, FallThrough).
|
|
opt_util__can_instr_fall_through(assign(_, _), yes).
|
|
opt_util__can_instr_fall_through(call(_, _, _, _, _, _), no).
|
|
opt_util__can_instr_fall_through(mkframe(_, _), yes).
|
|
opt_util__can_instr_fall_through(label(_), yes).
|
|
opt_util__can_instr_fall_through(goto(_), no).
|
|
opt_util__can_instr_fall_through(computed_goto(_, _), no).
|
|
opt_util__can_instr_fall_through(c_code(_, _), yes).
|
|
opt_util__can_instr_fall_through(if_val(_, _), yes).
|
|
opt_util__can_instr_fall_through(incr_hp(_, _, _, _, _), yes).
|
|
opt_util__can_instr_fall_through(mark_hp(_), yes).
|
|
opt_util__can_instr_fall_through(restore_hp(_), yes).
|
|
opt_util__can_instr_fall_through(free_heap(_), yes).
|
|
opt_util__can_instr_fall_through(store_ticket(_), yes).
|
|
opt_util__can_instr_fall_through(reset_ticket(_, _), yes).
|
|
opt_util__can_instr_fall_through(discard_ticket, yes).
|
|
opt_util__can_instr_fall_through(prune_ticket, yes).
|
|
opt_util__can_instr_fall_through(mark_ticket_stack(_), yes).
|
|
opt_util__can_instr_fall_through(prune_tickets_to(_), yes).
|
|
opt_util__can_instr_fall_through(incr_sp(_, _), yes).
|
|
opt_util__can_instr_fall_through(decr_sp(_), yes).
|
|
opt_util__can_instr_fall_through(init_sync_term(_, _), yes).
|
|
opt_util__can_instr_fall_through(fork(_, _, _), no).
|
|
opt_util__can_instr_fall_through(join_and_terminate(_), no).
|
|
opt_util__can_instr_fall_through(join_and_continue(_, _), no).
|
|
opt_util__can_instr_fall_through(pragma_c(_, _, _, _, _, _, _, _), yes).
|
|
|
|
% Check whether an instruction sequence can possibly fall through
|
|
% to the next instruction without using its label.
|
|
|
|
:- pred opt_util__can_block_fall_through(list(instruction), bool).
|
|
:- mode opt_util__can_block_fall_through(in, out) is det.
|
|
|
|
opt_util__can_block_fall_through([], yes).
|
|
opt_util__can_block_fall_through([Instr - _ | Instrs], FallThrough) :-
|
|
( opt_util__can_instr_fall_through(Instr, no) ->
|
|
FallThrough = no
|
|
;
|
|
opt_util__can_block_fall_through(Instrs, FallThrough)
|
|
).
|
|
|
|
:- pred opt_util__can_use_livevals(instr, bool).
|
|
:- mode opt_util__can_use_livevals(in, out) is det.
|
|
|
|
opt_util__can_use_livevals(comment(_), no).
|
|
opt_util__can_use_livevals(livevals(_), no).
|
|
opt_util__can_use_livevals(block(_, _, _), no).
|
|
opt_util__can_use_livevals(assign(_, _), no).
|
|
opt_util__can_use_livevals(call(_, _, _, _, _, _), yes).
|
|
opt_util__can_use_livevals(mkframe(_, _), no).
|
|
opt_util__can_use_livevals(label(_), no).
|
|
opt_util__can_use_livevals(goto(_), yes).
|
|
opt_util__can_use_livevals(computed_goto(_, _), no).
|
|
opt_util__can_use_livevals(c_code(_, _), no).
|
|
opt_util__can_use_livevals(if_val(_, _), yes).
|
|
opt_util__can_use_livevals(incr_hp(_, _, _, _, _), no).
|
|
opt_util__can_use_livevals(mark_hp(_), no).
|
|
opt_util__can_use_livevals(restore_hp(_), no).
|
|
opt_util__can_use_livevals(free_heap(_), no).
|
|
opt_util__can_use_livevals(store_ticket(_), no).
|
|
opt_util__can_use_livevals(reset_ticket(_, _), no).
|
|
opt_util__can_use_livevals(discard_ticket, no).
|
|
opt_util__can_use_livevals(prune_ticket, no).
|
|
opt_util__can_use_livevals(mark_ticket_stack(_), no).
|
|
opt_util__can_use_livevals(prune_tickets_to(_), no).
|
|
opt_util__can_use_livevals(incr_sp(_, _), no).
|
|
opt_util__can_use_livevals(decr_sp(_), no).
|
|
opt_util__can_use_livevals(init_sync_term(_, _), no).
|
|
opt_util__can_use_livevals(fork(_, _, _), no).
|
|
opt_util__can_use_livevals(join_and_terminate(_), no).
|
|
opt_util__can_use_livevals(join_and_continue(_, _), no).
|
|
opt_util__can_use_livevals(pragma_c(_, _, _, _, _, _, _, _), no).
|
|
|
|
% determine all the labels and code_addresses that are referenced by Instr
|
|
|
|
opt_util__instr_labels(Instr, Labels, CodeAddrs) :-
|
|
opt_util__instr_labels_2(Instr, Labels0, CodeAddrs1),
|
|
opt_util__instr_rvals_and_lvals(Instr, Rvals, Lvals),
|
|
exprn_aux__rval_list_addrs(Rvals, CodeAddrs2, _),
|
|
exprn_aux__lval_list_addrs(Lvals, CodeAddrs3, _),
|
|
list__append(CodeAddrs1, CodeAddrs2, CodeAddrs12),
|
|
list__append(CodeAddrs12, CodeAddrs3, CodeAddrs),
|
|
opt_util__find_label_code_addrs(CodeAddrs, Labels0, Labels).
|
|
|
|
:- pred opt_util__find_label_code_addrs(list(code_addr),
|
|
list(label), list(label)).
|
|
:- mode opt_util__find_label_code_addrs(in, in, out) is det.
|
|
|
|
% Find out which code addresses are also labels.
|
|
|
|
opt_util__find_label_code_addrs([], Labels, Labels).
|
|
opt_util__find_label_code_addrs([CodeAddr | Rest], Labels0, Labels) :-
|
|
( CodeAddr = label(Label) ->
|
|
Labels1 = [Label | Labels0]
|
|
;
|
|
Labels1 = Labels0
|
|
),
|
|
opt_util__find_label_code_addrs(Rest, Labels1, Labels).
|
|
|
|
:- pred opt_util__instr_labels_2(instr, list(label), list(code_addr)).
|
|
:- mode opt_util__instr_labels_2(in, out, out) is det.
|
|
|
|
% determine all the labels and code_addresses that are directly
|
|
% referenced by an instruction (not counting ones referenced indirectly
|
|
% via rvals or lvals)
|
|
|
|
opt_util__instr_labels_2(comment(_), [], []).
|
|
opt_util__instr_labels_2(livevals(_), [], []).
|
|
opt_util__instr_labels_2(block(_, _, Instrs), Labels, CodeAddrs) :-
|
|
opt_util__instr_list_labels(Instrs, Labels, CodeAddrs).
|
|
opt_util__instr_labels_2(assign(_,_), [], []).
|
|
opt_util__instr_labels_2(call(Target, Ret, _, _, _, _), [], [Target, Ret]).
|
|
opt_util__instr_labels_2(mkframe(_, Addr), [], [Addr]).
|
|
opt_util__instr_labels_2(label(_), [], []).
|
|
opt_util__instr_labels_2(goto(Addr), [], [Addr]).
|
|
opt_util__instr_labels_2(computed_goto(_, Labels), Labels, []).
|
|
opt_util__instr_labels_2(c_code(_, _), [], []).
|
|
opt_util__instr_labels_2(if_val(_, Addr), [], [Addr]).
|
|
opt_util__instr_labels_2(incr_hp(_, _, _, _, _), [], []).
|
|
opt_util__instr_labels_2(mark_hp(_), [], []).
|
|
opt_util__instr_labels_2(restore_hp(_), [], []).
|
|
opt_util__instr_labels_2(free_heap(_), [], []).
|
|
opt_util__instr_labels_2(store_ticket(_), [], []).
|
|
opt_util__instr_labels_2(reset_ticket(_, _), [], []).
|
|
opt_util__instr_labels_2(discard_ticket, [], []).
|
|
opt_util__instr_labels_2(prune_ticket, [], []).
|
|
opt_util__instr_labels_2(mark_ticket_stack(_), [], []).
|
|
opt_util__instr_labels_2(prune_tickets_to(_), [], []).
|
|
opt_util__instr_labels_2(incr_sp(_, _), [], []).
|
|
opt_util__instr_labels_2(decr_sp(_), [], []).
|
|
opt_util__instr_labels_2(init_sync_term(_, _), [], []).
|
|
opt_util__instr_labels_2(fork(Child, Parent, _), [Child, Parent], []).
|
|
opt_util__instr_labels_2(join_and_terminate(_), [], []).
|
|
opt_util__instr_labels_2(join_and_continue(_, Label), [Label], []).
|
|
opt_util__instr_labels_2(pragma_c(_, _, _, MaybeFixLabel, MaybeLayoutLabel,
|
|
MaybeOnlyLayoutLabel, MaybeSubLabel, _), Labels, []) :-
|
|
opt_util__pragma_c_labels(MaybeFixLabel, MaybeLayoutLabel,
|
|
MaybeOnlyLayoutLabel, MaybeSubLabel, Labels).
|
|
|
|
opt_util__possible_targets(comment(_), []).
|
|
opt_util__possible_targets(livevals(_), []).
|
|
opt_util__possible_targets(block(_, _, _), _) :-
|
|
error("block in possible_targets").
|
|
opt_util__possible_targets(assign(_, _), []).
|
|
opt_util__possible_targets(call(_, ReturnAddr, _, _, _, _), Labels) :-
|
|
( ReturnAddr = label(Label) ->
|
|
Labels = [Label]
|
|
;
|
|
Labels = []
|
|
).
|
|
opt_util__possible_targets(mkframe(_, _), []).
|
|
opt_util__possible_targets(label(_), []).
|
|
opt_util__possible_targets(goto(CodeAddr), Targets) :-
|
|
( CodeAddr = label(Label) ->
|
|
Targets = [Label]
|
|
;
|
|
Targets = []
|
|
).
|
|
opt_util__possible_targets(computed_goto(_, Targets), Targets).
|
|
opt_util__possible_targets(c_code(_, _), []).
|
|
opt_util__possible_targets(if_val(_, CodeAddr), Targets) :-
|
|
( CodeAddr = label(Label) ->
|
|
Targets = [Label]
|
|
;
|
|
Targets = []
|
|
).
|
|
opt_util__possible_targets(incr_hp(_, _, _, _, _), []).
|
|
opt_util__possible_targets(mark_hp(_), []).
|
|
opt_util__possible_targets(restore_hp(_), []).
|
|
opt_util__possible_targets(free_heap(_), []).
|
|
opt_util__possible_targets(store_ticket(_), []).
|
|
opt_util__possible_targets(reset_ticket(_, _), []).
|
|
opt_util__possible_targets(discard_ticket, []).
|
|
opt_util__possible_targets(prune_ticket, []).
|
|
opt_util__possible_targets(mark_ticket_stack(_), []).
|
|
opt_util__possible_targets(prune_tickets_to(_), []).
|
|
opt_util__possible_targets(incr_sp(_, _), []).
|
|
opt_util__possible_targets(decr_sp(_), []).
|
|
opt_util__possible_targets(init_sync_term(_, _), []).
|
|
opt_util__possible_targets(fork(Child, Parent, _), [Child, Parent]).
|
|
opt_util__possible_targets(join_and_terminate(_), []).
|
|
opt_util__possible_targets(join_and_continue(_, L), [L]).
|
|
opt_util__possible_targets(pragma_c(_, _, _, MaybeFixedLabel, MaybeLayoutLabel,
|
|
_, MaybeSubLabel, _), Labels) :-
|
|
opt_util__pragma_c_labels(MaybeFixedLabel, MaybeLayoutLabel,
|
|
no, MaybeSubLabel, Labels).
|
|
|
|
:- pred opt_util__pragma_c_labels(maybe(label), maybe(label), maybe(label),
|
|
maybe(label), list(label)).
|
|
:- mode opt_util__pragma_c_labels(in, in, in, in, out) is det.
|
|
|
|
opt_util__pragma_c_labels(MaybeFixedLabel, MaybeLayoutLabel,
|
|
MaybeOnlyLayoutLabel, MaybeSubLabel, Labels) :-
|
|
( MaybeFixedLabel = yes(FixedLabel) ->
|
|
Labels0 = [FixedLabel]
|
|
;
|
|
Labels0 = []
|
|
),
|
|
( MaybeLayoutLabel = yes(LayoutLabel) ->
|
|
Labels1 = [LayoutLabel | Labels0]
|
|
;
|
|
Labels1 = Labels0
|
|
),
|
|
( MaybeOnlyLayoutLabel = yes(OnlyLayoutLabel) ->
|
|
Labels2 = [OnlyLayoutLabel | Labels1]
|
|
;
|
|
Labels2 = Labels1
|
|
),
|
|
( MaybeSubLabel = yes(SubLabel) ->
|
|
Labels = [SubLabel | Labels2]
|
|
;
|
|
Labels = Labels2
|
|
).
|
|
|
|
:- pred opt_util__instr_rvals_and_lvals(instr, list(rval), list(lval)).
|
|
:- mode opt_util__instr_rvals_and_lvals(in, out, out) is det.
|
|
|
|
% determine all the rvals and lvals referenced by an instruction
|
|
|
|
opt_util__instr_rvals_and_lvals(comment(_), [], []).
|
|
opt_util__instr_rvals_and_lvals(livevals(_), [], []).
|
|
opt_util__instr_rvals_and_lvals(block(_, _, Instrs), Labels, CodeAddrs) :-
|
|
opt_util__instr_list_rvals_and_lvals(Instrs, Labels, CodeAddrs).
|
|
opt_util__instr_rvals_and_lvals(assign(Lval,Rval), [Rval], [Lval]).
|
|
opt_util__instr_rvals_and_lvals(call(_, _, _, _, _, _), [], []).
|
|
opt_util__instr_rvals_and_lvals(mkframe(_, _), [], []).
|
|
opt_util__instr_rvals_and_lvals(label(_), [], []).
|
|
opt_util__instr_rvals_and_lvals(goto(_), [], []).
|
|
opt_util__instr_rvals_and_lvals(computed_goto(Rval, _), [Rval], []).
|
|
opt_util__instr_rvals_and_lvals(c_code(_, _), [], []).
|
|
opt_util__instr_rvals_and_lvals(if_val(Rval, _), [Rval], []).
|
|
opt_util__instr_rvals_and_lvals(incr_hp(Lval, _, _, Rval, _), [Rval], [Lval]).
|
|
opt_util__instr_rvals_and_lvals(mark_hp(Lval), [], [Lval]).
|
|
opt_util__instr_rvals_and_lvals(restore_hp(Rval), [Rval], []).
|
|
opt_util__instr_rvals_and_lvals(free_heap(Rval), [Rval], []).
|
|
opt_util__instr_rvals_and_lvals(store_ticket(Lval), [], [Lval]).
|
|
opt_util__instr_rvals_and_lvals(reset_ticket(Rval, _Reason), [Rval], []).
|
|
opt_util__instr_rvals_and_lvals(discard_ticket, [], []).
|
|
opt_util__instr_rvals_and_lvals(prune_ticket, [], []).
|
|
opt_util__instr_rvals_and_lvals(mark_ticket_stack(Lval), [], [Lval]).
|
|
opt_util__instr_rvals_and_lvals(prune_tickets_to(Rval), [Rval], []).
|
|
opt_util__instr_rvals_and_lvals(incr_sp(_, _), [], []).
|
|
opt_util__instr_rvals_and_lvals(decr_sp(_), [], []).
|
|
opt_util__instr_rvals_and_lvals(init_sync_term(Lval, _), [], [Lval]).
|
|
opt_util__instr_rvals_and_lvals(fork(_, _, _), [], []).
|
|
opt_util__instr_rvals_and_lvals(join_and_terminate(Lval), [], [Lval]).
|
|
opt_util__instr_rvals_and_lvals(join_and_continue(Lval, _), [], [Lval]).
|
|
opt_util__instr_rvals_and_lvals(pragma_c(_, Cs, _, _, _, _, _, _),
|
|
Rvals, Lvals) :-
|
|
pragma_c_components_get_rvals_and_lvals(Cs, Rvals, Lvals).
|
|
|
|
% extract the rvals and lvals from the pragma_c_components
|
|
:- pred pragma_c_components_get_rvals_and_lvals(list(pragma_c_component),
|
|
list(rval), list(lval)).
|
|
:- mode pragma_c_components_get_rvals_and_lvals(in, out, out) is det.
|
|
|
|
pragma_c_components_get_rvals_and_lvals([], [], []).
|
|
pragma_c_components_get_rvals_and_lvals([Comp | Comps], Rvals, Lvals) :-
|
|
pragma_c_components_get_rvals_and_lvals(Comps, Rvals1, Lvals1),
|
|
pragma_c_component_get_rvals_and_lvals(Comp,
|
|
Rvals1, Rvals, Lvals1, Lvals).
|
|
|
|
% extract the rvals and lvals from the pragma_c_component
|
|
% and add them to the list.
|
|
:- pred pragma_c_component_get_rvals_and_lvals(pragma_c_component,
|
|
list(rval), list(rval), list(lval), list(lval)).
|
|
:- mode pragma_c_component_get_rvals_and_lvals(in, in, out, in, out) is det.
|
|
|
|
pragma_c_component_get_rvals_and_lvals(pragma_c_inputs(Inputs),
|
|
Rvals0, Rvals, Lvals, Lvals) :-
|
|
pragma_c_inputs_get_rvals(Inputs, Rvals1),
|
|
list__append(Rvals1, Rvals0, Rvals).
|
|
pragma_c_component_get_rvals_and_lvals(pragma_c_outputs(Outputs),
|
|
Rvals, Rvals, Lvals0, Lvals) :-
|
|
pragma_c_outputs_get_lvals(Outputs, Lvals1),
|
|
list__append(Lvals1, Lvals0, Lvals).
|
|
pragma_c_component_get_rvals_and_lvals(pragma_c_user_code(_, _),
|
|
Rvals, Rvals, Lvals, Lvals).
|
|
pragma_c_component_get_rvals_and_lvals(pragma_c_raw_code(_, _),
|
|
Rvals, Rvals, Lvals, Lvals).
|
|
pragma_c_component_get_rvals_and_lvals(pragma_c_fail_to(_),
|
|
Rvals, Rvals, Lvals, Lvals).
|
|
pragma_c_component_get_rvals_and_lvals(pragma_c_noop,
|
|
Rvals, Rvals, Lvals, Lvals).
|
|
|
|
% extract the rvals from the pragma_c_input
|
|
:- pred pragma_c_inputs_get_rvals(list(pragma_c_input), list(rval)).
|
|
:- mode pragma_c_inputs_get_rvals(in, out) is det.
|
|
|
|
pragma_c_inputs_get_rvals([], []).
|
|
pragma_c_inputs_get_rvals([I|Inputs], [R|Rvals]) :-
|
|
I = pragma_c_input(_Name, _Type, R, _),
|
|
pragma_c_inputs_get_rvals(Inputs, Rvals).
|
|
|
|
% extract the lvals from the pragma_c_output
|
|
:- pred pragma_c_outputs_get_lvals(list(pragma_c_output), list(lval)).
|
|
:- mode pragma_c_outputs_get_lvals(in, out) is det.
|
|
|
|
pragma_c_outputs_get_lvals([], []).
|
|
pragma_c_outputs_get_lvals([O|Outputs], [L|Lvals]) :-
|
|
O = pragma_c_output(L, _Type, _Name, _),
|
|
pragma_c_outputs_get_lvals(Outputs, Lvals).
|
|
|
|
% determine all the rvals and lvals referenced by a list of instructions
|
|
|
|
:- pred opt_util__instr_list_rvals_and_lvals(list(pair(instr, string)),
|
|
list(rval), list(lval)).
|
|
:- mode opt_util__instr_list_rvals_and_lvals(in, out, out) is det.
|
|
|
|
opt_util__instr_list_rvals_and_lvals([], [], []).
|
|
opt_util__instr_list_rvals_and_lvals([Instr - _|Instrs], Rvals, Lvals) :-
|
|
opt_util__instr_rvals_and_lvals(Instr, Rvals0, Lvals0),
|
|
opt_util__instr_list_rvals_and_lvals(Instrs, Rvals1, Lvals1),
|
|
list__append(Rvals0, Rvals1, Rvals),
|
|
list__append(Lvals0, Lvals1, Lvals).
|
|
|
|
opt_util__instr_list_labels([], [], []).
|
|
opt_util__instr_list_labels([Uinstr - _ | Instrs], Labels, CodeAddrs) :-
|
|
opt_util__instr_labels(Uinstr, Labels0, CodeAddrs0),
|
|
opt_util__instr_list_labels(Instrs, Labels1, CodeAddrs1),
|
|
list__append(Labels0, Labels1, Labels),
|
|
list__append(CodeAddrs0, CodeAddrs1, CodeAddrs).
|
|
|
|
opt_util__livevals_addr(label(Label), Result) :-
|
|
( Label = local(_, _) ->
|
|
Result = no
|
|
;
|
|
Result = yes
|
|
).
|
|
opt_util__livevals_addr(imported(_), yes).
|
|
opt_util__livevals_addr(succip, yes).
|
|
opt_util__livevals_addr(do_succeed(_), yes).
|
|
opt_util__livevals_addr(do_redo, no).
|
|
opt_util__livevals_addr(do_fail, no).
|
|
opt_util__livevals_addr(do_trace_redo_fail_shallow, no).
|
|
opt_util__livevals_addr(do_trace_redo_fail_deep, no).
|
|
opt_util__livevals_addr(do_call_closure, yes).
|
|
opt_util__livevals_addr(do_call_class_method, yes).
|
|
opt_util__livevals_addr(do_not_reached, no).
|
|
|
|
opt_util__count_temps_instr_list([], R, R, F, F).
|
|
opt_util__count_temps_instr_list([Uinstr - _Comment | Instrs], R0, R, F0, F) :-
|
|
opt_util__count_temps_instr(Uinstr, R0, R1, F0, F1),
|
|
opt_util__count_temps_instr_list(Instrs, R1, R, F1, F).
|
|
|
|
opt_util__count_temps_instr(comment(_), R, R, F, F).
|
|
opt_util__count_temps_instr(livevals(_), R, R, F, F).
|
|
opt_util__count_temps_instr(block(_, _, _), R, R, F, F).
|
|
opt_util__count_temps_instr(assign(Lval, Rval), R0, R, F0, F) :-
|
|
opt_util__count_temps_lval(Lval, R0, R1, F0, F1),
|
|
opt_util__count_temps_rval(Rval, R1, R, F1, F).
|
|
opt_util__count_temps_instr(call(_, _, _, _, _, _), R, R, F, F).
|
|
opt_util__count_temps_instr(mkframe(_, _), R, R, F, F).
|
|
opt_util__count_temps_instr(label(_), R, R, F, F).
|
|
opt_util__count_temps_instr(goto(_), R, R, F, F).
|
|
opt_util__count_temps_instr(computed_goto(Rval, _), R0, R, F0, F) :-
|
|
opt_util__count_temps_rval(Rval, R0, R, F0, F).
|
|
opt_util__count_temps_instr(if_val(Rval, _), R0, R, F0, F) :-
|
|
opt_util__count_temps_rval(Rval, R0, R, F0, F).
|
|
opt_util__count_temps_instr(c_code(_, _), R, R, F, F).
|
|
opt_util__count_temps_instr(incr_hp(Lval, _, _, Rval, _), R0, R, F0, F) :-
|
|
opt_util__count_temps_lval(Lval, R0, R1, F0, F1),
|
|
opt_util__count_temps_rval(Rval, R1, R, F1, F).
|
|
opt_util__count_temps_instr(mark_hp(Lval), R0, R, F0, F) :-
|
|
opt_util__count_temps_lval(Lval, R0, R, F0, F).
|
|
opt_util__count_temps_instr(restore_hp(Rval), R0, R, F0, F) :-
|
|
opt_util__count_temps_rval(Rval, R0, R, F0, F).
|
|
opt_util__count_temps_instr(free_heap(Rval), R0, R, F0, F) :-
|
|
opt_util__count_temps_rval(Rval, R0, R, F0, F).
|
|
opt_util__count_temps_instr(store_ticket(Lval), R0, R, F0, F) :-
|
|
opt_util__count_temps_lval(Lval, R0, R, F0, F).
|
|
opt_util__count_temps_instr(reset_ticket(Rval, _Reason), R0, R, F0, F) :-
|
|
opt_util__count_temps_rval(Rval, R0, R, F0, F).
|
|
opt_util__count_temps_instr(discard_ticket, R, R, F, F).
|
|
opt_util__count_temps_instr(prune_ticket, R, R, F, F).
|
|
opt_util__count_temps_instr(mark_ticket_stack(Lval), R0, R, F0, F) :-
|
|
opt_util__count_temps_lval(Lval, R0, R, F0, F).
|
|
opt_util__count_temps_instr(prune_tickets_to(Rval), R0, R, F0, F) :-
|
|
opt_util__count_temps_rval(Rval, R0, R, F0, F).
|
|
opt_util__count_temps_instr(incr_sp(_, _), R, R, F, F).
|
|
opt_util__count_temps_instr(decr_sp(_), R, R, F, F).
|
|
opt_util__count_temps_instr(init_sync_term(Lval, _), R0, R, F0, F) :-
|
|
opt_util__count_temps_lval(Lval, R0, R, F0, F).
|
|
opt_util__count_temps_instr(fork(_, _, _), R, R, F, F).
|
|
opt_util__count_temps_instr(join_and_terminate(Lval), R0, R, F0, F) :-
|
|
opt_util__count_temps_lval(Lval, R0, R, F0, F).
|
|
opt_util__count_temps_instr(join_and_continue(Lval, _), R0, R, F0, F) :-
|
|
opt_util__count_temps_lval(Lval, R0, R, F0, F).
|
|
opt_util__count_temps_instr(pragma_c(_, _, _, _, _, _, _, _), R, R, F, F).
|
|
|
|
:- pred opt_util__count_temps_lval(lval, int, int, int, int).
|
|
:- mode opt_util__count_temps_lval(in, in, out, in, out) is det.
|
|
|
|
opt_util__count_temps_lval(Lval, R0, R, F0, F) :-
|
|
( Lval = temp(Type, N) ->
|
|
(
|
|
Type = r,
|
|
int__max(R0, N, R),
|
|
F = F0
|
|
;
|
|
Type = f,
|
|
int__max(F0, N, F),
|
|
R = R0
|
|
)
|
|
; Lval = field(_, Rval, FieldNum) ->
|
|
opt_util__count_temps_rval(Rval, R0, R1, F0, F1),
|
|
opt_util__count_temps_rval(FieldNum, R1, R, F1, F)
|
|
;
|
|
R = R0,
|
|
F = F0
|
|
).
|
|
|
|
:- pred opt_util__count_temps_rval(rval, int, int, int, int).
|
|
:- mode opt_util__count_temps_rval(in, in, out, in, out) is det.
|
|
|
|
% XXX assume that we don't generate code
|
|
% that uses a temp var without defining it.
|
|
opt_util__count_temps_rval(_, R, R, F, F).
|
|
|
|
opt_util__format_label(local(_, ProcLabel), Str) :-
|
|
opt_util__format_proclabel(ProcLabel, Str).
|
|
opt_util__format_label(c_local(ProcLabel), Str) :-
|
|
opt_util__format_proclabel(ProcLabel, Str).
|
|
opt_util__format_label(local(ProcLabel), Str) :-
|
|
opt_util__format_proclabel(ProcLabel, Str).
|
|
opt_util__format_label(exported(ProcLabel), Str) :-
|
|
opt_util__format_proclabel(ProcLabel, Str).
|
|
|
|
:- pred opt_util__format_proclabel(proc_label, string).
|
|
:- mode opt_util__format_proclabel(in, out) is det.
|
|
|
|
opt_util__format_proclabel(proc(_Module, _PredOrFunc, _, Name, Arity, ProcId),
|
|
Str) :-
|
|
string__int_to_string(Arity, ArityStr),
|
|
proc_id_to_int(ProcId, Mode),
|
|
string__int_to_string(Mode, ModeStr),
|
|
string__append_list([Name, "/", ArityStr, " mode ", ModeStr], Str).
|
|
opt_util__format_proclabel(special_proc(_Module, SpecialPredId, TypeModule,
|
|
TypeName, TypeArity, ProcId), Str) :-
|
|
string__int_to_string(TypeArity, TypeArityStr),
|
|
proc_id_to_int(ProcId, Mode),
|
|
string__int_to_string(Mode, ModeStr),
|
|
TypeCtor = qualified(TypeModule, TypeName) - TypeArity,
|
|
PredName = special_pred_name(SpecialPredId, TypeCtor),
|
|
string__append_list([PredName, "_", TypeName, "/", TypeArityStr,
|
|
" mode ", ModeStr], Str).
|
|
|
|
opt_util__has_both_incr_decr_sp(Instrs) :-
|
|
opt_util__has_both_incr_decr_sp_2(Instrs, no, yes, no, yes).
|
|
|
|
:- pred opt_util__has_both_incr_decr_sp_2(list(instruction),
|
|
bool, bool, bool, bool).
|
|
:- mode opt_util__has_both_incr_decr_sp_2(in, in, out, in, out) is det.
|
|
|
|
opt_util__has_both_incr_decr_sp_2([], HasIncr, HasIncr, HasDecr, HasDecr).
|
|
opt_util__has_both_incr_decr_sp_2([Uinstr - _ | Instrs],
|
|
HasIncr0, HasIncr, HasDecr0, HasDecr) :-
|
|
( Uinstr = incr_sp(_, _) ->
|
|
HasIncr1 = yes
|
|
;
|
|
HasIncr1 = HasIncr0
|
|
),
|
|
( Uinstr = decr_sp(_) ->
|
|
HasDecr1 = yes
|
|
;
|
|
HasDecr1 = HasDecr0
|
|
),
|
|
opt_util__has_both_incr_decr_sp_2(Instrs,
|
|
HasIncr1, HasIncr, HasDecr1, HasDecr).
|
|
|
|
opt_util__touches_nondet_ctrl([], no).
|
|
opt_util__touches_nondet_ctrl([Uinstr - _ | Instrs], Touch) :-
|
|
opt_util__touches_nondet_ctrl_instr(Uinstr, Touch0),
|
|
(
|
|
Touch0 = yes,
|
|
Touch = yes
|
|
;
|
|
Touch0 = no,
|
|
opt_util__touches_nondet_ctrl(Instrs, Touch)
|
|
).
|
|
|
|
:- pred opt_util__touches_nondet_ctrl_instr(instr, bool).
|
|
:- mode opt_util__touches_nondet_ctrl_instr(in, out) is det.
|
|
|
|
opt_util__touches_nondet_ctrl_instr(Uinstr, Touch) :-
|
|
( Uinstr = assign(Lval, Rval) ->
|
|
opt_util__touches_nondet_ctrl_lval(Lval, TouchLval),
|
|
opt_util__touches_nondet_ctrl_rval(Rval, TouchRval),
|
|
bool__or(TouchLval, TouchRval, Touch)
|
|
; Uinstr = incr_hp(Lval, _, _, Rval, _) ->
|
|
opt_util__touches_nondet_ctrl_lval(Lval, TouchLval),
|
|
opt_util__touches_nondet_ctrl_rval(Rval, TouchRval),
|
|
bool__or(TouchLval, TouchRval, Touch)
|
|
; Uinstr = mark_hp(Lval) ->
|
|
opt_util__touches_nondet_ctrl_lval(Lval, Touch)
|
|
; Uinstr = restore_hp(Rval) ->
|
|
opt_util__touches_nondet_ctrl_rval(Rval, Touch)
|
|
; Uinstr = pragma_c(_, Components, _, _, _, _, _, _) ->
|
|
opt_util__touches_nondet_ctrl_components(Components, Touch)
|
|
;
|
|
Touch = yes
|
|
).
|
|
|
|
:- pred opt_util__touches_nondet_ctrl_lval(lval, bool).
|
|
:- mode opt_util__touches_nondet_ctrl_lval(in, out) is det.
|
|
|
|
opt_util__touches_nondet_ctrl_lval(reg(_, _), no).
|
|
opt_util__touches_nondet_ctrl_lval(stackvar(_), no).
|
|
opt_util__touches_nondet_ctrl_lval(framevar(_), no).
|
|
opt_util__touches_nondet_ctrl_lval(succip, no).
|
|
opt_util__touches_nondet_ctrl_lval(maxfr, yes).
|
|
opt_util__touches_nondet_ctrl_lval(curfr, yes).
|
|
opt_util__touches_nondet_ctrl_lval(succfr(_), yes).
|
|
opt_util__touches_nondet_ctrl_lval(prevfr(_), yes).
|
|
opt_util__touches_nondet_ctrl_lval(redofr(_), yes).
|
|
opt_util__touches_nondet_ctrl_lval(redoip(_), yes).
|
|
opt_util__touches_nondet_ctrl_lval(succip(_), yes).
|
|
opt_util__touches_nondet_ctrl_lval(hp, no).
|
|
opt_util__touches_nondet_ctrl_lval(sp, no).
|
|
opt_util__touches_nondet_ctrl_lval(field(_, Rval1, Rval2), Touch) :-
|
|
opt_util__touches_nondet_ctrl_rval(Rval1, Touch1),
|
|
opt_util__touches_nondet_ctrl_rval(Rval2, Touch2),
|
|
bool__or(Touch1, Touch2, Touch).
|
|
opt_util__touches_nondet_ctrl_lval(lvar(_), no).
|
|
opt_util__touches_nondet_ctrl_lval(temp(_, _), no).
|
|
opt_util__touches_nondet_ctrl_lval(mem_ref(Rval), Touch) :-
|
|
opt_util__touches_nondet_ctrl_rval(Rval, Touch).
|
|
|
|
:- pred opt_util__touches_nondet_ctrl_rval(rval, bool).
|
|
:- mode opt_util__touches_nondet_ctrl_rval(in, out) is det.
|
|
|
|
opt_util__touches_nondet_ctrl_rval(lval(Lval), Touch) :-
|
|
opt_util__touches_nondet_ctrl_lval(Lval, Touch).
|
|
opt_util__touches_nondet_ctrl_rval(var(_), no).
|
|
opt_util__touches_nondet_ctrl_rval(mkword(_, Rval), Touch) :-
|
|
opt_util__touches_nondet_ctrl_rval(Rval, Touch).
|
|
opt_util__touches_nondet_ctrl_rval(const(_), no).
|
|
opt_util__touches_nondet_ctrl_rval(unop(_, Rval), Touch) :-
|
|
opt_util__touches_nondet_ctrl_rval(Rval, Touch).
|
|
opt_util__touches_nondet_ctrl_rval(binop(_, Rval1, Rval2), Touch) :-
|
|
opt_util__touches_nondet_ctrl_rval(Rval1, Touch1),
|
|
opt_util__touches_nondet_ctrl_rval(Rval2, Touch2),
|
|
bool__or(Touch1, Touch2, Touch).
|
|
opt_util__touches_nondet_ctrl_rval(mem_addr(MemRef), Touch) :-
|
|
opt_util__touches_nondet_ctrl_mem_ref(MemRef, Touch).
|
|
|
|
:- pred opt_util__touches_nondet_ctrl_mem_ref(mem_ref, bool).
|
|
:- mode opt_util__touches_nondet_ctrl_mem_ref(in, out) is det.
|
|
|
|
opt_util__touches_nondet_ctrl_mem_ref(stackvar_ref(_), no).
|
|
opt_util__touches_nondet_ctrl_mem_ref(framevar_ref(_), no).
|
|
opt_util__touches_nondet_ctrl_mem_ref(heap_ref(Rval, _, _), Touch) :-
|
|
opt_util__touches_nondet_ctrl_rval(Rval, Touch).
|
|
|
|
:- pred opt_util__touches_nondet_ctrl_components(list(pragma_c_component),
|
|
bool).
|
|
:- mode opt_util__touches_nondet_ctrl_components(in, out) is det.
|
|
|
|
opt_util__touches_nondet_ctrl_components([], no).
|
|
opt_util__touches_nondet_ctrl_components([C | Cs], Touch) :-
|
|
opt_util__touches_nondet_ctrl_component(C, Touch1),
|
|
opt_util__touches_nondet_ctrl_components(Cs, Touch2),
|
|
bool__or(Touch1, Touch2, Touch).
|
|
|
|
:- pred opt_util__touches_nondet_ctrl_component(pragma_c_component, bool).
|
|
:- mode opt_util__touches_nondet_ctrl_component(in, out) is det.
|
|
|
|
% The inputs and outputs components get emitted as simple
|
|
% straight-line code that do not refer to control slots.
|
|
% The compiler does not generate raw_code that refers to control slots.
|
|
% User code shouldn't either, but until we have prohibited the
|
|
% use of ordinary pragma C codes for model_non procedures,
|
|
% some user code will need to ignore this restriction.
|
|
|
|
opt_util__touches_nondet_ctrl_component(pragma_c_inputs(_), no).
|
|
opt_util__touches_nondet_ctrl_component(pragma_c_outputs(_), no).
|
|
opt_util__touches_nondet_ctrl_component(pragma_c_raw_code(_, _), no).
|
|
opt_util__touches_nondet_ctrl_component(pragma_c_user_code(_, _), yes).
|
|
opt_util__touches_nondet_ctrl_component(pragma_c_fail_to(_), no).
|
|
opt_util__touches_nondet_ctrl_component(pragma_c_noop, no).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
opt_util__lval_access_rvals(reg(_, _), []).
|
|
opt_util__lval_access_rvals(stackvar(_), []).
|
|
opt_util__lval_access_rvals(framevar(_), []).
|
|
opt_util__lval_access_rvals(succip, []).
|
|
opt_util__lval_access_rvals(maxfr, []).
|
|
opt_util__lval_access_rvals(curfr, []).
|
|
opt_util__lval_access_rvals(redoip(Rval), [Rval]).
|
|
opt_util__lval_access_rvals(succip(Rval), [Rval]).
|
|
opt_util__lval_access_rvals(redofr(Rval), [Rval]).
|
|
opt_util__lval_access_rvals(prevfr(Rval), [Rval]).
|
|
opt_util__lval_access_rvals(succfr(Rval), [Rval]).
|
|
opt_util__lval_access_rvals(hp, []).
|
|
opt_util__lval_access_rvals(sp, []).
|
|
opt_util__lval_access_rvals(field(_, Rval1, Rval2), [Rval1, Rval2]).
|
|
opt_util__lval_access_rvals(temp(_, _), []).
|
|
opt_util__lval_access_rvals(lvar(_), _) :-
|
|
error("lvar detected in opt_util__lval_access_rvals").
|
|
opt_util__lval_access_rvals(mem_ref(Rval), [Rval]).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
opt_util__rvals_free_of_lval([], _).
|
|
opt_util__rvals_free_of_lval([Rval | Rvals], Forbidden) :-
|
|
opt_util__rval_free_of_lval(Rval, Forbidden),
|
|
opt_util__rvals_free_of_lval(Rvals, Forbidden).
|
|
|
|
opt_util__rval_free_of_lval(lval(Lval), Forbidden) :-
|
|
Lval \= Forbidden,
|
|
opt_util__lval_access_rvals(Lval, Rvals),
|
|
opt_util__rvals_free_of_lval(Rvals, Forbidden).
|
|
opt_util__rval_free_of_lval(var(_), _) :-
|
|
error("found var in opt_util__rval_free_of_lval").
|
|
opt_util__rval_free_of_lval(mkword(_, Rval), Forbidden) :-
|
|
opt_util__rval_free_of_lval(Rval, Forbidden).
|
|
opt_util__rval_free_of_lval(const(_), _).
|
|
opt_util__rval_free_of_lval(unop(_, Rval), Forbidden) :-
|
|
opt_util__rval_free_of_lval(Rval, Forbidden).
|
|
opt_util__rval_free_of_lval(binop(_, Rval1, Rval2), Forbidden) :-
|
|
opt_util__rval_free_of_lval(Rval1, Forbidden),
|
|
opt_util__rval_free_of_lval(Rval2, Forbidden).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
opt_util__count_incr_hp(Instrs, N) :-
|
|
opt_util__count_incr_hp_2(Instrs, 0, N).
|
|
|
|
:- pred opt_util__count_incr_hp_2(list(instruction), int, int).
|
|
:- mode opt_util__count_incr_hp_2(in, in, out) is det.
|
|
|
|
opt_util__count_incr_hp_2([], N, N).
|
|
opt_util__count_incr_hp_2([Uinstr0 - _ | Instrs], N0, N) :-
|
|
( Uinstr0 = incr_hp(_, _, _, _, _) ->
|
|
N1 = N0 + 1
|
|
;
|
|
N1 = N0
|
|
),
|
|
opt_util__count_incr_hp_2(Instrs, N1, N).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
opt_util__propagate_livevals(Instrs0, Instrs) :-
|
|
list__reverse(Instrs0, RevInstrs0),
|
|
set__init(Livevals),
|
|
opt_util__propagate_livevals_2(RevInstrs0, Livevals, RevInstrs),
|
|
list__reverse(RevInstrs, Instrs).
|
|
|
|
:- pred opt_util__propagate_livevals_2(list(instruction), set(lval),
|
|
list(instruction)).
|
|
:- mode opt_util__propagate_livevals_2(in, in, out) is det.
|
|
|
|
opt_util__propagate_livevals_2([], _, []).
|
|
opt_util__propagate_livevals_2([Instr0 | Instrs0], Livevals0,
|
|
[Instr | Instrs]) :-
|
|
Instr0 = Uinstr0 - Comment,
|
|
( Uinstr0 = livevals(ThisLivevals) ->
|
|
set__union(Livevals0, ThisLivevals, Livevals),
|
|
Instr = livevals(Livevals) - Comment
|
|
;
|
|
Instr = Instr0,
|
|
( Uinstr0 = assign(Lval, _) ->
|
|
set__delete(Livevals0, Lval, Livevals)
|
|
; opt_util__can_instr_fall_through(Uinstr0, no) ->
|
|
set__init(Livevals)
|
|
;
|
|
Livevals = Livevals0
|
|
)
|
|
),
|
|
opt_util__propagate_livevals_2(Instrs0, Livevals, Instrs).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% The code in this section is concerned with replacing all references
|
|
% to one given label with a reference to another given label.
|
|
|
|
opt_util__replace_labels_instruction_list([], _, _, []).
|
|
opt_util__replace_labels_instruction_list([Instr0 | Instrs0], ReplMap,
|
|
ReplData, [Instr | Instrs]) :-
|
|
opt_util__replace_labels_instruction(Instr0, ReplMap, ReplData, Instr),
|
|
opt_util__replace_labels_instruction_list(Instrs0, ReplMap, ReplData,
|
|
Instrs).
|
|
|
|
opt_util__replace_labels_instruction(Instr0 - Comment, ReplMap, ReplData,
|
|
Instr - Comment) :-
|
|
opt_util__replace_labels_instr(Instr0, ReplMap, ReplData, Instr).
|
|
|
|
opt_util__replace_labels_instr(comment(Comment), _, _, comment(Comment)).
|
|
opt_util__replace_labels_instr(livevals(Livevals), _, _, livevals(Livevals)).
|
|
opt_util__replace_labels_instr(block(R, F, Instrs0), ReplMap, ReplData,
|
|
block(R, F, Instrs)) :-
|
|
opt_util__replace_labels_instruction_list(Instrs0, ReplMap, ReplData,
|
|
Instrs).
|
|
opt_util__replace_labels_instr(assign(Lval0, Rval0), ReplMap, ReplData,
|
|
assign(Lval, Rval)) :-
|
|
(
|
|
ReplData = yes,
|
|
opt_util__replace_labels_lval(Lval0, ReplMap, Lval),
|
|
opt_util__replace_labels_rval(Rval0, ReplMap, Rval)
|
|
;
|
|
ReplData = no,
|
|
Lval = Lval0,
|
|
Rval = Rval0
|
|
).
|
|
opt_util__replace_labels_instr(call(Target, Return0, LiveInfo, CXT, GP, CM),
|
|
ReplMap, _, call(Target, Return, LiveInfo, CXT, GP, CM)) :-
|
|
opt_util__replace_labels_code_addr(Return0, ReplMap, Return).
|
|
opt_util__replace_labels_instr(mkframe(NondetFrameInfo, Redoip0), ReplMap,
|
|
ReplData, mkframe(NondetFrameInfo, Redoip)) :-
|
|
(
|
|
ReplData = yes,
|
|
opt_util__replace_labels_code_addr(Redoip0, ReplMap, Redoip)
|
|
;
|
|
ReplData = no,
|
|
Redoip = Redoip0
|
|
).
|
|
opt_util__replace_labels_instr(label(Label), ReplMap, _, label(Label)) :-
|
|
( map__search(ReplMap, Label, _) ->
|
|
% The reason why we are replacing references to this label
|
|
% is that it is being eliminated, and in fact should have been
|
|
% already eliminated by the time opt_util__replace_labels_instr
|
|
% is called.
|
|
error("eliminated label in opt_util__replace_labels_instr")
|
|
;
|
|
true
|
|
).
|
|
opt_util__replace_labels_instr(goto(Target0), ReplMap, _, goto(Target)) :-
|
|
opt_util__replace_labels_code_addr(Target0, ReplMap, Target).
|
|
opt_util__replace_labels_instr(computed_goto(Rval0, Labels0), ReplMap,
|
|
ReplData, computed_goto(Rval, Labels)) :-
|
|
(
|
|
ReplData = yes,
|
|
opt_util__replace_labels_rval(Rval0, ReplMap, Rval)
|
|
;
|
|
ReplData = no,
|
|
Rval = Rval0
|
|
),
|
|
opt_util__replace_labels_label_list(Labels0, ReplMap, Labels).
|
|
opt_util__replace_labels_instr(c_code(Code, Lvals), _, _, c_code(Code, Lvals)).
|
|
opt_util__replace_labels_instr(if_val(Rval0, Target0), ReplMap, ReplData,
|
|
if_val(Rval, Target)) :-
|
|
(
|
|
ReplData = yes,
|
|
opt_util__replace_labels_rval(Rval0, ReplMap, Rval)
|
|
;
|
|
ReplData = no,
|
|
Rval = Rval0
|
|
),
|
|
opt_util__replace_labels_code_addr(Target0, ReplMap, Target).
|
|
opt_util__replace_labels_instr(incr_hp(Lval0, MaybeTag, MO, Rval0, Msg),
|
|
ReplMap, ReplData, incr_hp(Lval, MaybeTag, MO, Rval, Msg)) :-
|
|
(
|
|
ReplData = yes,
|
|
opt_util__replace_labels_lval(Lval0, ReplMap, Lval),
|
|
opt_util__replace_labels_rval(Rval0, ReplMap, Rval)
|
|
;
|
|
ReplData = no,
|
|
Lval = Lval0,
|
|
Rval = Rval0
|
|
).
|
|
opt_util__replace_labels_instr(mark_hp(Lval0), ReplMap, ReplData,
|
|
mark_hp(Lval)) :-
|
|
(
|
|
ReplData = yes,
|
|
opt_util__replace_labels_lval(Lval0, ReplMap, Lval)
|
|
;
|
|
ReplData = no,
|
|
Lval = Lval0
|
|
).
|
|
opt_util__replace_labels_instr(restore_hp(Rval0), ReplMap, ReplData,
|
|
restore_hp(Rval)) :-
|
|
(
|
|
ReplData = yes,
|
|
opt_util__replace_labels_rval(Rval0, ReplMap, Rval)
|
|
;
|
|
ReplData = no,
|
|
Rval = Rval0
|
|
).
|
|
opt_util__replace_labels_instr(free_heap(Rval0), ReplMap, ReplData,
|
|
free_heap(Rval)) :-
|
|
(
|
|
ReplData = yes,
|
|
opt_util__replace_labels_rval(Rval0, ReplMap, Rval)
|
|
;
|
|
ReplData = no,
|
|
Rval = Rval0
|
|
).
|
|
opt_util__replace_labels_instr(store_ticket(Lval0), ReplMap, ReplData,
|
|
store_ticket(Lval)) :-
|
|
(
|
|
ReplData = yes,
|
|
opt_util__replace_labels_lval(Lval0, ReplMap, Lval)
|
|
;
|
|
ReplData = no,
|
|
Lval = Lval0
|
|
).
|
|
opt_util__replace_labels_instr(reset_ticket(Rval0, Reason), ReplMap, ReplData,
|
|
reset_ticket(Rval, Reason)) :-
|
|
(
|
|
ReplData = yes,
|
|
opt_util__replace_labels_rval(Rval0, ReplMap, Rval)
|
|
;
|
|
ReplData = no,
|
|
Rval = Rval0
|
|
).
|
|
opt_util__replace_labels_instr(discard_ticket, _, _, discard_ticket).
|
|
opt_util__replace_labels_instr(prune_ticket, _, _, prune_ticket).
|
|
opt_util__replace_labels_instr(mark_ticket_stack(Lval0), ReplMap, ReplData,
|
|
mark_ticket_stack(Lval)) :-
|
|
(
|
|
ReplData = yes,
|
|
opt_util__replace_labels_lval(Lval0, ReplMap, Lval)
|
|
;
|
|
ReplData = no,
|
|
Lval = Lval0
|
|
).
|
|
opt_util__replace_labels_instr(prune_tickets_to(Rval0), ReplMap, ReplData,
|
|
prune_tickets_to(Rval)) :-
|
|
(
|
|
ReplData = yes,
|
|
opt_util__replace_labels_rval(Rval0, ReplMap, Rval)
|
|
;
|
|
ReplData = no,
|
|
Rval = Rval0
|
|
).
|
|
opt_util__replace_labels_instr(incr_sp(Size, Msg), _, _, incr_sp(Size, Msg)).
|
|
opt_util__replace_labels_instr(decr_sp(Size), _, _, decr_sp(Size)).
|
|
opt_util__replace_labels_instr(init_sync_term(T, N), _, _,
|
|
init_sync_term(T, N)).
|
|
opt_util__replace_labels_instr(fork(Child0, Parent0, SlotCount), Replmap, _,
|
|
fork(Child, Parent, SlotCount)) :-
|
|
opt_util__replace_labels_label(Child0, Replmap, Child),
|
|
opt_util__replace_labels_label(Parent0, Replmap, Parent).
|
|
opt_util__replace_labels_instr(join_and_terminate(Lval0), Replmap, _,
|
|
join_and_terminate(Lval)) :-
|
|
opt_util__replace_labels_lval(Lval0, Replmap, Lval).
|
|
opt_util__replace_labels_instr(join_and_continue(Lval0, Label0),
|
|
Replmap, _, join_and_continue(Lval, Label)) :-
|
|
opt_util__replace_labels_label(Label0, Replmap, Label),
|
|
opt_util__replace_labels_lval(Lval0, Replmap, Lval).
|
|
opt_util__replace_labels_instr(pragma_c(A, Comps0, C, MaybeFix, MaybeLayout,
|
|
MaybeOnlyLayout, MaybeSub0, F), ReplMap, _,
|
|
pragma_c(A, Comps, C, MaybeFix, MaybeLayout, MaybeOnlyLayout,
|
|
MaybeSub, F)) :-
|
|
(
|
|
MaybeFix = no
|
|
;
|
|
MaybeFix = yes(FixLabel0),
|
|
opt_util__replace_labels_label(FixLabel0, ReplMap, FixLabel),
|
|
% We cannot replace the label in the C code string
|
|
% itself.
|
|
require(unify(FixLabel0, FixLabel),
|
|
"trying to replace Mercury label in C code")
|
|
),
|
|
(
|
|
MaybeLayout = no
|
|
;
|
|
MaybeLayout = yes(LayoutLabel0),
|
|
opt_util__replace_labels_label(LayoutLabel0, ReplMap,
|
|
LayoutLabel),
|
|
% We cannot replace the label that has a layout
|
|
% structure.
|
|
require(unify(LayoutLabel0, LayoutLabel),
|
|
"trying to replace Mercury label with layout")
|
|
),
|
|
(
|
|
MaybeOnlyLayout = no
|
|
;
|
|
MaybeOnlyLayout = yes(OnlyLayoutLabel0),
|
|
opt_util__replace_labels_label(OnlyLayoutLabel0, ReplMap,
|
|
OnlyLayoutLabel),
|
|
% We cannot replace the label that has a layout
|
|
% structure.
|
|
require(unify(OnlyLayoutLabel0, OnlyLayoutLabel),
|
|
"trying to replace Mercury label with layout")
|
|
),
|
|
(
|
|
MaybeSub0 = no,
|
|
MaybeSub = no,
|
|
Comps = Comps0
|
|
;
|
|
MaybeSub0 = yes(SubLabel0),
|
|
opt_util__replace_labels_label(SubLabel0, ReplMap, SubLabel),
|
|
MaybeSub = yes(SubLabel),
|
|
opt_util__replace_labels_comps(Comps0, ReplMap, Comps)
|
|
).
|
|
|
|
:- pred opt_util__replace_labels_comps(list(pragma_c_component),
|
|
map(label, label), list(pragma_c_component)).
|
|
:- mode opt_util__replace_labels_comps(in, in, out) is det.
|
|
|
|
opt_util__replace_labels_comps([], _, []).
|
|
opt_util__replace_labels_comps([Comp0 | Comps0], ReplMap, [Comp | Comps]) :-
|
|
opt_util__replace_labels_comp(Comp0, ReplMap, Comp),
|
|
opt_util__replace_labels_comps(Comps0, ReplMap, Comps).
|
|
|
|
:- pred opt_util__replace_labels_comp(pragma_c_component,
|
|
map(label, label), pragma_c_component).
|
|
:- mode opt_util__replace_labels_comp(in, in, out) is det.
|
|
|
|
opt_util__replace_labels_comp(pragma_c_inputs(A), _, pragma_c_inputs(A)).
|
|
opt_util__replace_labels_comp(pragma_c_outputs(A), _, pragma_c_outputs(A)).
|
|
opt_util__replace_labels_comp(pragma_c_user_code(A, B), _,
|
|
pragma_c_user_code(A, B)).
|
|
opt_util__replace_labels_comp(pragma_c_raw_code(A, B), _,
|
|
pragma_c_raw_code(A, B)).
|
|
opt_util__replace_labels_comp(pragma_c_fail_to(Label0), ReplMap,
|
|
pragma_c_fail_to(Label)) :-
|
|
opt_util__replace_labels_label(Label0, ReplMap, Label).
|
|
opt_util__replace_labels_comp(pragma_c_noop, _, pragma_c_noop).
|
|
|
|
:- pred opt_util__replace_labels_lval(lval, map(label, label), lval).
|
|
:- mode opt_util__replace_labels_lval(in, in, out) is det.
|
|
|
|
opt_util__replace_labels_lval(reg(RegType, RegNum), _, reg(RegType, RegNum)).
|
|
opt_util__replace_labels_lval(stackvar(N), _, stackvar(N)).
|
|
opt_util__replace_labels_lval(framevar(N), _, framevar(N)).
|
|
opt_util__replace_labels_lval(succip, _, succip).
|
|
opt_util__replace_labels_lval(maxfr, _, maxfr).
|
|
opt_util__replace_labels_lval(curfr, _, curfr).
|
|
opt_util__replace_labels_lval(succip(Rval0), ReplMap, succip(Rval)) :-
|
|
opt_util__replace_labels_rval(Rval0, ReplMap, Rval).
|
|
opt_util__replace_labels_lval(redoip(Rval0), ReplMap, redoip(Rval)) :-
|
|
opt_util__replace_labels_rval(Rval0, ReplMap, Rval).
|
|
opt_util__replace_labels_lval(redofr(Rval0), ReplMap, redofr(Rval)) :-
|
|
opt_util__replace_labels_rval(Rval0, ReplMap, Rval).
|
|
opt_util__replace_labels_lval(succfr(Rval0), ReplMap, succfr(Rval)) :-
|
|
opt_util__replace_labels_rval(Rval0, ReplMap, Rval).
|
|
opt_util__replace_labels_lval(prevfr(Rval0), ReplMap, prevfr(Rval)) :-
|
|
opt_util__replace_labels_rval(Rval0, ReplMap, Rval).
|
|
opt_util__replace_labels_lval(hp, _, hp).
|
|
opt_util__replace_labels_lval(sp, _, sp).
|
|
opt_util__replace_labels_lval(field(Tag, Base0, Offset0), ReplMap,
|
|
field(Tag, Base, Offset)) :-
|
|
opt_util__replace_labels_rval(Base0, ReplMap, Base),
|
|
opt_util__replace_labels_rval(Offset0, ReplMap, Offset).
|
|
opt_util__replace_labels_lval(lvar(Var), _, lvar(Var)).
|
|
opt_util__replace_labels_lval(temp(Type, Num), _, temp(Type, Num)).
|
|
opt_util__replace_labels_lval(mem_ref(Rval0), ReplMap, mem_ref(Rval)) :-
|
|
opt_util__replace_labels_rval(Rval0, ReplMap, Rval).
|
|
|
|
:- pred opt_util__replace_labels_rval(rval::in, map(label, label)::in,
|
|
rval::out) is det.
|
|
|
|
opt_util__replace_labels_rval(lval(Lval0), ReplMap, lval(Lval)) :-
|
|
opt_util__replace_labels_lval(Lval0, ReplMap, Lval).
|
|
opt_util__replace_labels_rval(var(Var), _, var(Var)).
|
|
opt_util__replace_labels_rval(mkword(Tag, Rval0), ReplMap,
|
|
mkword(Tag, Rval)) :-
|
|
opt_util__replace_labels_rval(Rval0, ReplMap, Rval).
|
|
opt_util__replace_labels_rval(const(Const0), ReplMap, const(Const)) :-
|
|
opt_util__replace_labels_rval_const(Const0, ReplMap, Const).
|
|
opt_util__replace_labels_rval(unop(Op, Rval0), ReplMap, unop(Op, Rval)) :-
|
|
opt_util__replace_labels_rval(Rval0, ReplMap, Rval).
|
|
opt_util__replace_labels_rval(binop(Op, LRval0, RRval0), ReplMap,
|
|
binop(Op, LRval, RRval)) :-
|
|
opt_util__replace_labels_rval(LRval0, ReplMap, LRval),
|
|
opt_util__replace_labels_rval(RRval0, ReplMap, RRval).
|
|
opt_util__replace_labels_rval(mem_addr(MemRef0), ReplMap, mem_addr(MemRef)) :-
|
|
opt_util__replace_labels_mem_ref(MemRef0, ReplMap, MemRef).
|
|
|
|
:- pred opt_util__replace_labels_mem_ref(mem_ref::in, map(label, label)::in,
|
|
mem_ref::out) is det.
|
|
|
|
opt_util__replace_labels_mem_ref(stackvar_ref(N), _, stackvar_ref(N)).
|
|
opt_util__replace_labels_mem_ref(framevar_ref(N), _, framevar_ref(N)).
|
|
opt_util__replace_labels_mem_ref(heap_ref(Rval0, Tag, N), ReplMap,
|
|
heap_ref(Rval, Tag, N)) :-
|
|
opt_util__replace_labels_rval(Rval0, ReplMap, Rval).
|
|
|
|
:- pred opt_util__replace_labels_rval_const(rval_const::in,
|
|
map(label, label)::in, rval_const::out) is det.
|
|
|
|
opt_util__replace_labels_rval_const(true, _, true).
|
|
opt_util__replace_labels_rval_const(false, _, false).
|
|
opt_util__replace_labels_rval_const(int_const(N), _, int_const(N)).
|
|
opt_util__replace_labels_rval_const(float_const(N), _, float_const(N)).
|
|
opt_util__replace_labels_rval_const(string_const(S), _, string_const(S)).
|
|
opt_util__replace_labels_rval_const(multi_string_const(L, S), _,
|
|
multi_string_const(L, S)).
|
|
opt_util__replace_labels_rval_const(code_addr_const(Addr0), ReplMap,
|
|
code_addr_const(Addr)) :-
|
|
opt_util__replace_labels_code_addr(Addr0, ReplMap, Addr).
|
|
opt_util__replace_labels_rval_const(data_addr_const(DataAddr, MaybeOffset), _,
|
|
data_addr_const(DataAddr, MaybeOffset)).
|
|
opt_util__replace_labels_rval_const(label_entry(Label), _, label_entry(Label)).
|
|
|
|
:- pred opt_util__replace_labels_code_addr(code_addr::in, map(label, label)::in,
|
|
code_addr::out) is det.
|
|
|
|
opt_util__replace_labels_code_addr(label(Label0), ReplMap, label(Label)) :-
|
|
opt_util__replace_labels_label(Label0, ReplMap, Label).
|
|
opt_util__replace_labels_code_addr(imported(Proc), _, imported(Proc)).
|
|
opt_util__replace_labels_code_addr(succip, _, succip).
|
|
opt_util__replace_labels_code_addr(do_succeed(Last), _, do_succeed(Last)).
|
|
opt_util__replace_labels_code_addr(do_redo, _, do_redo).
|
|
opt_util__replace_labels_code_addr(do_fail, _, do_fail).
|
|
opt_util__replace_labels_code_addr(do_trace_redo_fail_shallow, _,
|
|
do_trace_redo_fail_shallow).
|
|
opt_util__replace_labels_code_addr(do_trace_redo_fail_deep, _,
|
|
do_trace_redo_fail_deep).
|
|
opt_util__replace_labels_code_addr(do_call_closure, _, do_call_closure).
|
|
opt_util__replace_labels_code_addr(do_call_class_method, _,
|
|
do_call_class_method).
|
|
opt_util__replace_labels_code_addr(do_not_reached, _, do_not_reached).
|
|
|
|
:- pred opt_util__replace_labels_label_list(list(label)::in,
|
|
map(label, label)::in, list(label)::out) is det.
|
|
|
|
opt_util__replace_labels_label_list([], _ReplMap, []).
|
|
opt_util__replace_labels_label_list([Label0 | Labels0], ReplMap,
|
|
[Label | Labels]) :-
|
|
opt_util__replace_labels_label(Label0, ReplMap, Label),
|
|
opt_util__replace_labels_label_list(Labels0, ReplMap, Labels).
|
|
|
|
:- pred opt_util__replace_labels_label(label::in, map(label, label)::in,
|
|
label::out) is det.
|
|
|
|
opt_util__replace_labels_label(Label0, ReplMap, Label) :-
|
|
( map__search(ReplMap, Label0, NewLabel) ->
|
|
Label = NewLabel
|
|
;
|
|
Label = Label0
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|