mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-19 07:45:09 +00:00
Estimated hours taken: 8
Add a new option, --checked-nondet-tailcalls, that enables the use of
Prolog style nondet tail calls (which check whether the current frame is
on top of the nondet stack and only do a tail call if it is).
This option is not likely to help Mercury code, since most of the time
the test will fail, which means we incurred its cost and did not gain
the benefit of the tailcall. However, HAL often has predicates that are
declared nondet but are det or semidet most of the time, and these can
benefit.
compiler/options.m:
doc/user_guide.texi:
Add the new option, which is not on by default and is not turned on
at any optimization level; you have to give it explicitly.
compiler/llds.m:
Modify the call_model type to distinguish the new style nondet tail
call from the old (which does not do a runtime test).
compiler/code_info.m:
Check the fail state whether it is suitable for new style nondet
tail calls.
compiler/call_gen.m:
Put the result from code_info.m into the generated LLDS.
compiler/jumpopt.m:
Use the new status field in the LLDS to perform the optimization,
if the option is given.
Document the main predicate and its new argument.
compiler/optimize.m:
Pass the value of the new option to jumpopt.
tests/hard_coded/checked_nondet_tailcall.{m,exp}:
A new test case to check that the code we generate with the new
option works correctly. (Checking whether it actually reduces
nondet stack usage would be harder.)
365 lines
10 KiB
Mathematica
365 lines
10 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1996-1999 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.
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% optimize.m - LLDS to LLDS optimizations.
|
|
|
|
% Main author: zs.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module optimize.
|
|
|
|
:- interface.
|
|
|
|
:- import_module llds.
|
|
:- import_module io, list.
|
|
|
|
:- pred optimize_main(list(c_procedure)::in, global_data::in,
|
|
list(c_procedure)::out, io__state::di, io__state::uo) is det.
|
|
|
|
:- pred optimize__proc(c_procedure::in, global_data::in,
|
|
c_procedure::out, io__state::di, io__state::uo) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module jumpopt, labelopt, dupelim, peephole.
|
|
:- import_module frameopt, delay_slot, value_number, options.
|
|
:- import_module globals, passes_aux, opt_util, opt_debug, vn_debug.
|
|
:- import_module continuation_info.
|
|
|
|
:- import_module bool, int, map, bimap, set, std_util.
|
|
|
|
optimize_main([], _, []) --> [].
|
|
optimize_main([Proc0 | Procs0], GlobalData, [Proc | Procs]) -->
|
|
optimize__proc(Proc0, GlobalData, Proc), !,
|
|
optimize_main(Procs0, GlobalData, Procs).
|
|
|
|
optimize__proc(CProc0, GlobalData, CProc) -->
|
|
{ CProc0 = c_procedure(Name, Arity, PredProcId, Instrs0) },
|
|
globals__io_lookup_bool_option(debug_opt, DebugOpt),
|
|
opt_debug__msg(DebugOpt, "before optimization"),
|
|
opt_debug__dump_instrs(DebugOpt, Instrs0),
|
|
globals__io_lookup_int_option(optimize_repeat, AllRepeat),
|
|
globals__io_lookup_int_option(optimize_vnrepeat, VnRepeat),
|
|
globals__io_lookup_bool_option(optimize_value_number, ValueNumber),
|
|
{
|
|
global_data_maybe_get_proc_layout(GlobalData, PredProcId,
|
|
ProcLayout)
|
|
->
|
|
ProcLayout = proc_layout_info(_, _, _, _, _, _, _, LabelMap),
|
|
map__sorted_keys(LabelMap, LayoutLabels),
|
|
set__sorted_list_to_set(LayoutLabels, LayoutLabelSet)
|
|
;
|
|
set__init(LayoutLabelSet)
|
|
},
|
|
( { ValueNumber = yes } ->
|
|
{ NovnRepeat is AllRepeat - VnRepeat },
|
|
optimize__repeat(NovnRepeat, no, LayoutLabelSet,
|
|
Instrs0, Instrs1),
|
|
optimize__middle(Instrs1, no, LayoutLabelSet, Instrs2),
|
|
optimize__repeat(VnRepeat, yes, LayoutLabelSet,
|
|
Instrs2, Instrs3)
|
|
;
|
|
optimize__repeat(AllRepeat, no, LayoutLabelSet,
|
|
Instrs0, Instrs1),
|
|
optimize__middle(Instrs1, yes, LayoutLabelSet, Instrs3)
|
|
),
|
|
optimize__last(Instrs3, LayoutLabelSet, Instrs),
|
|
{ CProc = c_procedure(Name, Arity, PredProcId, Instrs) }.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred optimize__repeat(int::in, bool::in, set(label)::in,
|
|
list(instruction)::in, list(instruction)::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
optimize__repeat(Iter0, DoVn, LayoutLabelSet, Instrs0, Instrs) -->
|
|
(
|
|
{ Iter0 > 0 }
|
|
->
|
|
{ Iter1 is Iter0 - 1 },
|
|
( { Iter1 = 0 } ->
|
|
{ Final = yes }
|
|
;
|
|
{ Final = no }
|
|
),
|
|
optimize__repeated(Instrs0, DoVn, Final, LayoutLabelSet,
|
|
Instrs1, Mod),
|
|
( { Mod = yes } ->
|
|
optimize__repeat(Iter1, DoVn, LayoutLabelSet,
|
|
Instrs1, Instrs)
|
|
;
|
|
{ Instrs = Instrs1 }
|
|
)
|
|
;
|
|
{ Instrs = Instrs0 }
|
|
).
|
|
|
|
% We short-circuit jump sequences before normal peepholing
|
|
% to create more opportunities for use of the tailcall macro.
|
|
|
|
:- pred optimize__repeated(list(instruction)::in, bool::in, bool::in,
|
|
set(label)::in, list(instruction)::out, bool::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
optimize__repeated(Instrs0, DoVn, Final, LayoutLabelSet, Instrs, Mod) -->
|
|
globals__io_lookup_bool_option(very_verbose, VeryVerbose),
|
|
globals__io_lookup_bool_option(debug_opt, DebugOpt),
|
|
{ opt_util__find_first_label(Instrs0, Label) },
|
|
{ opt_util__format_label(Label, LabelStr) },
|
|
|
|
globals__io_lookup_bool_option(optimize_value_number, ValueNumber),
|
|
( { ValueNumber = yes, DoVn = yes } ->
|
|
( { VeryVerbose = yes } ->
|
|
io__write_string("% Optimizing value number for "),
|
|
io__write_string(LabelStr),
|
|
io__write_string("\n")
|
|
;
|
|
[]
|
|
),
|
|
value_number_main(Instrs0, LayoutLabelSet, Instrs1),
|
|
( { Instrs1 = Instrs0 } ->
|
|
[]
|
|
;
|
|
opt_debug__msg(DebugOpt, "after value numbering"),
|
|
opt_debug__dump_instrs(DebugOpt, Instrs1)
|
|
)
|
|
;
|
|
{ Instrs1 = Instrs0 }
|
|
),
|
|
globals__io_lookup_bool_option(optimize_jumps, Jumpopt),
|
|
globals__io_lookup_bool_option(optimize_fulljumps, FullJumpopt),
|
|
globals__io_lookup_bool_option(checked_nondet_tailcalls,
|
|
CheckedNondetTailCalls),
|
|
( { Jumpopt = yes } ->
|
|
( { VeryVerbose = yes } ->
|
|
io__write_string("% Optimizing jumps for "),
|
|
io__write_string(LabelStr),
|
|
io__write_string("\n")
|
|
;
|
|
[]
|
|
),
|
|
{ jumpopt_main(Instrs1, FullJumpopt, Final,
|
|
CheckedNondetTailCalls, Instrs2, Mod1) },
|
|
( { Mod1 = yes } ->
|
|
opt_debug__msg(DebugOpt, "after jump optimization"),
|
|
opt_debug__dump_instrs(DebugOpt, Instrs2)
|
|
;
|
|
[]
|
|
)
|
|
;
|
|
{ Instrs2 = Instrs1 },
|
|
{ Mod1 = no }
|
|
),
|
|
globals__io_lookup_bool_option(optimize_peep, Peephole),
|
|
( { Peephole = yes } ->
|
|
( { VeryVerbose = yes } ->
|
|
io__write_string("% Optimizing locally for "),
|
|
io__write_string(LabelStr),
|
|
io__write_string("\n")
|
|
;
|
|
[]
|
|
),
|
|
globals__io_get_gc_method(GC_Method),
|
|
{ peephole__optimize(GC_Method, Instrs2, Instrs3, Mod2) },
|
|
( { Mod2 = yes } ->
|
|
opt_debug__msg(DebugOpt, "after peepholing"),
|
|
opt_debug__dump_instrs(DebugOpt, Instrs3)
|
|
;
|
|
[]
|
|
)
|
|
;
|
|
{ Instrs3 = Instrs2 },
|
|
{ Mod2 = no }
|
|
),
|
|
globals__io_lookup_bool_option(optimize_labels, LabelElim),
|
|
( { LabelElim = yes } ->
|
|
( { VeryVerbose = yes } ->
|
|
io__write_string("% Optimizing labels for "),
|
|
io__write_string(LabelStr),
|
|
io__write_string("\n")
|
|
;
|
|
[]
|
|
),
|
|
{ labelopt_main(Instrs3, Final, LayoutLabelSet,
|
|
Instrs4, Mod3) },
|
|
( { Mod3 = yes } ->
|
|
opt_debug__msg(DebugOpt, "after label optimization"),
|
|
opt_debug__dump_instrs(DebugOpt, Instrs4)
|
|
;
|
|
[]
|
|
)
|
|
;
|
|
{ Instrs4 = Instrs3 },
|
|
{ Mod3 = no }
|
|
),
|
|
globals__io_lookup_bool_option(optimize_dups, DupElim),
|
|
( { DupElim = yes } ->
|
|
( { VeryVerbose = yes } ->
|
|
io__write_string("% Optimizing duplicates for "),
|
|
io__write_string(LabelStr),
|
|
io__write_string("\n")
|
|
;
|
|
[]
|
|
),
|
|
{ dupelim_main(Instrs4, Instrs) },
|
|
( { Instrs = Instrs4 } ->
|
|
[]
|
|
;
|
|
opt_debug__msg(DebugOpt, "after duplicate elimination"),
|
|
opt_debug__dump_instrs(DebugOpt, Instrs)
|
|
)
|
|
;
|
|
{ Instrs = Instrs4 }
|
|
),
|
|
{ Mod1 = no, Mod2 = no, Mod3 = no, Instrs = Instrs0 ->
|
|
Mod = no
|
|
;
|
|
Mod = yes
|
|
},
|
|
globals__io_lookup_bool_option(statistics, Statistics),
|
|
maybe_report_stats(Statistics).
|
|
|
|
:- pred optimize__middle(list(instruction)::in, bool::in, set(label)::in,
|
|
list(instruction)::out, io__state::di, io__state::uo) is det.
|
|
|
|
optimize__middle(Instrs0, Final, LayoutLabelSet, Instrs) -->
|
|
globals__io_lookup_bool_option(very_verbose, VeryVerbose),
|
|
globals__io_lookup_bool_option(debug_opt, DebugOpt),
|
|
{ opt_util__find_first_label(Instrs0, Label) },
|
|
{ opt_util__format_label(Label, LabelStr) },
|
|
|
|
globals__io_lookup_bool_option(optimize_frames, FrameOpt),
|
|
( { FrameOpt = yes } ->
|
|
( { VeryVerbose = yes } ->
|
|
io__write_string("% Optimizing frames for "),
|
|
io__write_string(LabelStr),
|
|
io__write_string("\n")
|
|
;
|
|
[]
|
|
),
|
|
{ frameopt_main(Instrs0, Instrs1, Mod1, Jumps) },
|
|
( { Mod1 = yes } ->
|
|
opt_debug__msg(DebugOpt, "after frame optimization"),
|
|
opt_debug__dump_instrs(DebugOpt, Instrs1)
|
|
;
|
|
[]
|
|
),
|
|
globals__io_lookup_bool_option(optimize_fulljumps, FullJumpopt),
|
|
globals__io_lookup_bool_option(checked_nondet_tailcalls,
|
|
CheckedNondetTailCalls),
|
|
( { Jumps = yes, FullJumpopt = yes } ->
|
|
( { VeryVerbose = yes } ->
|
|
io__write_string("% Optimizing jumps for "),
|
|
io__write_string(LabelStr),
|
|
io__write_string("\n")
|
|
;
|
|
[]
|
|
),
|
|
{ jumpopt_main(Instrs1, FullJumpopt, Final,
|
|
CheckedNondetTailCalls, Instrs2, Mod2) },
|
|
( { Mod2 = yes } ->
|
|
opt_debug__msg(DebugOpt, "after jump optimization"),
|
|
opt_debug__dump_instrs(DebugOpt, Instrs2)
|
|
;
|
|
[]
|
|
)
|
|
;
|
|
{ Instrs2 = Instrs1 }
|
|
),
|
|
( { Mod1 = yes } ->
|
|
( { VeryVerbose = yes } ->
|
|
io__write_string("% Optimizing labels for "),
|
|
io__write_string(LabelStr),
|
|
io__write_string("\n")
|
|
;
|
|
[]
|
|
),
|
|
{ labelopt_main(Instrs2, Final, LayoutLabelSet,
|
|
Instrs, Mod3) },
|
|
( { Mod3 = yes } ->
|
|
opt_debug__msg(DebugOpt, "after label optimization"),
|
|
opt_debug__dump_instrs(DebugOpt, Instrs)
|
|
;
|
|
[]
|
|
)
|
|
;
|
|
{ Instrs = Instrs2 }
|
|
)
|
|
;
|
|
{ Instrs = Instrs0 }
|
|
).
|
|
|
|
:- pred optimize__last(list(instruction)::in, set(label)::in,
|
|
list(instruction)::out, io__state::di, io__state::uo) is det.
|
|
|
|
optimize__last(Instrs0, LayoutLabelSet, Instrs) -->
|
|
globals__io_lookup_bool_option(very_verbose, VeryVerbose),
|
|
globals__io_lookup_bool_option(debug_opt, DebugOpt),
|
|
{ opt_util__find_first_label(Instrs0, Label) },
|
|
{ opt_util__format_label(Label, LabelStr) },
|
|
|
|
globals__io_lookup_bool_option(optimize_delay_slot, DelaySlot),
|
|
globals__io_lookup_bool_option(optimize_value_number, ValueNumber),
|
|
( { DelaySlot = yes ; ValueNumber = yes } ->
|
|
% We must get rid of any extra labels added by other passes,
|
|
% since they can confuse both post_value_number and delay_slot.
|
|
( { VeryVerbose = yes } ->
|
|
io__write_string("% Optimizing labels for "),
|
|
io__write_string(LabelStr),
|
|
io__write_string("\n")
|
|
;
|
|
[]
|
|
),
|
|
{ labelopt_main(Instrs0, no, LayoutLabelSet, Instrs1, Mod1) },
|
|
( { Mod1 = yes } ->
|
|
opt_debug__msg(DebugOpt, "after label optimization"),
|
|
opt_debug__dump_instrs(DebugOpt, Instrs1)
|
|
;
|
|
[]
|
|
)
|
|
;
|
|
{ Instrs1 = Instrs0 }
|
|
),
|
|
( { DelaySlot = yes } ->
|
|
( { VeryVerbose = yes } ->
|
|
io__write_string("% Optimizing delay slot for "),
|
|
io__write_string(LabelStr),
|
|
io__write_string("\n")
|
|
;
|
|
[]
|
|
),
|
|
{ fill_branch_delay_slot(Instrs1, Instrs2) },
|
|
( { Instrs1 = Instrs0 } ->
|
|
opt_debug__msg(DebugOpt, "after delay slot filling"),
|
|
opt_debug__dump_instrs(DebugOpt, Instrs2)
|
|
;
|
|
[]
|
|
)
|
|
;
|
|
{ Instrs2 = Instrs1 }
|
|
),
|
|
( { ValueNumber = yes } ->
|
|
( { VeryVerbose = yes } ->
|
|
io__write_string("% Optimizing post value number for "),
|
|
io__write_string(LabelStr),
|
|
io__write_string("\n")
|
|
;
|
|
[]
|
|
),
|
|
{ value_number__post_main(Instrs2, Instrs) },
|
|
( { Instrs = Instrs2 } ->
|
|
[]
|
|
;
|
|
opt_debug__msg(DebugOpt, "after post value number"),
|
|
opt_debug__dump_instrs(DebugOpt, Instrs)
|
|
)
|
|
;
|
|
{ Instrs = Instrs1 }
|
|
).
|