mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-17 06:47:17 +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.
155 lines
4.8 KiB
Mathematica
155 lines
4.8 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1997-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.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Main author: zs.
|
|
%
|
|
% This module defines a representation for basic blocks, sequences of
|
|
% instructions with one entry and one exit, and provides predicates
|
|
% that convert a list of instructions into a list of basic blocks
|
|
% and vice versa.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module basic_block.
|
|
|
|
:- interface.
|
|
|
|
:- import_module llds.
|
|
:- import_module list, map, std_util.
|
|
|
|
:- type block_map == map(label, block_info).
|
|
|
|
:- type block_info
|
|
---> block_info(
|
|
label,
|
|
% The label starting the block.
|
|
instruction,
|
|
% The instruction containing the label.
|
|
list(instruction),
|
|
% The code of the block without the initial
|
|
% label.
|
|
list(label),
|
|
% The labels we can jump to
|
|
% (not falling through).
|
|
maybe(label)
|
|
% The label we fall through to
|
|
% (if there is one).
|
|
).
|
|
|
|
:- pred create_basic_blocks(list(instruction)::in, list(instruction)::out,
|
|
proc_label::out, int::out, list(label)::out, block_map::out) is det.
|
|
|
|
:- pred flatten_basic_blocks(list(label)::in, block_map::in,
|
|
list(instruction)::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module opt_util.
|
|
:- import_module bool, int, require.
|
|
|
|
create_basic_blocks(Instrs0, Comments, ProcLabel, N,
|
|
LabelSeq, BlockMap) :-
|
|
opt_util__get_prologue(Instrs0, ProcLabel, LabelInstr,
|
|
Comments, AfterLabelInstrs),
|
|
Instrs1 = [LabelInstr | AfterLabelInstrs],
|
|
opt_util__new_label_no(Instrs0, 1000, N0),
|
|
map__init(BlockMap0),
|
|
build_block_map(Instrs1, LabelSeq, BlockMap0, BlockMap,
|
|
ProcLabel, N0, N).
|
|
|
|
% Add labels to the given instruction sequence so that
|
|
% every basic block has labels around it.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred build_block_map(list(instruction)::in, list(label)::out,
|
|
block_map::in, block_map::out, proc_label::in, int::in, int::out)
|
|
is det.
|
|
|
|
build_block_map([], [], BlockMap, BlockMap, _, N, N).
|
|
build_block_map([OrigInstr0 | OrigInstrs0], LabelSeq, BlockMap0, BlockMap,
|
|
ProcLabel, N0, N) :-
|
|
( OrigInstr0 = label(OrigLabel) - _ ->
|
|
Label = OrigLabel,
|
|
LabelInstr = OrigInstr0,
|
|
RestInstrs = OrigInstrs0,
|
|
N1 = N0
|
|
;
|
|
N1 is N0 + 1,
|
|
Label = local(ProcLabel, N0),
|
|
LabelInstr = label(Label) - "",
|
|
RestInstrs = [OrigInstr0 | OrigInstrs0]
|
|
),
|
|
(
|
|
take_until_end_of_block(RestInstrs, BlockInstrs, Instrs1),
|
|
build_block_map(Instrs1, LabelSeq0,
|
|
BlockMap0, BlockMap1, ProcLabel, N1, N),
|
|
( list__last(BlockInstrs, LastInstr) ->
|
|
LastInstr = LastUinstr - _,
|
|
possible_targets(LastUinstr, SideLabels),
|
|
opt_util__can_instr_fall_through(LastUinstr,
|
|
CanFallThrough),
|
|
( CanFallThrough = yes ->
|
|
get_fallthrough_from_seq(LabelSeq0,
|
|
MaybeFallThrough)
|
|
;
|
|
MaybeFallThrough = no
|
|
)
|
|
;
|
|
SideLabels = [],
|
|
get_fallthrough_from_seq(LabelSeq0,
|
|
MaybeFallThrough)
|
|
),
|
|
BlockInfo = block_info(Label, LabelInstr, BlockInstrs,
|
|
SideLabels, MaybeFallThrough),
|
|
map__det_insert(BlockMap1, Label, BlockInfo, BlockMap),
|
|
LabelSeq = [Label | LabelSeq0]
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred take_until_end_of_block(list(instruction)::in,
|
|
list(instruction)::out, list(instruction)::out) is det.
|
|
|
|
take_until_end_of_block([], [], []).
|
|
take_until_end_of_block([Instr0 | Instrs0], BlockInstrs, Rest) :-
|
|
Instr0 = Uinstr0 - _Comment,
|
|
( Uinstr0 = label(_) ->
|
|
BlockInstrs = [],
|
|
Rest = [Instr0 | Instrs0]
|
|
; opt_util__can_instr_branch_away(Uinstr0, yes) ->
|
|
BlockInstrs = [Instr0],
|
|
Rest = Instrs0
|
|
;
|
|
take_until_end_of_block(Instrs0, BlockInstrs1, Rest),
|
|
BlockInstrs = [Instr0 | BlockInstrs1]
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred get_fallthrough_from_seq(list(label)::in, maybe(label)::out) is det.
|
|
|
|
get_fallthrough_from_seq(LabelSeq, MaybeFallThrough) :-
|
|
( LabelSeq = [NextLabel | _] ->
|
|
MaybeFallThrough = yes(NextLabel)
|
|
;
|
|
MaybeFallThrough = no
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
flatten_basic_blocks([], _, []).
|
|
flatten_basic_blocks([Label | Labels], BlockMap, Instrs) :-
|
|
flatten_basic_blocks(Labels, BlockMap, RestInstrs),
|
|
map__lookup(BlockMap, Label, BlockInfo),
|
|
BlockInfo = block_info(_, BlockLabelInstr, BlockInstrs, _, _),
|
|
list__append([BlockLabelInstr | BlockInstrs], RestInstrs, Instrs).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|