Files
mercury/compiler/optimize.m
Zoltan Somogyi 96e1ed99e1 Give many optimization options backend-specific names ...
... and delete their second name.

compiler/options.m:
    The internal names of many optimization options have traditionally
    given no clue about which backend(s) they apply to, which made it
    hard to document them. Change this by including either llds or mlds
    in the names of these options, unless the rest of the name already
    ruled out one or the other backend.

    In one case, this exercise relevaled that an option that was classified
    as MLDS-only is used by the LLDS backend as well. Reclassify this option.

    Also, rename many options to the names they have in the opt_tuple.
    Those names are more recent, and their naming is more consistent
    (e.g. they are all verb phrases).

tools/make_optimization_options_db:
    Delete the different-from-the-opt-tuple name alternatives.

tools/make_optimization_options_end:
    Conform to the option renames.

    Also, fix a bug. The list of options enabled at each optimization
    level lists each option twice, once by its name in the opt_tuple
    (which is what we use to actually implement optimization levels)
    and once by its name in options.m (which we use to implement
    the option that prints out the optimization levels). In one case,
    the two names did not match; fix this.

compiler/optimization_options.m:
    Rebuild this module with tools/make_optimization_options.

compiler/add_trail_ops.m:
compiler/global_data.m:
compiler/handle_options.m:
compiler/ite_gen.m:
compiler/jumpopt.m:
compiler/mercury_compile_llds_back_end.m:
compiler/mercury_compile_mlds_back_end.m:
compiler/ml_optimize.m:
compiler/optimize.m:
compiler/options.m:
compiler/proc_gen.m:
compiler/stack_layout.m:
    Conform to the option renames.

tests/warnings/help_opt_levels.err_exp:
    Expect the fix to make_optimization_options_end.

tests/warnings/help_text.err_exp:
    Expect the option reclassification.
2025-07-07 05:00:37 +02:00

888 lines
34 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
% Copyright (C) 1996-2012 The University of Melbourne.
% Copyright (C) 2015, 2018, 2020-2025 The Mercury team.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%-----------------------------------------------------------------------------%
%
% File: optimize.m.
% Main author: zs.
%
% This module contains LLDS to LLDS optimizations.
%
%-----------------------------------------------------------------------------%
:- module ll_backend.optimize.
:- interface.
:- import_module libs.
:- import_module libs.globals.
:- import_module ll_backend.global_data.
:- import_module ll_backend.llds.
:- import_module mdbcomp.
:- import_module mdbcomp.sym_name.
:- import_module io.
:- import_module list.
%-----------------------------------------------------------------------------%
:- pred optimize_procs(io.text_output_stream::in, globals::in, module_name::in,
global_data::in, list(c_procedure)::in, list(c_procedure)::out) is det.
:- pred optimize_proc(io.text_output_stream::in, globals::in, module_name::in,
global_data::in, c_procedure::in, c_procedure::out) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module hlds.
:- import_module hlds.code_model.
:- import_module hlds.hlds_pred.
:- import_module libs.file_util.
:- import_module libs.optimization_options.
:- import_module libs.options.
:- import_module ll_backend.continuation_info.
:- import_module ll_backend.delay_slot.
:- import_module ll_backend.dupelim.
:- import_module ll_backend.frameopt.
:- import_module ll_backend.jumpopt.
:- import_module ll_backend.labelopt.
:- import_module ll_backend.opt_debug.
:- import_module ll_backend.opt_util.
:- import_module ll_backend.peephole.
:- import_module ll_backend.reassign.
:- import_module ll_backend.stdlabel.
:- import_module ll_backend.use_local_vars.
:- import_module ll_backend.wrap_blocks.
:- import_module mdbcomp.prim_data.
:- import_module parse_tree.
:- import_module parse_tree.prog_data.
:- import_module bool.
:- import_module char.
:- import_module counter.
:- import_module dir.
:- import_module int.
:- import_module io.call_system.
:- import_module map.
:- import_module maybe.
:- import_module require.
:- import_module set_tree234.
:- import_module string.
%-----------------------------------------------------------------------------%
optimize_procs(_, _, _, _, [], []).
optimize_procs(ProgressStream, Globals, ModuleName, GlobalData,
[Proc0 | Procs0], [Proc | Procs]) :-
optimize_proc(ProgressStream, Globals, ModuleName, GlobalData,
Proc0, Proc),
optimize_procs(ProgressStream, Globals, ModuleName, GlobalData,
Procs0, Procs).
optimize_proc(ProgressStream, Globals, ModuleName, GlobalData,
CProc0, CProc) :-
Info = init_llds_opt_info(ProgressStream, Globals, ModuleName),
some [!OptDebugInfo, !LabelNumCounter, !Instrs] (
CProc0 = c_procedure(PorF, Name, UserArity, PredProcId, ProcLabel,
CodeModel, EffTraceLevel, !:Instrs, !:LabelNumCounter,
MayAlterRtti, CGlobalVars),
need_opt_debug_info(Info, PorF, Name, UserArity, PredProcId,
MaybeBaseName),
(
MaybeBaseName = no,
!:OptDebugInfo = no_opt_debug_info
;
MaybeBaseName = yes(BaseName),
FirstFileName = BaseName ++ ".opt" ++ num_to_str(0),
trace [io(!IO)] (
output_first_opt_debug(Info, FirstFileName, ProcLabel,
!.Instrs, !.LabelNumCounter, !IO)
),
!:OptDebugInfo = opt_debug_info(BaseName, 0, FirstFileName, 0,
FirstFileName, !.Instrs)
),
Repeat = Info ^ lopt_opt_repeat,
( if
global_data_maybe_get_proc_layout(GlobalData,
PredProcId, ProcLayout)
then
LabelMap = ProcLayout ^ pli_internal_map,
map.sorted_keys(LabelMap, LayoutLabelNums),
LayoutLabels = list.map(
make_internal_label_for_proc_label(ProcLabel),
LayoutLabelNums),
set_tree234.sorted_list_to_set(LayoutLabels, LayoutLabelSet)
else
LayoutLabelSet = set_tree234.init
),
Statistics = Info ^ lopt_detailed_statistics,
optimize_initial(Info, LayoutLabelSet, ProcLabel, CodeModel,
MayAlterRtti, !LabelNumCounter, !OptDebugInfo, !Instrs),
optimize_repeat(Info, Repeat, LayoutLabelSet, ProcLabel,
MayAlterRtti, !LabelNumCounter, !OptDebugInfo, !Instrs),
trace [io(!IO)] (
maybe_report_stats(ProgressStream, Statistics, !IO)
),
optimize_middle(Info, yes, LayoutLabelSet, ProcLabel, CodeModel,
MayAlterRtti, !LabelNumCounter, !OptDebugInfo, !Instrs),
trace [io(!IO)] (
maybe_report_stats(ProgressStream, Statistics, !IO)
),
optimize_last(Info, LayoutLabelSet, ProcLabel,
!LabelNumCounter, !.OptDebugInfo, !Instrs),
trace [io(!IO)] (
maybe_report_stats(ProgressStream, Statistics, !IO)
),
CProc = c_procedure(PorF, Name, UserArity, PredProcId, ProcLabel,
CodeModel, EffTraceLevel, !.Instrs, !.LabelNumCounter,
MayAlterRtti, CGlobalVars)
).
:- func make_internal_label_for_proc_label(proc_label, int) = label.
make_internal_label_for_proc_label(ProcLabel, LabelNum)
= internal_label(LabelNum, ProcLabel).
%-----------------------------------------------------------------------------%
:- type opt_debug_info
---> opt_debug_info(
% Base file name for the dump files.
odi_dump_file_base_name :: string,
% The number of the last dump file written.
odi_last_dump_num :: int,
% The name of the last dump file written.
odi_last_dump_file_name :: string,
% The number of the last dump file written that has
% the instruction sequence in it.
odi_last_instrs_dump_num :: int,
% The name of the last dump file written that has
% the instruction sequence in it.
odi_last_instrs_dump_file_name :: string,
% The instruction sequence at the time the last dump file
% was written.
odi_last_dump_instr_seq :: list(instruction)
)
; no_opt_debug_info.
:- pred need_opt_debug_info(llds_opt_info::in, pred_or_func::in, string::in,
user_arity::in, pred_proc_id::in, maybe(string)::out) is det.
need_opt_debug_info(Info, PorF, Name, UserArity, PredProcId, MaybeBaseName) :-
DebugOpt = Info ^ lopt_debug_opt,
DebugOptPredIdStrs = Info ^ lopt_debug_opt_pred_ids,
DebugOptPredNames = Info ^ lopt_debug_opt_pred_names,
PredProcId = proc(PredId, ProcId),
pred_id_to_int(PredId, PredIdInt),
proc_id_to_int(ProcId, ProcIdInt),
( if
DebugOpt = yes,
(
DebugOptPredIdStrs = [_ | _],
DebugOptPredNames = [_ | _],
(
some [DebugOptPredIdStr, DebugOptPredId] (
list.member(DebugOptPredIdStr, DebugOptPredIdStrs),
string.to_int(DebugOptPredIdStr, DebugOptPredId),
DebugOptPredId = PredIdInt
)
;
list.member(Name, DebugOptPredNames)
)
;
DebugOptPredIdStrs = [_ | _],
DebugOptPredNames = [],
some [DebugOptPredIdStr, DebugOptPredId] (
list.member(DebugOptPredIdStr, DebugOptPredIdStrs),
string.to_int(DebugOptPredIdStr, DebugOptPredId),
DebugOptPredId = PredIdInt
)
;
DebugOptPredIdStrs = [],
DebugOptPredNames = [_ | _],
list.member(Name, DebugOptPredNames)
;
DebugOptPredIdStrs = [],
DebugOptPredNames = []
)
then
UserArity = user_arity(UserArityInt),
string.format("%s/%s_%s_%d.pred%d.proc%d",
[s(opt_subdir_name), s(pred_or_func_to_str(PorF)),
s(mangle_name_as_filename(Name)), i(UserArityInt),
i(PredIdInt), i(ProcIdInt)], BaseName),
MaybeBaseName = yes(BaseName)
else
MaybeBaseName = no
).
:- pred output_first_opt_debug(llds_opt_info::in, string::in, proc_label::in,
list(instruction)::in, counter::in, io::di, io::uo) is det.
output_first_opt_debug(Info, FileName, ProcLabel, Instrs0, Counter, !IO) :-
io.call_system.call_system("mkdir -p " ++ opt_subdir_name, MkdirRes, !IO),
( if MkdirRes = ok(0) then
io.open_output(FileName, Res, !IO),
(
Res = ok(FileStream),
counter.allocate(NextLabel, Counter, _),
llds_proc_dump_msg(FileStream, yes, NextLabel,
"before optimization", !IO),
AutoComments = Info ^ lopt_auto_comments,
opt_debug.maybe_write_instrs(FileStream, yes, AutoComments,
yes(ProcLabel), Instrs0, !IO),
io.close_output(FileStream, !IO)
;
Res = error(_),
unexpected($pred, "cannot open " ++ FileName)
)
else
unexpected($pred, "cannot make " ++ opt_subdir_name)
).
:- func opt_subdir_name = string.
opt_subdir_name = "OptSubdir".
:- func num_to_str(int) = string.
num_to_str(N) =
( if N < 10 then
"0" ++ string.int_to_string(N)
else
string.int_to_string(N)
).
:- pred maybe_dump_proc_code(llds_opt_info::in, list(instruction)::in,
counter::in, string::in, string::in, proc_label::in,
opt_debug_info::in, opt_debug_info::out) is det.
maybe_dump_proc_code(Info, Instrs, Counter, Suffix, Msg, ProcLabel,
!OptDebugInfo) :-
(
!.OptDebugInfo = opt_debug_info(BaseName, OptNum0, _OptFileName0,
PrevNum, PrevFileName, PrevInstrs),
OptNum = OptNum0 + 1,
OptFileName = BaseName ++ ".opt" ++ num_to_str(OptNum)
++ "." ++ Suffix,
DiffFileName = BaseName ++ ".diff" ++ num_to_str(OptNum)
++ "." ++ Suffix,
( if Instrs = PrevInstrs then
Same = yes,
!:OptDebugInfo = opt_debug_info(BaseName, OptNum, OptFileName,
PrevNum, PrevFileName, Instrs)
else
Same = no,
!:OptDebugInfo = opt_debug_info(BaseName, OptNum, OptFileName,
OptNum, OptFileName, Instrs)
),
trace [io(!IO)] (
io.open_output(OptFileName, Res, !IO),
(
Res = ok(FileStream),
counter.allocate(NextLabel, Counter, _),
llds_proc_dump_msg(FileStream, yes, NextLabel, Msg, !IO),
(
Same = yes,
io.write_string(FileStream,
"same as previous version\n", !IO)
;
Same = no,
AutoComments = Info ^ lopt_auto_comments,
opt_debug.maybe_write_instrs(FileStream, yes, AutoComments,
yes(ProcLabel), Instrs, !IO)
),
io.close_output(FileStream, !IO)
;
Res = error(_),
unexpected($pred, "cannot open " ++ OptFileName)
),
(
Same = yes
;
Same = no,
% Although the -u is not fully portable, it is available on
% all the systems we intend to use it on, and the main user
% of --debug-opt (zs) strongly prefers -u to -c.
DiffCommand = "diff -u '" ++ PrevFileName ++ "' '" ++
OptFileName ++ "' > '" ++ DiffFileName ++ "'",
io.call_system.call_system(DiffCommand, _, !IO)
)
)
;
!.OptDebugInfo = no_opt_debug_info
).
%-----------------------------------------------------------------------------%
:- pred optimize_initial(llds_opt_info::in, set_tree234(label)::in,
proc_label::in, code_model::in, may_alter_rtti::in,
counter::in, counter::out, opt_debug_info::in, opt_debug_info::out,
list(instruction)::in, list(instruction)::out) is det.
optimize_initial(Info, LayoutLabelSet, ProcLabel, CodeModel, MayAlterRtti,
!LabelNumCounter, !OptDebugInfo, !Instrs) :-
LabelStr = opt_util.format_proc_label(ProcLabel),
OptFrames = Info ^ lopt_opt_frames,
( if
OptFrames = opt_frames,
MayAlterRtti = may_alter_rtti,
CodeModel = model_non
then
VeryVerbose = Info ^ lopt_very_verbose,
(
VeryVerbose = yes,
trace [io(!IO)] (
get_opt_progress_output_stream(Info, ProgressStream),
io.format(ProgressStream,
"%% Optimizing nondet frames for %s\n",
[s(LabelStr)], !IO)
)
;
VeryVerbose = no
),
frameopt_keep_nondet_frame(ProcLabel, LayoutLabelSet,
!LabelNumCounter, !Instrs, _Mod),
maybe_dump_proc_code(Info, !.Instrs, !.LabelNumCounter, "ndframeopt",
"after nondet frame opt", ProcLabel, !OptDebugInfo)
else
true
).
%-----------------------------------------------------------------------------%
:- pred optimize_repeat(llds_opt_info::in, int::in, set_tree234(label)::in,
proc_label::in, may_alter_rtti::in, counter::in, counter::out,
opt_debug_info::in, opt_debug_info::out,
list(instruction)::in, list(instruction)::out) is det.
optimize_repeat(Info, CurIter, LayoutLabelSet, ProcLabel,
MayAlterRtti, !LabelNumCounter, !OptDebugInfo, !Instrs) :-
( if CurIter > 0 then
NextIter = CurIter - 1,
( if NextIter = 0 then
Final = yes
else
Final = no
),
optimize_repeated(Info, Final, LayoutLabelSet, ProcLabel, MayAlterRtti,
!LabelNumCounter, !OptDebugInfo, !Instrs, Mod),
(
Mod = yes,
optimize_repeat(Info, NextIter, LayoutLabelSet, ProcLabel,
MayAlterRtti, !LabelNumCounter, !OptDebugInfo, !Instrs)
;
Mod = no
)
else
true
).
% We short-circuit jump sequences before normal peepholing
% to create more opportunities for use of the tailcall macro.
%
:- pred optimize_repeated(llds_opt_info::in, bool::in, set_tree234(label)::in,
proc_label::in, may_alter_rtti::in, counter::in, counter::out,
opt_debug_info::in, opt_debug_info::out,
list(instruction)::in, list(instruction)::out, bool::out) is det.
optimize_repeated(Info, Final, LayoutLabelSet, ProcLabel, MayAlterRtti,
!LabelNumCounter, !OptDebugInfo, !Instrs, Mod) :-
InstrsAtStart = !.Instrs,
LabelStr = opt_util.format_proc_label(ProcLabel),
VeryVerbose = Info ^ lopt_very_verbose,
OptJump = Info ^ lopt_opt_jumps,
OptFullJump = Info ^ lopt_opt_fulljumps,
PessimizeTailCalls = Info ^ lopt_pes_tailcalls,
CheckedNondetTailCalls = Info ^ lopt_checked_nondet_tailcalls,
(
OptJump = opt_jumps,
(
VeryVerbose = yes,
trace [io(!IO)] (
get_opt_progress_output_stream(Info, ProgressStream),
io.format(ProgressStream, "%% Optimizing jumps for %s\n",
[s(LabelStr)], !IO)
)
;
VeryVerbose = no
),
optimize_jumps_in_proc(LayoutLabelSet, MayAlterRtti, ProcLabel,
OptFullJump, Final, PessimizeTailCalls, CheckedNondetTailCalls,
!LabelNumCounter, !Instrs, Mod1),
maybe_dump_proc_code(Info, !.Instrs, !.LabelNumCounter,
"jump", "after jump opt", ProcLabel, !OptDebugInfo)
;
OptJump = do_not_opt_jumps,
Mod1 = no
),
Peephole = Info ^ lopt_opt_peep,
(
Peephole = peep_llds,
(
VeryVerbose = yes,
trace [io(!IO)] (
get_opt_progress_output_stream(Info, ProgressStream),
io.format(ProgressStream, "%% Optimizing locally for %s\n",
[s(LabelStr)], !IO)
)
;
VeryVerbose = no
),
GC_Method = Info ^ lopt_gc_method,
OptPeepMkword = Info ^ lopt_opt_peep_mkword,
peephole_optimize(GC_Method, OptPeepMkword, !Instrs, Mod2),
maybe_dump_proc_code(Info, !.Instrs, !.LabelNumCounter,
"peep", "after peephole", ProcLabel, !OptDebugInfo)
;
Peephole = do_not_peep_llds,
Mod2 = no
),
OptLabels = Info ^ lopt_opt_labels,
(
OptLabels = opt_labels,
(
VeryVerbose = yes,
trace [io(!IO)] (
get_opt_progress_output_stream(Info, ProgressStream),
io.format(ProgressStream, "%% Optimizing labels for %s\n",
[s(LabelStr)], !IO)
)
;
VeryVerbose = no
),
labelopt_main(Final, LayoutLabelSet, !Instrs, Mod3),
maybe_dump_proc_code(Info, !.Instrs, !.LabelNumCounter,
"label", "after label opt", ProcLabel, !OptDebugInfo)
;
OptLabels = do_not_opt_labels,
Mod3 = no
),
DupElim = Info ^ lopt_opt_dups,
(
DupElim = opt_dup_instrs_llds,
(
VeryVerbose = yes,
trace [io(!IO)] (
get_opt_progress_output_stream(Info, ProgressStream),
io.format(ProgressStream, "%% Optimizing duplicates for %s\n",
[s(LabelStr)], !IO)
)
;
VeryVerbose = no
),
dupelim_main(ProcLabel, !LabelNumCounter, !Instrs),
maybe_dump_proc_code(Info, !.Instrs, !.LabelNumCounter,
"dup", "after duplicates", ProcLabel, !OptDebugInfo)
;
DupElim = do_not_opt_dup_instrs_llds
),
( if Mod1 = no, Mod2 = no, Mod3 = no, !.Instrs = InstrsAtStart then
Mod = no
else
Mod = yes
),
trace [io(!IO)] (
get_opt_progress_output_stream(Info, ProgressStream),
Statistics = Info ^ lopt_detailed_statistics,
maybe_report_stats(ProgressStream, Statistics, !IO)
).
:- pred optimize_middle(llds_opt_info::in, bool::in, set_tree234(label)::in,
proc_label::in, code_model::in, may_alter_rtti::in,
counter::in, counter::out, opt_debug_info::in, opt_debug_info::out,
list(instruction)::in, list(instruction)::out) is det.
optimize_middle(Info, Final, LayoutLabelSet, ProcLabel, CodeModel,
MayAlterRtti, !LabelNumCounter, !OptDebugInfo, !Instrs) :-
VeryVerbose = Info ^ lopt_very_verbose,
LabelStr = opt_util.format_proc_label(ProcLabel),
OptFrames = Info ^ lopt_opt_frames,
(
OptFrames = opt_frames,
(
VeryVerbose = yes,
trace [io(!IO)] (
get_opt_progress_output_stream(Info, ProgressStream),
io.format(ProgressStream, "%% Optimizing frames for %s\n",
[s(LabelStr)], !IO)
)
;
VeryVerbose = no
),
FrameOptComments = Info ^ lopt_frameopt_comments,
(
( CodeModel = model_det
; CodeModel = model_semi
),
frameopt_main_det_stack(ProcLabel, !LabelNumCounter, !Instrs,
FrameOptComments, FrameModified)
;
CodeModel = model_non,
frameopt_main_nondet_stack(ProcLabel, !LabelNumCounter, !Instrs,
FrameOptComments, FrameModified)
),
maybe_dump_proc_code(Info, !.Instrs, !.LabelNumCounter,
"frame", "after frame opt", ProcLabel, !OptDebugInfo),
Statistics = Info ^ lopt_detailed_statistics,
trace [io(!IO)] (
get_opt_progress_output_stream(Info, ProgressStream),
maybe_report_stats(ProgressStream, Statistics, !IO)
),
OptFullJump = Info ^ lopt_opt_fulljumps,
PessimizeTailCalls = Info ^ lopt_pes_tailcalls,
CheckedNondetTailCalls = Info ^ lopt_checked_nondet_tailcalls,
( if
( OptFullJump = opt_fulljumps
; FrameModified = yes
)
then
(
VeryVerbose = yes,
trace [io(!IO)] (
get_opt_progress_output_stream(Info, ProgressStream),
io.format(ProgressStream, "%% Optimizing jumps for %s\n",
[s(LabelStr)], !IO)
)
;
VeryVerbose = no
),
optimize_jumps_in_proc(LayoutLabelSet, MayAlterRtti, ProcLabel,
OptFullJump, Final, PessimizeTailCalls, CheckedNondetTailCalls,
!LabelNumCounter, !Instrs, JumpModified),
% Some jump optimization, such as the one that replaces two
% separate semidet epilogs (one assigning false and one assigning
% true to r1) with one semidet epilog that assigns to r1
% the value of a boolean expression, can leave dead code
% in !:Insts. We need to execute the following passes
% to eliminate that dead code.
%
% NOTE: We ignored JumpModified for almost three decades,
% so such situations must be *extremely* rare. It would therefore
% be nice if jumpopt could tell us not just whether it made
% *any* modifications (which is what JumpModified does), but also
% whether it made any modifications that *require* cleanup.
bool.or(FrameModified, JumpModified, FrameOrJumpModified),
maybe_dump_proc_code(Info, !.Instrs, !.LabelNumCounter,
"jump", "after jumps", ProcLabel, !OptDebugInfo)
else
FrameOrJumpModified = FrameModified
),
(
FrameOrJumpModified = yes,
(
VeryVerbose = yes,
trace [io(!IO)] (
get_opt_progress_output_stream(Info, ProgressStream),
io.format(ProgressStream, "%% Optimizing labels for %s\n",
[s(LabelStr)], !IO)
)
;
VeryVerbose = no
),
labelopt_main(Final, LayoutLabelSet, !Instrs, _Mod3),
maybe_dump_proc_code(Info, !.Instrs, !.LabelNumCounter,
"label", "after labels", ProcLabel, !OptDebugInfo)
;
FrameOrJumpModified = no
),
(
FrameOrJumpModified = yes,
(
VeryVerbose = yes,
trace [io(!IO)] (
get_opt_progress_output_stream(Info, ProgressStream),
io.format(ProgressStream, "%% Optimizing locally for %s\n",
[s(LabelStr)], !IO)
)
;
VeryVerbose = no
),
GC_Method = Info ^ lopt_gc_method,
OptPeepMkword = Info ^ lopt_opt_peep_mkword,
peephole_optimize(GC_Method, OptPeepMkword, !Instrs, _Mod),
maybe_dump_proc_code(Info, !.Instrs, !.LabelNumCounter,
"peep", "after peephole", ProcLabel, !OptDebugInfo)
;
FrameOrJumpModified = no
)
;
OptFrames = do_not_opt_frames
),
UseLocalVars = Info ^ lopt_use_local_vars,
(
UseLocalVars = use_local_vars_llds,
(
VeryVerbose = yes,
trace [io(!IO)] (
get_opt_progress_output_stream(Info, ProgressStream),
io.format(ProgressStream, "%% Optimizing local vars for %s\n",
[s(LabelStr)], !IO)
)
;
VeryVerbose = no
),
NumRealRRegs = Info ^ lopt_num_real_r_regs,
AccessThreshold = Info ^ lopt_local_vars_access_threshold,
AutoComments = Info ^ lopt_auto_comments,
use_local_vars_proc(!Instrs, NumRealRRegs, AccessThreshold,
AutoComments, ProcLabel, !LabelNumCounter),
maybe_dump_proc_code(Info, !.Instrs, !.LabelNumCounter, "use_local",
"after use_local_vars", ProcLabel, !OptDebugInfo)
;
UseLocalVars = do_not_use_local_vars_llds
).
:- pred optimize_last(llds_opt_info::in, set_tree234(label)::in,
proc_label::in, counter::in, counter::out, opt_debug_info::in,
list(instruction)::in, list(instruction)::out) is det.
optimize_last(Info, LayoutLabelSet, ProcLabel,
!LabelNumCounter, !.OptDebugInfo, !Instrs) :-
VeryVerbose = Info ^ lopt_very_verbose,
LabelStr = opt_util.format_proc_label(ProcLabel),
Reassign = Info ^ lopt_opt_reassign,
DelaySlot = Info ^ lopt_opt_delay_slots,
UseLocalVars = Info ^ lopt_use_local_vars,
StdLabels = Info ^ lopt_std_labels,
( if
( Reassign = opt_llds_reassign
; DelaySlot = opt_delay_slot
; UseLocalVars = use_local_vars_llds
; StdLabels = standardize_labels
)
then
% We must get rid of any extra labels added by other passes,
% since they can confuse reassign, wrap_blocks and delay_slot.
(
VeryVerbose = yes,
trace [io(!IO)] (
get_opt_progress_output_stream(Info, ProgressStream),
io.format(ProgressStream, "%% Optimizing labels for %s\n",
[s(LabelStr)], !IO)
)
;
VeryVerbose = no
),
labelopt_main(no, LayoutLabelSet, !Instrs, _Mod1),
maybe_dump_proc_code(Info, !.Instrs, !.LabelNumCounter,
"label", "after label opt", ProcLabel, !OptDebugInfo)
else
true
),
(
Reassign = opt_llds_reassign,
(
VeryVerbose = yes,
trace [io(!IO)] (
get_opt_progress_output_stream(Info, ProgressStream),
io.format(ProgressStream, "%% Optimizing reassign for %s\n",
[s(LabelStr)], !IO)
)
;
VeryVerbose = no
),
remove_reassign(!Instrs),
maybe_dump_proc_code(Info, !.Instrs, !.LabelNumCounter,
"reassign", "after reassign", ProcLabel, !OptDebugInfo)
;
Reassign = do_not_opt_llds_reassign
),
(
DelaySlot = opt_delay_slot,
(
VeryVerbose = yes,
trace [io(!IO)] (
get_opt_progress_output_stream(Info, ProgressStream),
io.format(ProgressStream, "%% Optimizing delay slot for %s\n",
[s(LabelStr)], !IO)
)
;
VeryVerbose = no
),
fill_branch_delay_slot(!Instrs),
maybe_dump_proc_code(Info, !.Instrs, !.LabelNumCounter,
"delay_slot", "after delay slots", ProcLabel, !OptDebugInfo)
;
DelaySlot = do_not_opt_delay_slot
),
(
VeryVerbose = yes,
trace [io(!IO)] (
get_opt_progress_output_stream(Info, ProgressStream),
io.format(ProgressStream, "%% Optimizing returns for %s\n",
[s(LabelStr)], !IO)
)
;
VeryVerbose = no
),
combine_decr_sp(!Instrs),
maybe_dump_proc_code(Info, !.Instrs, !.LabelNumCounter,
"decr_sp", "after combine decr_sp", ProcLabel, !OptDebugInfo),
(
StdLabels = standardize_labels,
(
VeryVerbose = yes,
trace [io(!IO)] (
get_opt_progress_output_stream(Info, ProgressStream),
io.format(ProgressStream, "%% Standardizing labels for %s\n",
[s(LabelStr)], !IO)
)
;
VeryVerbose = no
),
standardize_labels(!Instrs, !LabelNumCounter),
maybe_dump_proc_code(Info, !.Instrs, !.LabelNumCounter,
"stdlabel", "after standard labels", ProcLabel, !OptDebugInfo)
;
StdLabels = do_not_standardize_labels
),
(
UseLocalVars = use_local_vars_llds,
(
VeryVerbose = yes,
trace [io(!IO)] (
get_opt_progress_output_stream(Info, ProgressStream),
io.format(ProgressStream, "%% Wrapping blocks for %s\n",
[s(LabelStr)], !IO)
)
;
VeryVerbose = no
),
wrap_blocks(!Instrs),
maybe_dump_proc_code(Info, !.Instrs, !.LabelNumCounter,
"wrapblocks", "after wrap blocks", ProcLabel, !.OptDebugInfo, _)
;
UseLocalVars = do_not_use_local_vars_llds
).
%-----------------------------------------------------------------------------%
% Mangle the given name just sufficiently to make it acceptable as a
% filename.
%
:- func mangle_name_as_filename(string) = string.
mangle_name_as_filename(Str0) = Str :-
string.foldl(escape_dir_char, Str0, "", Str).
:- pred escape_dir_char(char::in, string::in, string::out) is det.
escape_dir_char(Char, !Str) :-
( if dir.is_directory_separator(Char) then
!:Str = !.Str ++ "_slash_"
else
!:Str = !.Str ++ char_to_string(Char)
).
%-----------------------------------------------------------------------------%
:- type llds_opt_info
---> llds_opt_info(
lopt_debug_opt_pred_ids :: list(string),
lopt_debug_opt_pred_names :: list(string),
lopt_num_real_r_regs :: int,
lopt_local_vars_access_threshold :: int,
lopt_opt_repeat :: int,
lopt_progress_stream :: io.text_output_stream,
lopt_globals :: globals,
lopt_module_name :: module_name,
lopt_gc_method :: gc_method,
lopt_debug_opt :: bool,
lopt_auto_comments :: maybe_auto_comments,
lopt_frameopt_comments :: bool,
lopt_detailed_statistics :: bool,
lopt_very_verbose :: bool,
lopt_checked_nondet_tailcalls ::
maybe_opt_checked_nondet_tailcalls,
lopt_opt_delay_slots :: maybe_opt_delay_slot,
lopt_opt_dups :: maybe_opt_dup_instrs_llds,
lopt_opt_frames :: maybe_opt_frames,
lopt_opt_jumps :: maybe_opt_jumps,
lopt_opt_fulljumps :: maybe_opt_fulljumps,
lopt_opt_labels :: maybe_opt_labels,
lopt_opt_peep :: maybe_peep_llds,
lopt_opt_peep_mkword :: maybe_peep_llds_mkword,
lopt_opt_reassign :: maybe_opt_llds_reassign,
lopt_pes_tailcalls :: maybe_pessimize_llds_tailcalls,
lopt_std_labels :: maybe_standardize_labels,
lopt_use_local_vars :: maybe_use_local_vars_llds
).
:- func init_llds_opt_info(io.text_output_stream, globals, module_name)
= llds_opt_info.
init_llds_opt_info(ProgressStream, Globals, ModuleName) = Info :-
globals.lookup_accumulating_option(Globals, debug_opt_pred_id,
DebugOptPredIdStrs),
globals.lookup_accumulating_option(Globals, debug_opt_pred_name,
DebugOptPredNames),
globals.lookup_int_option(Globals, num_real_r_regs, NumRealRRegs),
globals.get_opt_tuple(Globals, OptTuple),
LocalVarAccessThreshold = OptTuple ^ ot_llds_local_var_access_threshold,
OptRepeat = OptTuple ^ ot_opt_repeat,
globals.get_gc_method(Globals, GCMethod),
globals.lookup_bool_option(Globals, debug_opt, DebugOpt),
globals.lookup_bool_option(Globals, auto_comments, AutoCommentsOption),
( AutoCommentsOption = no, AutoComments = no_auto_comments
; AutoCommentsOption = yes, AutoComments = auto_comments
),
globals.lookup_bool_option(Globals, frameopt_comments, FrameOptComments),
globals.lookup_bool_option(Globals, detailed_statistics,
DetailedStatistics),
globals.lookup_bool_option(Globals, very_verbose, VeryVerbose),
CheckedNondetTailCalls = OptTuple ^ ot_opt_checked_nondet_tailcalls,
OptDelaySlots = OptTuple ^ ot_opt_delay_slot,
OptDups = OptTuple ^ ot_opt_dup_instrs_llds,
OptFrames = OptTuple ^ ot_opt_frames,
OptJumps = OptTuple ^ ot_opt_jumps,
OptFullJumps = OptTuple ^ ot_opt_fulljumps,
OptLabels = OptTuple ^ ot_opt_labels,
OptPeep = OptTuple ^ ot_peep_llds,
OptPeepMkword = OptTuple ^ ot_peep_llds_mkword,
OptReassign = OptTuple ^ ot_opt_llds_reassign,
PessimizeTailCalls = OptTuple ^ ot_pessimize_llds_tailcalls,
StdLabels = OptTuple ^ ot_standardize_labels,
UseLocalVars = OptTuple ^ ot_use_local_vars_llds,
Info = llds_opt_info(DebugOptPredIdStrs, DebugOptPredNames,
NumRealRRegs, LocalVarAccessThreshold, OptRepeat,
ProgressStream, Globals, ModuleName,
GCMethod, DebugOpt, AutoComments, FrameOptComments,
DetailedStatistics, VeryVerbose,
CheckedNondetTailCalls, OptDelaySlots, OptDups, OptFrames,
OptJumps, OptFullJumps, OptLabels, OptPeep, OptPeepMkword, OptReassign,
PessimizeTailCalls, StdLabels, UseLocalVars).
:- pred get_opt_progress_output_stream(llds_opt_info::in,
io.text_output_stream::out) is det.
get_opt_progress_output_stream(Info, ProgressStream) :-
ProgressStream = Info ^ lopt_progress_stream.
%-----------------------------------------------------------------------------%
:- end_module ll_backend.optimize.
%-----------------------------------------------------------------------------%