mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-15 05:44:58 +00:00
Estimated hours taken: 40
Support line numbers in the debugger. You now get contexts (filename:lineno
pairs) printed in several circumstances, and you can put breakpoints on
contexts, when they correspond to trace events or to calls. The latter are
implemented as breakpoints on the label layouts of the return sites.
This required extending the debugging RTTI, so that associated with each
module there is now a new data structure listing the source file names that
contribute labels with layout structures to the code of the module. For each
such source file, this table gives a list of all such labels arising from
that file. The table entry for a label gives the line number within the file,
and the pointer to the label layout structure.
compiler/llds.m:
Add a context field to the call instruction.
compiler/continuation_info.m:
Instead of the old division of continuation info about labels into
trace ports and everything else, divide them into trace ports, resume
points and return sites. Record contexts with trace ports, and record
contexts and called procedure information with return sites.
compiler/code_info.m:
Conform to the changes in continuation_info.m.
compiler/options.m:
Add a new option that allows us to disable the generation of line
number information for size benchmarking (it has no other use).
compiler/stack_layout.m:
Generate the new components of the RTTI, unless the option says not to.
compiler/code_gen.m:
compiler/pragma_c_gen.m:
compiler/trace.m:
Include contexts in the information we gather for the layouts
associated with the events we generate.
compiler/call_gen.m:
Include contexts in the call LLDS instructions, for association
with the return site's label layout structure (which is done after
code generation is finished).
compiler/handle_options.m:
Delete the code that tests or sets the deleted options.
compiler/mercury_compile.m:
Delete the code that tests the deleted options.
compiler/basic_block.m:
compiler/dupelim.m:
compiler/frameopt.m:
compiler/livemap.m:
compiler/llds_common.m:
compiler/llds_out.m:
compiler/middle_rec.m:
compiler/opt_debug.m:
compiler/opt_util.m:
compiler/value_number.m:
compiler/vn_*.m:
Trivial changes to conform to the changes to llds.m.
compiler/jumpopt.m:
Do not optimize away jumps to labels with layout structures.
The jumps we are particularly concerned about now are the jumps
that return from procedure calls. Previously, it was okay to redirect
returns from several calls so that all go to the same label, since
the live variable information associated with the labels could be
merged. However, we now also associate line numbers with calls, and
these cannot be usefully merged.
compiler/optimize.m:
Pass the information required by jumpopt to it.
doc/user_guide.texi:
Document that you can now break at line numbers.
Document the new "context" command, and the -d or --detailed option
of the stack command and the commands that set ancestor levels.
runtime/mercury_stack_layout.h:
Extend the module layout structure definition with the new tables.
Remove the conditional facility for including label numbers in label
layout structures. It hasn't been used in a long time, and neither
Tyson or me expect to use it to debug either gc or the debugger itself,
so it has no uses left; the line numbers have superseded it.
runtime/mercury_stack_trace.[ch]:
Extend the code to print stack traces to also optionally print
contexts.
Add some utility predicates currently used by the debugger that could
also be use for debugging gc or for more detailed stack traces.
trace/mercury_trace_internal.c:
Implement the "break <context>" command, the "context" command, and
the -d or --detailed option of the stack command and the commands
that set ancestor levels.
Conditionally define a conditionally used variable.
trace/mercury_trace_external.c:
Minor changes to keep up with the changes to stack traces.
Delete an unused variable.
trace/mercury_trace_spy.[ch]:
Check for breakpoints on contexts.
trace/mercury_trace_tables.[ch]:
Add functions to search the RTTI data structures for labels
corresponding to a given context.
trace/mercury_trace_vars.[ch]:
Remember the context of the current environment.
tests/debugger/queen.{inp,exp}:
Test the new capabilities of the debugger.
tests/debugger/*.{inp,exp}:
Update the expected output of the debugger to account for contexts.
In some cases, modify the input script to put contexts where they don't
overflow lines.
366 lines
10 KiB
Mathematica
366 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, LayoutLabelSet, 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, LayoutLabelSet, 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 }
|
|
).
|