Files
mercury/compiler/labelopt.m
Zoltan Somogyi b96dacdcac Make a bunch of switches complete.
compiler/exception_analysis.m:
compiler/frameopt.m:
compiler/get_dependencies.m:
compiler/labelopt.m:
compiler/ml_global_data.m:
compiler/ml_optimize.m:
compiler/options_file.m:
compiler/parse_class.m:
compiler/rtti.m:
compiler/rtti_out.m:
compiler/type_util.m:
compiler/var_locn.m:
    As above.

compiler/inst_match.m:
    Fix a stray piece of code.

compiler/loop_inv.m:
    Add a module qualification.

compiler/opt_util.m:
    Delete two unused predicates.
2017-03-09 13:43:48 +11:00

191 lines
6.6 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
% Copyright (C) 1994-1999, 2003-2007, 2010-2012 The University of Melbourne.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%-----------------------------------------------------------------------------%
%
% File: labelopt.m.
% Author: zs.
%
% Module to eliminate useless labels and dead code.
%
%-----------------------------------------------------------------------------%
:- module ll_backend.labelopt.
:- interface.
:- import_module ll_backend.llds.
:- import_module bool.
:- import_module list.
:- import_module set_tree234.
%-----------------------------------------------------------------------------%
% Build up a set showing which labels are branched to, then traverse the
% instruction list removing unnecessary labels. If the instruction before
% the label branches away, we also remove the instruction block following
% the label.
%
:- pred labelopt_main(bool::in, set_tree234(label)::in,
list(instruction)::in, list(instruction)::out, bool::out) is det.
% Build up a set showing which labels are referred to. The input set is
% the list of labels referred to from outside the given list of
% instructions.
%
:- pred build_useset(list(instruction)::in,
set_tree234(label)::in, set_tree234(label)::out) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module ll_backend.opt_util.
:- import_module maybe.
%-----------------------------------------------------------------------------%
labelopt_main(Final, LayoutLabelSet, Instrs0, Instrs, Mod) :-
build_useset(Instrs0, LayoutLabelSet, Useset),
opt_labels_in_instr_list(Instrs0, Instrs1, Useset, Mod),
( if
Final = yes,
Mod = yes
then
labelopt_main(Final, LayoutLabelSet, Instrs1, Instrs, _)
else
Instrs = Instrs1
).
%-----------------------------------------------------------------------------%
build_useset([], !Useset).
build_useset([Instr | Instructions], !Useset) :-
Instr = llds_instr(Uinstr, _Comment),
opt_util.instr_labels_only(Uinstr, Labels),
set_tree234.insert_list(Labels, !Useset),
build_useset(Instructions, !Useset).
%-----------------------------------------------------------------------------%
% Go through the given instruction sequence. When we find a label,
% we check whether the label can be branched to either from within
% the procedure or from the outside. If yes, we leave it alone. If not,
% we delete it. We delete the following code as well if the label was
% preceded by code that cannot fall through.
%
% We build up the generated instruction list in reverse order in
% opt_labels_in_instr_list_2, because building it in right order here
% would make opt_labels_in_instr_list not tail recursive, and thus unable
% to handle very long instruction lists.
%
:- pred opt_labels_in_instr_list(list(instruction)::in, list(instruction)::out,
set_tree234(label)::in, bool::out) is det.
opt_labels_in_instr_list(Instrs0, Instrs, Useset, Mod) :-
Fallthrough = yes,
opt_labels_in_instr_list_2(Instrs0, [], RevInstrs, no, Mod, Fallthrough,
Useset),
list.reverse(RevInstrs, Instrs).
:- pred opt_labels_in_instr_list_2(list(instruction)::in,
list(instruction)::in, list(instruction)::out,
bool::in, bool::out, bool::in, set_tree234(label)::in) is det.
opt_labels_in_instr_list_2([], !RevInstrs, !Mod, _Fallthrough, _Useset).
opt_labels_in_instr_list_2([Instr0 | Instrs0], !RevInstrs, !Mod,
!.Fallthrough, Useset) :-
Instr0 = llds_instr(Uinstr0, _Comment),
( if Uinstr0 = label(Label) then
( if
(
Label = entry_label(EntryType, _),
(
( EntryType = entry_label_exported
; EntryType = entry_label_local
),
NeedLabel = yes
;
EntryType = entry_label_c_local,
NeedLabel = no
),
NeedLabel = yes
;
set_tree234.member(Label, Useset)
)
then
!:RevInstrs = [Instr0 | !.RevInstrs],
!:Fallthrough = yes
else
eliminate_instr(Instr0, yes(!.Fallthrough), !RevInstrs, !Mod)
)
else
(
!.Fallthrough = yes,
!:RevInstrs = [Instr0 | !.RevInstrs]
;
!.Fallthrough = no,
eliminate_instr(Instr0, no, !RevInstrs, !Mod)
),
opt_util.can_instr_fall_through(Uinstr0) = Canfallthrough,
(
Canfallthrough = yes
;
Canfallthrough = no,
!:Fallthrough = no
)
),
opt_labels_in_instr_list_2(Instrs0, !RevInstrs, !Mod,
!.Fallthrough, Useset).
% Instead of removing eliminated instructions from the instruction list,
% we can replace them by placeholder comments. The original comment field
% on the instruction is often enough to deduce what the eliminated
% instruction was.
%
:- pred eliminate_instr(instruction::in, maybe(bool)::in,
list(instruction)::in, list(instruction)::out,
bool::in, bool::out) is det.
eliminate_instr(llds_instr(Uinstr0, Comment0), Label, !RevInstrs, !Mod) :-
labelopt_eliminate_total(Total),
(
Total = yes,
% We have deleted Uinstr0 by not adding it to !RevInstrs.
!:Mod = yes
;
Total = no,
( if Uinstr0 = comment(_) then
Uinstr = Uinstr0
else
(
Label = yes(Follow),
(
Follow = yes,
Uinstr = comment("eliminated label only")
;
Follow = no,
Uinstr = comment("eliminated label and block")
)
;
Label = no,
Uinstr = comment("eliminated instruction")
),
!:Mod = yes
),
!:RevInstrs = [llds_instr(Uinstr, Comment0) | !.RevInstrs]
).
:- pred labelopt_eliminate_total(bool::out) is det.
labelopt_eliminate_total(yes).
%-----------------------------------------------------------------------------%
:- end_module ll_backend.labelopt.
%-----------------------------------------------------------------------------%