for review: an even bigger step towards the debugger (part 3 of 4)

Zoltan Somogyi zs at cs.mu.OZ.AU
Wed Apr 1 17:11:29 AEST 1998


Index: compiler/stack_layout.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/stack_layout.m,v
retrieving revision 1.9
diff -u -u -r1.9 stack_layout.m
--- stack_layout.m	1998/03/11 05:10:05	1.9
+++ stack_layout.m	1998/04/01 03:53:06
@@ -34,7 +34,7 @@
 % 					(the location will be set to -1
 % 					if there is no succip available).
 %
-% if the option procid_stack_layout is set, i.e. if we are doing stack
+% If the option procid_stack_layout is set, i.e. if we are doing stack
 % tracing, execution tracing or profiling, the table will also include
 % information on the identity of the procedure. This information will take
 % one of two forms. Almost all procedures use the first form:
@@ -63,36 +63,18 @@
 % The meanings of the fields in both forms are the same as in procedure labels.
 %
 % If the option trace_stack_layout is set, i.e. if we are doing execution
-% tracing, the table will also include information on the variables that are
-% live at entry to and exit from the procedure:
+% tracing, the table will also include one extra field:
 %
-% 	# of live vars at entry	(Integer)
-% 	live data pairs 	(Word *) - pointer to vector of pairs
-%				containing MR_Live_Lval and MR_Live_Type
-% 	live data names	 	(Word *) - pointer to vector of String
-%	type parameters		(Word *) - pointer to vector of MR_Live_Lval
+%	call trace info		(Word *) - pointer to label stack layout
 %
-% 	# of live vars at exit	(Integer)
-% 	live data pairs 	(Word *) - pointer to vector of pairs
-%				containing MR_Live_Lval and MR_Live_Type
-% 	live data names	 	(Word *) - pointer to vector of String
-%	type parameters		(Word *) - pointer to vector of MR_Live_Lval
-%
-% The live data pair vector will have an entry for each live variable.
-% The entry will give the location of the variable and its type (it also
-% has room for its instantiation state, but this is not filled in yet).
-%
-% The live data name vector pointer may be NULL. If it is not, the vector
-% will have an entry for each live variable, with each entry being either
-% NULL or giving the name of the variable.
-%
-% The number of type parameters is never stored as it is not needed --
-% the type parameter vector will simply be indexed by the type parameter
-% number stored within pseudo-typeinfos inside the elements of the live
-% data pairs vectors.
+% This will point to the per-label layout info for the label associated
+% with the call event at the entry to the procedure. The purpose of this
+% information is to allow the runtime debugger to find out which variables
+% are where on entry, so it can reexecute the procedure if asked to do so
+% and if the values of the required variables are still available.
 %
 % If the option basic_stack_layout is set, we generate stack layout tables
-% for all labels internal to the procedure. This table will be stored in the
+% for some labels internal to the procedure. This table will be stored in the
 % global variable whose name is
 %	mercury_data__stack_layout__mercury__<proc_label>_i<label_number>.
 % This table has the following format:
@@ -103,29 +85,49 @@
 % 	live data pairs 	(Word *) - pointer to vector of pairs
 %				containing MR_Live_Lval and MR_Live_Type
 % 	live data names	 	(Word *) - pointer to vector of String
-% 	live data names	 	(Word *) - pointer to vector of String
 %	type parameters		(Word *) - pointer to vector of MR_Live_Lval
 %
-% We need detailed information about the variables that are live at an internal
-% label in two kinds of circumstances:
+% The internal label number field is just for the convenience of those
+% implementors who are debugging stack layout dependent code. It holds
+% either the label number, or -1 indicating the entry label.
+%
+% The live data pair vector will have an entry for each live variable.
+% The entry will give the location of the variable and its type. (It also
+% has room for its instantiation state, but this is not filled in yet.)
+%
+% The live data name vector pointer will be NULL. If it is not, the vector
+% will have an entry for each live variable, with each entry giving the name
+% of the variable (it is either a pointer to a string, or a NULL pointer,
+% which means that the variable has no name).
 %
-% -	the option trace_stack_layout is set, and the label represents
-%	a traced event (with the current set of events, this means the
-%	the entrance to one branch of a branched control structure)
+% The number of type parameters is never stored as it is not needed --
+% the type parameter vector will simply be indexed by the type variable's
+% variable number stored within pseudo-typeinfos inside the elements
+% of the live data pairs vectors. Since we allocate type variable numbers
+% sequentially, the type parameter vector will usually be dense. However,
+% after all variables whose types include e.g. type variable 2 have gone
+% out of scope, variables whose types include type variable 3 may still
+% be around.
+%
+% We need detailed information about the variables that are live at an
+% internal label in two kinds of circumstances. Stack layout information
+% will be present only for labels that fall into one or both of these
+% circumstances.
+%
+% -	The option trace_stack_layout is set, and the label represents
+%	a traced event at which variable info is needed (call, exit,
+%	or entrance to one branch of a branched control structure;
+%	fail events have no variable information).
 %
-% -	the option agc_stack_layout is set, and the label represents
+% -	The option agc_stack_layout is set, and the label represents
 % 	a point where execution can resume after a procedure call or
 %	after backtracking.
 %
-% If either of these conditions holds for a given label at which there are some
-% live variables, all the fields above will be present in the stack layout
-% table for that label. However, the pointer to the live data names vector
-% will be NULL unless the first condition holds for the label (i.e. the label
-% is used in execution tracing).
-%
-% If neither condition holds for a given label, or if the number of live
-% variables at that label is zero, then the "# of live vars" field will be zero
-% and the last four fields will not be present.
+% If there are no number of live variables at a label, the "# of live vars"
+% field will be zero and the last four fields will not be present.
+% Even if there are some live variables at a label, however, the pointer
+% to the live data names vector will be NULL unless the first condition
+% holds for the label (i.e. the label is used in execution tracing).
 %
 % XXX: Presently, type parameter vectors are not created, and
 % inst information is ignored. We also do not yet enable procid stack
@@ -137,17 +139,18 @@
 
 :- interface.
 
-:- import_module hlds_module, list, llds.
+:- import_module hlds_module, llds.
+:- import_module list, set_bbbtree.
 
-:- pred stack_layout__generate_llds(module_info, module_info, list(c_module)).
-:- mode stack_layout__generate_llds(in, out, out) is det.
+:- pred stack_layout__generate_llds(module_info::in, module_info::out,
+	list(c_module)::out, set_bbbtree(label)::out) is det.
 
 :- implementation.
 
 :- import_module globals, options, continuation_info, llds_out.
 :- import_module hlds_data, hlds_pred, base_type_layout, prog_data, prog_out.
-:- import_module assoc_list, bool, string, int, map, std_util, require.
-:- import_module set.
+:- import_module assoc_list, bool, string, int, require.
+:- import_module map, std_util, term, set.
 
 :- type stack_layout_info 	--->	
 	stack_layout_info(
@@ -156,16 +159,21 @@
 		bool,		% generate agc layout info?
 		bool,		% generate tracing layout info?
 		bool,		% generate procedure id layout info?
-		list(c_module)	% generated data
+		list(c_module),	% generated data
+		set_bbbtree(label)
+				% the set of labels with stack layouts
 	).
 
 %---------------------------------------------------------------------------%
 
-	% Initialize the StackLayoutInfo, and begin processing.
-stack_layout__generate_llds(ModuleInfo0, ModuleInfo, CModules) :-
+	% Process all the continuation information stored in the HLDS,
+	% converting it into LLDS data structures.
+
+stack_layout__generate_llds(ModuleInfo0, ModuleInfo, CModules,
+		StackLayoutLabels) :-
 	module_info_get_continuation_info(ModuleInfo0, ContinuationInfo),
-	continuation_info__get_all_proc_layouts(ProcLayoutList,
-		ContinuationInfo, _),
+	continuation_info__get_all_proc_layouts(ContinuationInfo,
+		ProcLayoutList),
 
 	module_info_name(ModuleInfo0, ModuleName),
 	module_info_get_cell_count(ModuleInfo0, CellCount),
@@ -174,61 +182,77 @@
 	globals__lookup_bool_option(Globals, trace_stack_layout, TraceLayout),
 	globals__lookup_bool_option(Globals, procid_stack_layout,
 		ProcInfoLayout),
+	set_bbbtree__init(StackLayoutLabels0),
 
 	LayoutInfo0 = stack_layout_info(ModuleName, CellCount, AgcLayout,
-		TraceLayout, ProcInfoLayout, []),
+		TraceLayout, ProcInfoLayout, [], StackLayoutLabels0),
 	list__foldl(stack_layout__construct_layouts, ProcLayoutList,
 		LayoutInfo0, LayoutInfo),
 
 	stack_layout__get_cmodules(CModules, LayoutInfo, _),
+	stack_layout__get_label_set(StackLayoutLabels, LayoutInfo, _),
 	stack_layout__get_cell_number(FinalCellCount, LayoutInfo, _),
 	module_info_set_cell_count(ModuleInfo0, FinalCellCount, ModuleInfo).
 
 %---------------------------------------------------------------------------%
 
-	% Construct the layouts for a single procedure.
+	% Construct the layouts that concern a single procedure:
+	% the procedure-specific layout and the layouts of the labels
+	% inside that procedure.
 	
 :- pred stack_layout__construct_layouts(proc_layout_info::in,
-		stack_layout_info::in, stack_layout_info::out) is det.
+	stack_layout_info::in, stack_layout_info::out) is det.
 
 stack_layout__construct_layouts(ProcLayoutInfo) -->
-
-	{ ProcLayoutInfo = proc_layout_info(MaybeGeneralInfo, InternalMap,
-		EntryInfo, ExitInfo) },
-
-	( { MaybeGeneralInfo = yes(GeneralInfo) } ->
-		stack_layout__construct_proc_layout(GeneralInfo, EntryInfo,
-			ExitInfo),
-		{ GeneralInfo = proc_layout_general_info(ProcLabel, _, _, _) },
-		{ map__to_assoc_list(InternalMap, Internals) },
-		list__foldl(stack_layout__construct_internal_layout(ProcLabel),
-			Internals)
-	;
-		{ error("stack_layout__construct_layouts: uninitialized proc layout") }
-	).
+	{ ProcLayoutInfo = proc_layout_info(ProcLabel, Detism,
+		StackSlots, SuccipLoc, CallLabel, InternalMap) },
+	stack_layout__construct_proc_layout(ProcLabel, Detism,
+		StackSlots, SuccipLoc, CallLabel),
+	{ map__to_assoc_list(InternalMap, Internals) },
+	list__foldl(stack_layout__construct_internal_layout(ProcLabel),
+		Internals).
 
 %---------------------------------------------------------------------------%
 
-	% Construct the layout describing a single procedure.
+	% Construct a procedure-specific layout.
+
+:- pred stack_layout__construct_proc_layout(proc_label::in,
+	determinism::in, int::in, maybe(int)::in, maybe(label)::in,
+	stack_layout_info::in, stack_layout_info::out) is det.
 
-:- pred stack_layout__construct_proc_layout(proc_layout_general_info::in,
-		maybe(continuation_label_info)::in,
-		maybe(continuation_label_info)::in,
-		stack_layout_info::in, stack_layout_info::out) is det.
-
-stack_layout__construct_proc_layout(GeneralInfo, MaybeEntryInfo,
-		MaybeExitInfo) -->
-	{ GeneralInfo = proc_layout_general_info(ProcLabel, Detism,
-		StackSlots, SuccipLoc) },
+stack_layout__construct_proc_layout(ProcLabel, Detism, StackSlots,
+		MaybeSuccipLoc, MaybeCallLabel) -->
 	{
-		SuccipLoc = yes(Location0)
+		MaybeSuccipLoc = yes(Location0)
 	->
 		Location = Location0
 	;
 			% Use a dummy location of -1 if there is
-			% no succip on the stack. The runtime system
-			% might be able to work around this, depending
-			% upon what it is using the stack layouts for.
+			% no succip on the stack.
+			%
+			% This case can arise in two circumstances.
+			% First, procedures that use the nondet stack
+			% have a special slot for the succip, so the
+			% succip is not stored in a general purpose
+			% slot. Second, procedures that use the det stack
+			% but which do not call other procedures
+			% do not save the succip on the stack.
+			%
+			% The tracing system does not care about the
+			% location of the saved succip. The accurate
+			% garbage collector does. It should know from
+			% the determinism that the procedure uses the
+			% nondet stack, which takes care of the first
+			% possibility above. Procedures that do not call
+			% other procedures do not establish resumption
+			% points and thus agc is not interested in them.
+			% As far as stack dumps go, calling error counts
+			% as a call, so any procedure that may call error
+			% (directly or indirectly) will have its saved succip
+			% location recorded, so the stack dump will work.
+			%
+			% Future uses of stack layouts will have to have
+			% similar constraints.
 		Location = -1
 	},
 	{ determinism_components(Detism, _, at_most_many) ->
@@ -244,32 +268,37 @@
 	{ stack_layout__represent_determinism(Detism, DetismRval) },
 	{ MaybeRvals0 = [yes(CodeAddrRval), yes(DetismRval),
 		yes(StackSlotsRval), yes(SuccipRval)] },
-	stack_layout__get_module_name(ModuleName),
 
 	stack_layout__get_procid_stack_layout(ProcIdLayout),
 	(
 		{ ProcIdLayout = yes }
 	->
 		{ stack_layout__construct_procid_rvals(ProcLabel, IdRvals) },
-		{ list__append(MaybeRvals0, IdRvals, MaybeRvals1) },
+		{ list__append(MaybeRvals0, IdRvals, MaybeRvals1) }
+	;
+		{ MaybeRvals1 = MaybeRvals0 }
+	),
 
-		stack_layout__get_trace_stack_layout(TraceLayout),
-		(
-			{ TraceLayout = yes }
-		->
-			stack_layout__construct_trace_rvals(MaybeEntryInfo,
-				MaybeExitInfo, TraceRvals),
-			{ list__append(MaybeRvals1, TraceRvals, MaybeRvals) }
+	stack_layout__get_module_name(ModuleName),
+	stack_layout__get_trace_stack_layout(TraceLayout),
+	(
+		{ TraceLayout = yes }
+	->
+		( { MaybeCallLabel = yes(CallLabel) } ->
+			{ CallRval = yes(const(data_addr_const(
+				data_addr(ModuleName,
+					stack_layout(CallLabel))))) },
+			{ list__append(MaybeRvals1, [CallRval], MaybeRvals) }
 		;
-			{ MaybeRvals = MaybeRvals1 }
+			{ error("stack_layout__construct_proc_layout: call label not present") }
 		)
 	;
-		{ MaybeRvals = MaybeRvals0 }
+		{ MaybeRvals = MaybeRvals1 }
 	),
 
 	{ CModule = c_data(ModuleName, stack_layout(Label), yes,
 		MaybeRvals, []) },
-	stack_layout__add_cmodule(CModule).
+	stack_layout__add_cmodule(CModule, Label).
 
 %---------------------------------------------------------------------------%
 
@@ -315,7 +344,7 @@
 
 %---------------------------------------------------------------------------%
 
-	% Construct the layout describing a single continuation label.
+	% Construct the layout describing a single internal label.
 
 :- pred stack_layout__construct_internal_layout(proc_label::in,
 	pair(label, internal_layout_info)::in,
@@ -326,74 +355,40 @@
 	stack_layout__get_module_name(ModuleName),
 	{ EntryAddrRval = const(data_addr_const(data_addr(ModuleName,
 		stack_layout(local(ProcLabel))))) },
-
-	stack_layout__construct_agc_rvals(Internal, AgcRvals),
-
-	{ LayoutRvals = [yes(EntryAddrRval) | AgcRvals] },
-
+	{ Label = local(_, LabelNum0) ->
+		LabelNum = LabelNum0
+	;
+		LabelNum = -1
+	},
+	{ LabelNumRval = const(int_const(LabelNum)) },
+	stack_layout__construct_internal_rvals(Internal, AgcRvals),
+	{ LayoutRvals = [yes(EntryAddrRval), yes(LabelNumRval) | AgcRvals] },
 	{ CModule = c_data(ModuleName, stack_layout(Label), yes,
 		LayoutRvals, []) },
-	stack_layout__add_cmodule(CModule).
+	stack_layout__add_cmodule(CModule, Label).
 
-	% Construct the rvals required for tracing.
-
-:- pred stack_layout__construct_trace_rvals(maybe(continuation_label_info)::in,
-	maybe(continuation_label_info)::in, list(maybe(rval))::out,
-	stack_layout_info::in, stack_layout_info::out) is det.
+	% Construct the rvals required for accurate GC or for tracing.
 
-stack_layout__construct_trace_rvals(MaybeEntryInfo, MaybeExitInfo,
-		RvalList) -->
-	(
-		{ MaybeEntryInfo = yes(EntryInfo) },
-		{ MaybeExitInfo = yes(ExitInfo) }
-	->
-		{ EntryInfo = continuation_label_info(EntryLvals, EntryTVars) },
-		{ ExitInfo = continuation_label_info(ExitLvals, ExitTVars) },
-		stack_layout__construct_livelval_rvals(EntryLvals, EntryTVars,
-			EntryRvals),
-		stack_layout__construct_livelval_rvals(ExitLvals, ExitTVars,
-			ExitRvals),
-		{ list__append(EntryRvals, ExitRvals, RvalList) }
-	;
-		{ error("stack_layout__construct_trace_rvals: entry or exit information not available.") }
-	).
-
-	% Construct the rvals required for accurate GC.
-
-:- pred stack_layout__construct_agc_rvals(internal_layout_info::in,
+:- pred stack_layout__construct_internal_rvals(internal_layout_info::in,
 	list(maybe(rval))::out,
 	stack_layout_info::in, stack_layout_info::out) is det.
 
-stack_layout__construct_agc_rvals(Internal, RvalList) -->
-	stack_layout__get_agc_stack_layout(AgcStackLayout),
+stack_layout__construct_internal_rvals(Internal, RvalList) -->
 	(
-		{ AgcStackLayout = yes }
+		{ Internal = yes(layout_label_info(LiveLvalSet, TVars)) }
 	->
-		{ Internal = internal_layout_info(ContinuationLabelInfo) },
-		{
-			ContinuationLabelInfo = yes(continuation_label_info(
-				LiveLvalSet0, TVars0))
-		->
-			LiveLvalSet = LiveLvalSet0,
-			TVars = TVars0
-		;
-			% This label is not being used as a continuation,
-			% or we are not doing accurate GC, so we record
-			% no live values here.
-			% This might not be a true reflection of the
-			% liveness at this point, so the values cannot
-			% be relied upon by the runtime system unless
-			% you know you are at a continuation (and doing
-			% accurate GC).
-			
-			set__init(LiveLvalSet),
-			set__init(TVars)
-		},
 		stack_layout__construct_livelval_rvals(LiveLvalSet, TVars,
 			RvalList)
 	;
-		{ RvalList = [yes(const(int_const(0))),
-			yes(const(int_const(0)))] }
+		% This label is not being used as a continuation,
+		% or we are not doing accurate GC, so we record
+		% no live values here.
+		% This might not be a true reflection of the
+		% liveness at this point, so the values cannot
+		% be relied upon by the runtime system unless
+		% you know you are at a continuation (and doing
+		% accurate GC).
+		{ RvalList = [yes(const(int_const(0)))] }
 	).
 
 %---------------------------------------------------------------------------%
@@ -403,34 +398,60 @@
 		stack_layout_info, stack_layout_info).
 :- mode stack_layout__construct_livelval_rvals(in, in, out, in, out) is det.
 
-stack_layout__construct_livelval_rvals(LiveLvalSet, TVarSet, RvalList) -->
+stack_layout__construct_livelval_rvals(LiveLvalSet, TVarLocnSet, RvalList) -->
 	{ set__to_sorted_list(LiveLvalSet, LiveLvals) },
 	{ list__length(LiveLvals, Length) },
-	{ LengthRval = const(int_const(Length)) },
-	stack_layout__construct_liveval_pairs(LiveLvals, LiveValRval,
-		NamesRval),
-
-	{ set__to_sorted_list(TVarSet, TVars) },
-	{ assoc_list__values(TVars, TypeParamLvals) },
-	stack_layout__construct_type_parameter_locn_vector(TypeParamLvals,
-		TypeParamRval),
-
-	{ RvalList = [yes(LengthRval), yes(LiveValRval),
-		yes(NamesRval), yes(TypeParamRval)] }.
+	{ VarLengthRval = const(int_const(Length)) },
+	( { Length > 0 } ->
+		stack_layout__construct_liveval_pairs(LiveLvals, LiveValRval,
+			NamesRval),
+
+		{ set__to_sorted_list(TVarLocnSet, TVarLocns) },
+		stack_layout__construct_type_param_locn_vector(TVarLocns, 1,
+			TypeParamLocs),
+		stack_layout__get_next_cell_number(CNum1),
+		{ TypeParamRval = create(0, TypeParamLocs, no, CNum1,
+			"stack_layout_type_param_locn_vector") },
+		{ list__length(TypeParamLocs, TypeParamsLength) },
+		{ TypeParamLengthRval = const(int_const(TypeParamsLength)) },
+
+		{ RvalList = [yes(VarLengthRval), yes(LiveValRval),
+			yes(NamesRval), yes(TypeParamLengthRval),
+			yes(TypeParamRval)] }
+	;
+		{ RvalList = [yes(VarLengthRval)] }
+	).
 
 %---------------------------------------------------------------------------%
 
-:- pred stack_layout__construct_type_parameter_locn_vector(list(lval)::in,
-	rval::out, stack_layout_info::in, stack_layout_info::out) is det.
+	% Given a association list of type variables and their locations
+	% sorted on the type variables, represent them in an array of
+	% location descriptions indexed by the type variable. The next
+	% slot to fill is given by the second argument.
+
+:- pred stack_layout__construct_type_param_locn_vector(
+	assoc_list(tvar, lval)::in, int::in, list(maybe(rval))::out,
+	stack_layout_info::in, stack_layout_info::out) is det.
+
+stack_layout__construct_type_param_locn_vector([], _, []) --> [].
+stack_layout__construct_type_param_locn_vector([TVar - Locn | TVarLocns],
+		CurSlot, Vector) -->
+	{ term__var_to_int(TVar, TVarNum) },
+	{ NextSlot is CurSlot + 1 },
+	( { TVarNum = CurSlot } ->
+		{ stack_layout__represent_lval(Locn, Rval) },
+		stack_layout__construct_type_param_locn_vector(TVarLocns,
+			NextSlot, VectorTail),
+		{ Vector = [yes(Rval) | VectorTail] }
+	; { TVarNum > CurSlot } ->
+		stack_layout__construct_type_param_locn_vector(TVarLocns,
+			NextSlot, VectorTail),
+			% This slot will never be referred to.
+		{ Vector = [yes(const(int_const(0))) | VectorTail] }
+	;
 
-stack_layout__construct_type_parameter_locn_vector(TypeParamLvals,
-		TypeParamVector) -->
-	{ MakeLval = lambda([Lval::in, yes(Rval)::out] is det, (
-		stack_layout__represent_lval(Lval, Rval))) },
-	{ list__map(MakeLval, TypeParamLvals, TypeParamLocs) },
-	stack_layout__get_next_cell_number(CNum1),
-	{ TypeParamVector = create(0, TypeParamLocs, no, CNum1,
-		"stack_layout_type_parameter_locn_vector") }.
+		{ error("unsorted tvars in construct_type_param_locn_vector") }
+	).
 
 	% Construct a vector of (lval, live_value_type) pairs,
 	% and a corresponding vector of variable names.
@@ -488,7 +509,7 @@
 	%
 	% Low integers for special values, a pointer for other values.
 	% (Remember to keep the low integers below the max varint value in
-	% runtime/type_info.h).
+	% runtime/mercury_type_info.h).
 
 :- pred stack_layout__represent_live_value_type(live_value_type, rval,
 	stack_layout_info, stack_layout_info).
@@ -509,8 +530,8 @@
 stack_layout__represent_live_value_type(var(Type, _Inst), Rval) -->
 	stack_layout__get_cell_number(CNum0),
 	{ base_type_layout__construct_pseudo_type_info(Type, Rval0,
-		CNum0, CNum) },
-	stack_layout__set_cell_number(CNum),
+		CNum0, CNum1) },
+	stack_layout__set_cell_number(CNum1),
 		% XXX hack - don't yet write out insts
 	{ Rval1 = const(int_const(-1)) },
 	stack_layout__get_next_cell_number(CNum2),
@@ -633,60 +654,68 @@
 	stack_layout_info::in, stack_layout_info::out) is det.
 
 stack_layout__get_module_name(ModuleName, LayoutInfo, LayoutInfo) :-
-	LayoutInfo = stack_layout_info(ModuleName, _, _, _, _, _).
+	LayoutInfo = stack_layout_info(ModuleName, _, _, _, _, _, _).
 
 :- pred stack_layout__get_next_cell_number(int::out,
 	stack_layout_info::in, stack_layout_info::out) is det.
 
 stack_layout__get_next_cell_number(CNum0, LayoutInfo0, LayoutInfo) :-
-	LayoutInfo0 = stack_layout_info(A, CNum0, C, D, E, F),
+	LayoutInfo0 = stack_layout_info(A, CNum0, C, D, E, F, G),
 	CNum is CNum0 + 1,
-	LayoutInfo = stack_layout_info(A, CNum, C, D, E, F).
+	LayoutInfo = stack_layout_info(A, CNum, C, D, E, F, G).
 
 :- pred stack_layout__get_cell_number(int::out,
 	stack_layout_info::in, stack_layout_info::out) is det.
 
 stack_layout__get_cell_number(CNum, LayoutInfo, LayoutInfo) :-
-	LayoutInfo = stack_layout_info(_, CNum, _, _, _, _).
-
-:- pred stack_layout__get_cmodules(list(c_module)::out,
-	stack_layout_info::in, stack_layout_info::out) is det.
-
-stack_layout__get_cmodules(CModules, LayoutInfo, LayoutInfo) :-
-	LayoutInfo = stack_layout_info(_, _, _, _, _, CModules).
+	LayoutInfo = stack_layout_info(_, CNum, _, _, _, _, _).
 
 :- pred stack_layout__get_agc_stack_layout(bool::out,
 	stack_layout_info::in, stack_layout_info::out) is det.
 
 stack_layout__get_agc_stack_layout(AgcStackLayout, LayoutInfo, LayoutInfo) :-
-	LayoutInfo = stack_layout_info(_, _, AgcStackLayout, _, _, _).
+	LayoutInfo = stack_layout_info(_, _, AgcStackLayout, _, _, _, _).
 
 :- pred stack_layout__get_trace_stack_layout(bool::out,
 	stack_layout_info::in, stack_layout_info::out) is det.
 
 stack_layout__get_trace_stack_layout(TraceStackLayout, LayoutInfo,
 		LayoutInfo) :-
-	LayoutInfo = stack_layout_info(_, _, _, TraceStackLayout, _, _).
+	LayoutInfo = stack_layout_info(_, _, _, TraceStackLayout, _, _, _).
 
 :- pred stack_layout__get_procid_stack_layout(bool::out,
 	stack_layout_info::in, stack_layout_info::out) is det.
 
 stack_layout__get_procid_stack_layout(ProcIdStackLayout, LayoutInfo,
 		LayoutInfo) :-
-	LayoutInfo = stack_layout_info(_, _, _, _, ProcIdStackLayout, _).
+	LayoutInfo = stack_layout_info(_, _, _, _, ProcIdStackLayout, _, _).
+
+:- pred stack_layout__get_cmodules(list(c_module)::out,
+	stack_layout_info::in, stack_layout_info::out) is det.
+
+stack_layout__get_cmodules(CModules, LayoutInfo, LayoutInfo) :-
+	LayoutInfo = stack_layout_info(_, _, _, _, _, CModules, _).
 
-:- pred stack_layout__add_cmodule(c_module::in,
+:- pred stack_layout__get_label_set(set_bbbtree(label)::out,
 	stack_layout_info::in, stack_layout_info::out) is det.
 
-stack_layout__add_cmodule(CModule, LayoutInfo0, LayoutInfo) :-
-	LayoutInfo0 = stack_layout_info(A, B, C, D, E, CModules0),
+stack_layout__get_label_set(StackLayoutLabels, LayoutInfo, LayoutInfo) :-
+	LayoutInfo = stack_layout_info(_, _, _, _, _, _, StackLayoutLabels).
+
+:- pred stack_layout__add_cmodule(c_module::in, label::in,
+	stack_layout_info::in, stack_layout_info::out) is det.
+
+stack_layout__add_cmodule(CModule, Label, LayoutInfo0, LayoutInfo) :-
+	LayoutInfo0 = stack_layout_info(A, B, C, D, E, CModules0,
+		StackLayoutLabels0),
 	CModules = [CModule | CModules0],
-	LayoutInfo = stack_layout_info(A, B, C, D, E, CModules).
+	set_bbbtree__insert(StackLayoutLabels0, Label, StackLayoutLabels),
+	LayoutInfo = stack_layout_info(A, B, C, D, E, CModules,
+		StackLayoutLabels).
 
 :- pred stack_layout__set_cell_number(int::in,
 	stack_layout_info::in, stack_layout_info::out) is det.
 
 stack_layout__set_cell_number(CNum, LayoutInfo0, LayoutInfo) :-
-	LayoutInfo0 = stack_layout_info(A, _, C, D, E, F),
-	LayoutInfo = stack_layout_info(A, CNum, C, D, E, F).
-
+	LayoutInfo0 = stack_layout_info(A, _, C, D, E, F, G),
+	LayoutInfo = stack_layout_info(A, CNum, C, D, E, F, G).
Index: compiler/store_alloc.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/store_alloc.m,v
retrieving revision 1.60
diff -u -u -r1.60 store_alloc.m
--- store_alloc.m	1998/03/24 00:06:59	1.60
+++ store_alloc.m	1998/03/31 10:04:23
@@ -37,7 +37,7 @@
 :- implementation.
 
 :- import_module follow_vars, liveness, hlds_goal, llds.
-:- import_module options, globals, goal_util, mode_util, instmap.
+:- import_module options, globals, goal_util, mode_util, instmap, trace.
 :- import_module list, map, set, std_util, assoc_list.
 :- import_module bool, int, require, term.
 
@@ -60,7 +60,12 @@
 		proc_info_goal(ProcInfo0, Goal2)
 	),
 	initial_liveness(ProcInfo0, ModuleInfo, Liveness0),
-	set__init(ResumeVars0),
+	globals__lookup_bool_option(Globals, generate_trace, Trace),
+	( Trace = yes ->
+		trace__fail_vars(ModuleInfo, ProcInfo0, ResumeVars0)
+	;
+		set__init(ResumeVars0)
+	),
 	store_alloc_in_goal(Goal2, Liveness0, ResumeVars0, ModuleInfo, Goal, _),
 	proc_info_set_goal(ProcInfo0, Goal, ProcInfo).
 
Index: compiler/string_switch.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/string_switch.m,v
retrieving revision 1.28
diff -u -u -r1.28 string_switch.m
--- string_switch.m	1998/03/03 17:36:05	1.28
+++ string_switch.m	1998/03/28 04:05:48
@@ -303,27 +303,16 @@
 		{ LabelCode = node([
 			label(Label) - Comment
 		]) },
-		code_info__get_maybe_trace_info(MaybeTraceInfo),
-		( { MaybeTraceInfo = yes(TraceInfo) } ->
-			{ Goal = _ - GoalInfo },
-			{ goal_info_get_goal_path(GoalInfo, Path) },
-			trace__generate_event_code(switch(Path), TraceInfo,
-				TraceCode)
-		;
-			{ TraceCode = empty }
-		),
+		code_info__grab_code_info(CodeInfo),
+		trace__maybe_generate_internal_event_code(Goal, TraceCode),
+		code_gen__generate_goal(CodeModel, Goal, GoalCode),
+		code_info__generate_branch_end(CodeModel, StoreMap, SaveCode),
 		(
 			{ string_switch__this_is_last_case(Slot, TblSize,
 				HashSlotMap) }
 		->
-			code_gen__generate_goal(CodeModel, Goal, GoalCode),
-			code_info__generate_branch_end(CodeModel, StoreMap,
-				SaveCode)
+			[]
 		;
-			code_info__grab_code_info(CodeInfo),
-			code_gen__generate_goal(CodeModel, Goal, GoalCode),
-			code_info__generate_branch_end(CodeModel, StoreMap,
-				SaveCode),
 			code_info__slap_code_info(CodeInfo)
 		),
 		{ FinishCode = node([
Index: compiler/switch_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/switch_gen.m,v
retrieving revision 1.64
diff -u -u -r1.64 switch_gen.m
--- switch_gen.m	1998/03/03 17:36:06	1.64
+++ switch_gen.m	1998/03/28 04:41:34
@@ -307,21 +307,13 @@
 
 switch_gen__generate_cases([case(_, _, Cons, Goal) | Cases], Var, CodeModel,
 		CanFail, StoreMap, EndLabel, CasesCode) -->
-	code_info__get_maybe_trace_info(MaybeTraceInfo),
-	( { MaybeTraceInfo = yes(TraceInfo) } ->
-		{ Goal = _ - GoalInfo },
-		{ goal_info_get_goal_path(GoalInfo, Path) },
-		trace__generate_event_code(switch(Path), TraceInfo,
-			TraceCode)
-	;
-		{ TraceCode = empty }
-	),
 	code_info__grab_code_info(CodeInfo0),
 	(
 		{ Cases = [_|_] ; CanFail = can_fail }
 	->
 		unify_gen__generate_tag_test(Var, Cons, branch_on_failure,
 			NextLabel, TestCode),
+		trace__maybe_generate_internal_event_code(Goal, TraceCode),
 		code_gen__generate_goal(CodeModel, Goal, GoalCode),
 		code_info__generate_branch_end(CodeModel, StoreMap, SaveCode),
 		{ ElseCode = node([
@@ -340,6 +332,7 @@
 		code_info__grab_code_info(CodeInfo1),
 		code_info__slap_code_info(CodeInfo0)
 	;
+		trace__maybe_generate_internal_event_code(Goal, TraceCode),
 		code_gen__generate_goal(CodeModel, Goal, GoalCode),
 		code_info__generate_branch_end(CodeModel, StoreMap, SaveCode),
 		{ ThisCaseCode =
Index: compiler/tag_switch.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/tag_switch.m,v
retrieving revision 1.43
diff -u -u -r1.43 tag_switch.m
--- tag_switch.m	1998/03/03 17:36:08	1.43
+++ tag_switch.m	1998/03/28 04:11:24
@@ -659,15 +659,8 @@
 	->
 		% There is no secondary tag, so there is no switch on it
 		( { GoalList = [-1 - Goal] } ->
-			code_info__get_maybe_trace_info(MaybeTraceInfo),
-			( { MaybeTraceInfo = yes(TraceInfo) } ->
-				{ Goal = _ - GoalInfo },
-				{ goal_info_get_goal_path(GoalInfo, Path) },
-				trace__generate_event_code(switch(Path),
-					TraceInfo, TraceCode)
-			;
-				{ TraceCode = empty }
-			),
+			trace__maybe_generate_internal_event_code(Goal,
+				TraceCode),
 			code_gen__generate_goal(CodeModel, Goal, GoalCode),
 			code_info__generate_branch_end(CodeModel, StoreMap,
 				SaveCode),
@@ -803,15 +796,6 @@
 tag_switch__generate_secondary_try_me_else_chain([Case0 | Cases0], StagRval,
 		CodeModel, CanFail, StoreMap, EndLabel, FailLabel, Code) -->
 	{ Case0 = Secondary - Goal },
-	code_info__get_maybe_trace_info(MaybeTraceInfo),
-	( { MaybeTraceInfo = yes(TraceInfo) } ->
-		{ Goal = _ - GoalInfo },
-		{ goal_info_get_goal_path(GoalInfo, Path) },
-		trace__generate_event_code(switch(Path), TraceInfo,
-			TraceCode)
-	;
-		{ TraceCode = empty }
-	),
 	( { Cases0 = [_|_] ; CanFail = can_fail } ->
 		code_info__grab_code_info(CodeInfo),
 		code_info__get_next_label(ElseLabel),
@@ -821,6 +805,7 @@
 				label(ElseLabel))
 				- "test remote sec tag only"
 		]) },
+		trace__maybe_generate_internal_event_code(Goal, TraceCode),
 		code_gen__generate_goal(CodeModel, Goal, GoalCode),
 		code_info__generate_branch_end(CodeModel, StoreMap, SaveCode),
 		{ GotoLabelCode = node([
@@ -850,6 +835,7 @@
 			{ Code = tree(ThisCode, FailCode) }
 		)
 	;
+		trace__maybe_generate_internal_event_code(Goal, TraceCode),
 		code_gen__generate_goal(CodeModel, Goal, GoalCode),
 		code_info__generate_branch_end(CodeModel, StoreMap, SaveCode),
 		{ GotoCode = node([
@@ -880,15 +866,6 @@
 		CodeModel, CanFail, StoreMap, EndLabel, FailLabel,
 		PrevTests0, PrevCases0, Code) -->
 	{ Case0 = Secondary - Goal },
-	code_info__get_maybe_trace_info(MaybeTraceInfo),
-	( { MaybeTraceInfo = yes(TraceInfo) } ->
-		{ Goal = _ - GoalInfo },
-		{ goal_info_get_goal_path(GoalInfo, Path) },
-		trace__generate_event_code(switch(Path), TraceInfo,
-			TraceCode)
-	;
-		{ TraceCode = empty }
-	),
 	( { Cases0 = [_|_] ; CanFail = can_fail } ->
 		code_info__grab_code_info(CodeInfo),
 		code_info__get_next_label(ThisStagLabel),
@@ -902,6 +879,7 @@
 			label(ThisStagLabel) -
 				"handle next secondary tag"
 		]) },
+		trace__maybe_generate_internal_event_code(Goal, TraceCode),
 		code_gen__generate_goal(CodeModel, Goal, GoalCode),
 		code_info__generate_branch_end(CodeModel, StoreMap, SaveCode),
 		{ GotoCode = node([
@@ -931,6 +909,7 @@
 			{ Code = tree(PrevTests, tree(FailCode, PrevCases)) }
 		)
 	;
+		trace__maybe_generate_internal_event_code(Goal, TraceCode),
 		code_gen__generate_goal(CodeModel, Goal, GoalCode),
 		code_info__generate_branch_end(CodeModel, StoreMap, SaveCode),
 		{ GotoCode = node([
@@ -976,26 +955,15 @@
 				label(NewLabel) -
 					"start of case in secondary tag switch"
 			]) },
-			code_info__get_maybe_trace_info(MaybeTraceInfo),
-			( { MaybeTraceInfo = yes(TraceInfo) } ->
-				{ Goal = _ - GoalInfo },
-				{ goal_info_get_goal_path(GoalInfo, Path) },
-				trace__generate_event_code(switch(Path),
-					TraceInfo, TraceCode)
-			;
-				{ TraceCode = empty }
-			),
+			code_info__grab_code_info(CodeInfo),
+			trace__maybe_generate_internal_event_code(Goal,
+				TraceCode),
+			code_gen__generate_goal(CodeModel, Goal, GoalCode),
+			code_info__generate_branch_end(CodeModel, StoreMap,
+				SaveCode),
 			( { CaseList1 = [] } ->
-				code_gen__generate_goal(CodeModel, Goal,
-					GoalCode),
-				code_info__generate_branch_end(CodeModel,
-					StoreMap, SaveCode)
+				[]
 			;
-				code_info__grab_code_info(CodeInfo),
-				code_gen__generate_goal(CodeModel, Goal,
-					GoalCode),
-				code_info__generate_branch_end(CodeModel,
-					StoreMap, SaveCode),
 				code_info__slap_code_info(CodeInfo)
 			),
 			{ GotoCode = node([
@@ -1059,15 +1027,8 @@
 			),
 			{ MaybeFinalCodeInfo = MaybeFinalCodeInfo0 }
 		; { StagGoals = [CurSec - Goal] } ->
-			code_info__get_maybe_trace_info(MaybeTraceInfo),
-			( { MaybeTraceInfo = yes(TraceInfo) } ->
-				{ Goal = _ - GoalInfo },
-				{ goal_info_get_goal_path(GoalInfo, Path) },
-				trace__generate_event_code(switch(Path),
-					TraceInfo, TraceCode)
-			;
-				{ TraceCode = empty }
-			),
+			trace__maybe_generate_internal_event_code(Goal,
+				TraceCode),
 			code_gen__generate_goal(CodeModel, Goal, GoalCode),
 			code_info__generate_branch_end(CodeModel, StoreMap,
 				SaveCode),
Index: compiler/trace.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/trace.m,v
retrieving revision 1.7
diff -u -u -r1.7 trace.m
--- trace.m	1998/02/03 08:18:35	1.7
+++ trace.m	1998/03/31 10:50:00
@@ -3,7 +3,9 @@
 % This file may only be copied under the terms of the GNU General
 % Public License - see the file COPYING in the Mercury distribution.
 %-----------------------------------------------------------------------------%
-
+%
+% Author: zs.
+%
 % This module handles the generation of traces for the trace analysis system.
 %
 % For the general basis of trace analysis systems, see the paper
@@ -11,13 +13,31 @@
 % available from http://www.irisa.fr/lande/ducasse.
 %
 % We reserve two slots in the stack frame of the traced procedure.
-% One contains the call sequence number, which is set in the procedure prolog
+% One contains the call sequence number, which is set in the procedure prologue
 % by incrementing a global counter. The other contains the call depth, which
 % is also set by incrementing a global variable containing the depth of the
 % caller. The caller sets this global variable from its own saved depth
 % just before the call.
-
-% Author: zs.
+%
+% Each event has a label associated with it. The stack layout for that label
+% records what variables are live and where they are at the time of the event.
+% These labels are generated by the same predicate that generates the code
+% for the event, and are initially not used for anything else.
+% However, some of these labels may be fallen into from other places,
+% and thus optimization may redirect references from labels to one of these
+% labels. This cannot happen in the opposite direction, due to the reference
+% to each event's label from the event's pragma C code instruction.
+% (This prevents labelopt from removing the label.)
+%
+% We classify events into three kinds: external events (call, exit, fail),
+% internal events (switch, disj, ite_then, ite_else), and nondet pragma C
+% events (first, later). Code_gen.m, which calls this module to generate
+% all external events, checks whether tracing is required before calling us;
+% the predicates handing internal and nondet pragma C events must check this
+% themselves. The predicates generating internal events need the goal
+% following the event as a parameter. For the first and later arms of
+% nondet pragma C code, there is no such hlds_goal, which is why these events
+% need a bit of special treatment.
 
 %-----------------------------------------------------------------------------%
 
@@ -25,42 +45,112 @@
 
 :- interface.
 
-:- import_module hlds_goal, llds, code_info.
-
-:- type trace_port	--->	call
-			;	exit
-			;	fail
-			;	ite_then(goal_path)
-			;	ite_else(goal_path)
-			;	switch(goal_path)
-			;	disj(goal_path).
+:- import_module hlds_goal, hlds_pred, hlds_module.
+:- import_module prog_data, llds, code_info.
+:- import_module assoc_list, set, term.
+
+:- type external_trace_port
+	--->	call
+	;	exit
+	;	fail.
+
+:- type nondet_pragma_trace_port
+	--->	nondet_pragma_first
+	;	nondet_pragma_later.
 
 :- type trace_info.
 
+	% Return the set of input variables whose values should be preserved
+	% until the exit and fail ports. This will be all the input variables,
+	% except those that can be totally clobbered during the evaluation
+	% of the procedure (those partially clobbered may still be of interest,
+	% although to handle them properly we need to record insts in stack
+	% layouts).
+:- pred trace__fail_vars(module_info::in, proc_info::in, set(var)::out) is det.
+
+	% Set up the code generator state for tracing, by reserving
+	% slots for the call number and call depth.
 :- pred trace__setup(code_info::in, code_info::out) is det.
 
+	% Generate code to fill in the slots for the call number and depth.
 :- pred trace__generate_slot_fill_code(trace_info::in, code_tree::out) is det.
 
+	% Generate code to reset the call depth before a call.
 :- pred trace__generate_depth_reset_code(trace_info::in, code_tree::out) is det.
 
-:- pred trace__generate_event_code(trace_port::in, trace_info::in,
+	% If generate_trace is set, generate code for an internal trace event.
+	% This predicate must be called just before generating code for the
+	% given goal.
+:- pred trace__maybe_generate_internal_event_code(hlds_goal::in,
+	code_tree::out, code_info::in, code_info::out) is det.
+
+	% If generate_trace is set, generate code for a nondet pragma C code
+	% trace event.
+:- pred trace__maybe_generate_pragma_event_code(nondet_pragma_trace_port::in,
 	code_tree::out, code_info::in, code_info::out) is det.
 
+	% Generate code for an external trace event.
+	% Besides the trace code, we return the label on which we have hung
+	% the trace liveness information and data on the type variables in the
+	% liveness information, since some of our callers also need this
+	% information.
+:- pred trace__generate_external_event_code(external_trace_port::in,
+	trace_info::in, label::out, assoc_list(tvar, lval)::out, code_tree::out,
+	code_info::in, code_info::out) is det.
+
 :- pred trace__path_to_string(goal_path::in, string::out) is det.
 
 %-----------------------------------------------------------------------------%
 
 :- implementation.
 
-:- import_module hlds_module, hlds_pred, llds_out, code_util, tree.
-:- import_module bool, int, list, std_util, string, require.
+:- import_module continuation_info, type_util, llds_out, tree.
+:- import_module (inst), instmap, inst_match, mode_util.
+:- import_module list, bool, int, string, map, std_util, varset, require.
+
+:- type trace_port
+	--->	call
+	;	exit
+	;	fail
+	;	ite_then
+	;	ite_else
+	;	switch
+	;	disj
+	;	nondet_pragma_first
+	;	nondet_pragma_later.
+
+	% Information specific to a trace port.
+:- type trace_port_info
+	--->	external
+	;	internal(
+			goal_path,	% The path of the goal whose start
+					% this port represents.
+			set(var)	% The pre-death set of this goal.
+		)
+	;	nondet_pragma.
 
+	% Information for tracing that is valid throughout the execution
+	% of a procedure.
 :- type trace_info
 	--->	trace_info(
 			lval,	% stack slot of call sequence number
 			lval	% stack slot of call depth
 		).
 
+trace__fail_vars(ModuleInfo, ProcInfo, FailVars) :-
+	proc_info_headvars(ProcInfo, HeadVars),
+	proc_info_argmodes(ProcInfo, Modes),
+	proc_info_arg_info(ProcInfo, ArgInfos),
+	mode_list_get_final_insts(Modes, ModuleInfo, Insts),
+	(
+		trace__build_fail_vars(HeadVars, Insts, ArgInfos,
+			ModuleInfo, FailVarsList)
+	->
+		set__list_to_set(FailVarsList, FailVars)
+	;
+		error("length mismatch in trace__fail_vars")
+	).
+
 trace__setup -->
 	code_info__get_trace_slot(CallNumSlot),
 	code_info__get_trace_slot(CallDepthSlot),
@@ -89,53 +179,222 @@
 		c_code(Stmt) - ""
 	]).
 
-trace__generate_event_code(Port, TraceInfo, TraceCode) -->
-	code_info__get_pred_id(PredId),
-	code_info__get_proc_id(ProcId),
-	code_info__get_module_info(ModuleInfo),
+trace__maybe_generate_internal_event_code(Goal, Code) -->
+	code_info__get_maybe_trace_info(MaybeTraceInfo),
+	( { MaybeTraceInfo = yes(TraceInfo) } ->
+		{ Goal = _ - GoalInfo },
+		{ goal_info_get_goal_path(GoalInfo, Path) },
+		{ goal_info_get_pre_deaths(GoalInfo, PreDeaths) },
+		{
+			Path = [LastStep | _],
+			(
+				LastStep = switch(_),
+				PortPrime = switch
+			;
+				LastStep = disj(_),
+				PortPrime = disj
+			;
+				LastStep = ite_then,
+				PortPrime = ite_then
+			;
+				LastStep = ite_else,
+				PortPrime = ite_else
+			)
+		->
+			Port = PortPrime
+		;
+			error("trace__generate_internal_event_code: bad path")
+		},
+		trace__generate_event_code(Port, internal(Path, PreDeaths),
+			TraceInfo, _, _, Code)
+	;
+		{ Code = empty }
+	).
+
+trace__maybe_generate_pragma_event_code(PragmaPort, Code) -->
+	code_info__get_maybe_trace_info(MaybeTraceInfo),
+	( { MaybeTraceInfo = yes(TraceInfo) } ->
+		{ trace__convert_nondet_pragma_port_type(PragmaPort, Port) },
+		trace__generate_event_code(Port, nondet_pragma, TraceInfo,
+			_, _, Code)
+	;
+		{ Code = empty }
+	).
+
+trace__generate_external_event_code(ExternalPort, TraceInfo,
+		Label, TvarDataList, Code) -->
+	{ trace__convert_external_port_type(ExternalPort, Port) },
+	trace__generate_event_code(Port, external, TraceInfo,
+		Label, TvarDataList, Code).
+
+:- pred trace__generate_event_code(trace_port::in, trace_port_info::in,
+	trace_info::in, label::out, assoc_list(tvar, lval)::out,
+	code_tree::out, code_info::in, code_info::out) is det.
+
+trace__generate_event_code(Port, PortInfo, TraceInfo, Label, TvarDataList,
+		Code) -->
+	code_info__get_next_label(Label),
+	code_info__get_known_variables(LiveVars0),
 	{
-	code_util__make_proc_label(ModuleInfo, PredId, ProcId, ProcLabel),
-	llds_out__get_label(local(ProcLabel), yes, LabelStr),
+		PortInfo = external,
+		LiveVars = LiveVars0,
+		PathStr = ""
+	;
+		PortInfo = internal(Path, PreDeaths),
+		set__to_sorted_list(PreDeaths, PreDeathList),
+		list__delete_elems(LiveVars0, PreDeathList, LiveVars),
+		trace__path_to_string(Path, PathStr)
+	;
+		PortInfo = nondet_pragma,
+		LiveVars = [],
+		PathStr = ""
+	},
+	code_info__get_varset(VarSet),
+	code_info__get_instmap(InstMap),
+	{ set__init(TvarSet0) },
+	trace__produce_vars(LiveVars, VarSet, InstMap, TvarSet0, TvarSet,
+		VarInfoList, ProduceCode),
+	{ set__to_sorted_list(TvarSet, TvarList) },
+	code_info__variable_locations(VarLocs),
+        code_info__get_proc_info(ProcInfo),
+	{ proc_info_typeinfo_varmap(ProcInfo, TypeInfoMap) },
+	{ trace__find_typeinfos_for_tvars(TvarList, VarLocs, TypeInfoMap,
+		TvarDataList) },
+	code_info__max_reg_in_use(MaxReg),
+	{
+	set__list_to_set(VarInfoList, VarInfoSet),
+	set__list_to_set(TvarDataList, TvarDataSet),
+	LayoutLabelInfo = layout_label_info(VarInfoSet, TvarDataSet),
+	llds_out__get_label(Label, yes, LabelStr),
 	TraceInfo = trace_info(CallNumLval, CallDepthLval),
 	trace__stackref_to_string(CallNumLval, CallNumStr),
 	trace__stackref_to_string(CallDepthLval, CallDepthStr),
 	Quote = """",
 	Comma = ", ",
 	trace__port_to_string(Port, PortStr),
-	( trace__port_path(Port, Path) ->
-		trace__path_to_string(Path, PathStr)
-	;
-		PathStr = ""
-	),
+	IfStmt = "\tif (MR_trace_enabled) {\n",
+	EndStmt = "\t}",
+	SaveStmt = "\t\tsave_transient_registers();\n",
+	RestoreStmt = "\t\trestore_transient_registers();\n",
+	string__int_to_string(MaxReg, MaxRegStr),
 	string__append_list([
-		"MR_trace(",
-		"(const Word *) &mercury_data__stack_layout__", LabelStr, Comma,
-		PortStr, Comma,
+		"\t\tMR_trace((const MR_Stack_Layout_Label *)\n",
+		"\t\t\t&mercury_data__stack_layout__", LabelStr, Comma, "\n",
+		"\t\t\t", PortStr, Comma,
 		CallNumStr, Comma,
-		CallDepthStr, Comma,
-		Quote, PathStr, Quote, ");\n"],
+		CallDepthStr, Comma, "\n",
+		"\t\t\t", Quote, PathStr, Quote, Comma,
+		MaxRegStr, ");\n"],
+		CallStmt),
+	string__append_list([IfStmt, SaveStmt, CallStmt, RestoreStmt, EndStmt],
 		TraceStmt),
-	TraceCode = node([c_code(TraceStmt) - ""])
-	}.
+	TraceCode =
+		node([
+			label(Label)
+				- "A label to hang trace liveness on",
+				% Referring to the label from the pragma_c
+				% prevents the label from being renamed
+				% or optimized away.
+				% The label is before the trace code
+				% because sometimes this pair is preceded
+				% by another label, and this way we can
+				% eliminate this other label.
+			pragma_c([], [pragma_c_raw_code(TraceStmt)],
+				may_call_mercury, yes(Label))
+				- ""
+		]),
+	Code = tree(ProduceCode, TraceCode)
+	},
+	code_info__add_layout_for_label(Label, yes(LayoutLabelInfo)).
+
+:- pred trace__produce_vars(list(var)::in, varset::in, instmap::in,
+	set(tvar)::in, set(tvar)::out, list(var_info)::out, code_tree::out,
+	code_info::in, code_info::out) is det.
+
+trace__produce_vars([], _, _, Tvars, Tvars, [], empty) --> [].
+trace__produce_vars([Var | Vars], VarSet, InstMap, Tvars0, Tvars,
+		[VarInfo | VarInfos], tree(VarCode, VarsCode)) -->
+	code_info__produce_variable_in_reg_or_stack(Var, VarCode, Rval),
+	code_info__variable_type(Var, Type),
+	{
+	( Rval = lval(LvalPrime) ->
+		Lval = LvalPrime
+	;
+		error("var not an lval in trace__produce_vars")
+		% If the value of the variable is known,
+		% we record it as living in a nonexistent location, r0.
+		% The code that interprets layout information must know this.
+		% Lval = reg(r, 0)
+	),
+	varset__lookup_name(VarSet, Var, "V_", Name),
+	instmap__lookup_var(InstMap, Var, Inst),
+	LiveType = var(Type, Inst),
+	VarInfo = var_info(Lval, LiveType, Name),
+	type_util__vars(Type, TypeVars),
+	set__insert_list(Tvars0, TypeVars, Tvars1)
+	},
+	trace__produce_vars(Vars, VarSet, InstMap, Tvars1, Tvars,
+		VarInfos, VarsCode).
+
+	% For each type variable in the given list, find out where the
+	% typeinfo var for that type variable is.
+
+:- pred trace__find_typeinfos_for_tvars(list(tvar)::in,
+	map(var, set(rval))::in, map(tvar, type_info_locn)::in,
+	assoc_list(tvar, lval)::out) is det.
+
+trace__find_typeinfos_for_tvars(TypeVars, VarLocs, TypeInfoMap, TypeInfoDatas)
+		:-
+	map__apply_to_list(TypeVars, TypeInfoMap, TypeInfoLocns),
+	list__map(type_info_locn_var, TypeInfoLocns, TypeInfoVars),
+
+	map__apply_to_list(TypeInfoVars, VarLocs, TypeInfoLvalSets),
+	FindSingleLval = lambda([Set::in, Lval::out] is det, (
+		(
+			set__remove_least(Set, Value, _),
+			Value = lval(Lval0)
+		->
+			Lval = Lval0
+		;
+			error("trace__find_typeinfos_for_tvars: typeinfo var not available")
+		))
+	),
+	list__map(FindSingleLval, TypeInfoLvalSets, TypeInfoLvals),
+	assoc_list__from_corresponding_lists(TypeVars, TypeInfoLvals,
+		TypeInfoDatas).
 
 %-----------------------------------------------------------------------------%
 
-:- pred trace__port_path(trace_port::in, goal_path::out) is semidet.
+:- pred trace__build_fail_vars(list(var)::in, list(inst)::in,
+	list(arg_info)::in, module_info::in, list(var)::out) is semidet.
 
-trace__port_path(ite_then(Path), Path).
-trace__port_path(ite_else(Path), Path).
-trace__port_path(switch(Path),   Path).
-trace__port_path(disj(Path),     Path).
+trace__build_fail_vars([], [], [], _, []).
+trace__build_fail_vars([Var | Vars], [Inst | Insts], [Info | Infos],
+		ModuleInfo, FailVars) :-
+	trace__build_fail_vars(Vars, Insts, Infos, ModuleInfo, FailVars0),
+	Info = arg_info(_Loc, ArgMode),
+	(
+		ArgMode = top_in,
+		\+ inst_is_clobbered(ModuleInfo, Inst)
+	->
+		FailVars = [Var | FailVars0]
+	;
+		FailVars = FailVars0
+	).
+
+%-----------------------------------------------------------------------------%
 
 :- pred trace__port_to_string(trace_port::in, string::out) is det.
 
 trace__port_to_string(call, "MR_PORT_CALL").
 trace__port_to_string(exit, "MR_PORT_EXIT").
 trace__port_to_string(fail, "MR_PORT_FAIL").
-trace__port_to_string(ite_then(_), "MR_PORT_THEN").
-trace__port_to_string(ite_else(_), "MR_PORT_ELSE").
-trace__port_to_string(switch(_),   "MR_PORT_SWITCH").
-trace__port_to_string(disj(_),     "MR_PORT_DISJ").
+trace__port_to_string(ite_then, "MR_PORT_THEN").
+trace__port_to_string(ite_else, "MR_PORT_ELSE").
+trace__port_to_string(switch,   "MR_PORT_SWITCH").
+trace__port_to_string(disj,     "MR_PORT_DISJ").
+trace__port_to_string(nondet_pragma_first, "MR_PORT_PRAGMA_FIRST").
+trace__port_to_string(nondet_pragma_later, "MR_PORT_PRAGMA_LATER").
 
 :- pred trace__code_model_to_string(code_model::in, string::out) is det.
 
@@ -186,3 +445,18 @@
 trace__path_step_to_string(ite_else, "e;").
 trace__path_step_to_string(neg, "~;").
 trace__path_step_to_string(exist, "q;").
+
+:- pred trace__convert_external_port_type(external_trace_port::in,
+	trace_port::out) is det.
+
+trace__convert_external_port_type(call, call).
+trace__convert_external_port_type(exit, exit).
+trace__convert_external_port_type(fail, fail).
+
+:- pred trace__convert_nondet_pragma_port_type(nondet_pragma_trace_port::in,
+	trace_port::out) is det.
+
+trace__convert_nondet_pragma_port_type(nondet_pragma_first,
+	nondet_pragma_first).
+trace__convert_nondet_pragma_port_type(nondet_pragma_later,
+	nondet_pragma_later).
Index: compiler/vn_filter.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/vn_filter.m,v
retrieving revision 1.15
diff -u -u -r1.15 vn_filter.m
--- vn_filter.m	1998/01/13 10:14:09	1.15
+++ vn_filter.m	1998/03/16 04:30:41
@@ -25,7 +25,7 @@
 
 :- implementation.
 
-:- import_module opt_util.
+:- import_module code_util, opt_util.
 :- import_module require, std_util.
 
 	% Look for assignments to temp variables. If possible and profitable,
@@ -38,7 +38,7 @@
 		Instr0 = Uinstr0 - _,
 		Uinstr0 = assign(Temp, Defn),
 		Temp = temp(_, _),
-		opt_util__lvals_in_rval(Defn, Deps),
+		code_util__lvals_in_rval(Defn, Deps),
 		vn_filter__can_substitute(Instrs0, Temp, Defn, Deps,
 			Instrs1)
 	->
@@ -73,7 +73,7 @@
 	Instr0 = Uinstr0 - Comment,
 	(
 		vn_filter__user_instr(Uinstr0, yes(Rval)),
-		opt_util__lvals_in_rval(Rval, Lvals),
+		code_util__lvals_in_rval(Rval, Lvals),
 		list__delete_first(Lvals, Temp, OtherLvals)
 	->
 		% We don't want to perform the subsitution
@@ -81,7 +81,7 @@
 		\+ list__member(Temp, OtherLvals),
 		\+ (
 			vn_filter__defining_instr(Uinstr0, yes(Lval)),
-			opt_util__lvals_in_lval(Lval, AccessLvals),
+			code_util__lvals_in_lval(Lval, AccessLvals),
 			list__member(Temp, AccessLvals)
 		),
 		vn_filter__replace_in_user_instr(Uinstr0, Temp, Defn, Uinstr1),
@@ -99,7 +99,7 @@
 		->
 			fail
 		;
-			opt_util__lvals_in_lval(Lval, AccessLvals),
+			code_util__lvals_in_lval(Lval, AccessLvals),
 			list__delete_first(AccessLvals, Temp, OtherAccessLvals)
 		->
 			\+ list__member(Temp, OtherAccessLvals),
cvs diff: Diffing compiler/notes
cvs diff: Diffing doc
Index: doc/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/Mmakefile,v
retrieving revision 1.7
diff -u -u -r1.7 Mmakefile
--- Mmakefile	1998/03/11 22:07:20	1.7
+++ Mmakefile	1998/04/01 06:19:44
@@ -75,7 +75,8 @@
 	library_1.html faq_1.html transition_guide_1.html
 
 .PHONY: manpages
-manpages: c2init.1 mmc.1 mgnuc.1 ml.1 mmake.1 msc.1 mprof.1 mprof_merge_runs.1
+manpages: c2init.1 mmc.1 mgnuc.1 ml.1 mmake.1 mmd.1 msc.1 mprof.1 \
+	mprof_merge_runs.1
 
 #-----------------------------------------------------------------------------#
 
cvs diff: Diffing extras
cvs diff: Diffing extras/cgi
cvs diff: Diffing extras/complex_numbers
cvs diff: Diffing extras/complex_numbers/samples
cvs diff: Diffing extras/complex_numbers/tests
cvs diff: Diffing extras/graphics
cvs diff: Diffing extras/graphics/Togl-1.2
cvs diff: Diffing extras/graphics/mercury_opengl
cvs diff: Diffing extras/graphics/mercury_tcltk
cvs diff: Diffing extras/graphics/samples
cvs diff: Diffing extras/graphics/samples/calc
cvs diff: Diffing extras/graphics/samples/maze
cvs diff: Diffing extras/odbc
cvs diff: Diffing extras/references
cvs diff: Diffing extras/trailed_update
cvs diff: Diffing extras/trailed_update/samples
cvs diff: Diffing library
Index: library/array.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/array.m,v
retrieving revision 1.44
diff -u -u -r1.44 array.m
--- array.m	1998/03/31 23:16:23	1.44
+++ array.m	1998/04/01 04:43:02
@@ -288,9 +288,9 @@
 Declare_entry(mercury__array__array_compare_3_0);
 
 BEGIN_MODULE(array_module_builtins)
-	init_entry(mercury____Unify___array__array_1_0);
-	init_entry(mercury____Index___array__array_1_0);
-	init_entry(mercury____Compare___array__array_1_0);
+	init_entry_sl(mercury____Unify___array__array_1_0);
+	init_entry_sl(mercury____Index___array__array_1_0);
+	init_entry_sl(mercury____Compare___array__array_1_0);
 BEGIN_CODE
 
 Define_entry(mercury____Unify___array__array_1_0);
Index: library/benchmarking.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/benchmarking.m,v
retrieving revision 1.12
diff -u -u -r1.12 benchmarking.m
--- benchmarking.m	1998/02/02 02:49:57	1.12
+++ benchmarking.m	1998/03/30 10:10:46
@@ -558,9 +558,9 @@
 Declare_entry(do_call_det_closure);
 
 BEGIN_MODULE(benchmark_nondet_module)
-	init_entry(mercury__benchmarking__benchmark_nondet_5_0);
-	init_label(mercury__benchmarking__benchmark_nondet_5_0_i1);
-	init_label(mercury__benchmarking__benchmark_nondet_5_0_i2);
+	init_entry_sl(mercury__benchmarking__benchmark_nondet_5_0);
+	init_label_sl(mercury__benchmarking__benchmark_nondet_5_0_i1);
+	init_label_sl(mercury__benchmarking__benchmark_nondet_5_0_i2);
 BEGIN_CODE
 
 Define_entry(mercury__benchmarking__benchmark_nondet_5_0);
@@ -648,8 +648,8 @@
 MR_MAKE_STACK_LAYOUT_INTERNAL(mercury__benchmarking__benchmark_det_5_0, 1);
 
 BEGIN_MODULE(benchmark_det_module)
-	init_entry(mercury__benchmarking__benchmark_det_5_0);
-	init_label(mercury__benchmarking__benchmark_det_5_0_i1);
+	init_entry_sl(mercury__benchmarking__benchmark_det_5_0);
+	init_label_sl(mercury__benchmarking__benchmark_det_5_0_i1);
 BEGIN_CODE
 
 Define_entry(mercury__benchmarking__benchmark_det_5_0);
Index: library/require.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/require.m,v
retrieving revision 1.18
diff -u -u -r1.18 require.m
--- require.m	1998/03/11 05:57:41	1.18
+++ require.m	1998/03/26 08:12:05
@@ -58,6 +58,7 @@
 :- pragma c_code(error(Message::in), "
 	fflush(stdout);
 	fprintf(stderr, ""Software error: %s\\n"", Message);
+	MR_trace_report(stderr);
 	MR_dump_stack(MR_succip, MR_sp);
 	exit(1);
 #ifndef USE_GCC_NONLOCAL_GOTOS
Index: library/std_util.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/std_util.m,v
retrieving revision 1.115
diff -u -u -r1.115 std_util.m
--- std_util.m	1998/01/30 02:15:04	1.115
+++ std_util.m	1998/03/30 10:11:31
@@ -494,15 +494,15 @@
 MR_MAKE_STACK_LAYOUT_INTERNAL(mercury__std_util__builtin_aggregate_4_0, 3);
 
 BEGIN_MODULE(builtin_aggregate_module)
-	init_entry(mercury__std_util__builtin_aggregate_4_0);
-	init_entry(mercury__std_util__builtin_aggregate_4_1);
-	init_entry(mercury__std_util__builtin_aggregate_4_2);
-	init_entry(mercury__std_util__builtin_aggregate_4_3);
-	init_entry(mercury__std_util__builtin_aggregate_4_4);
-	init_entry(mercury__std_util__builtin_aggregate_4_5);
-	init_label(mercury__std_util__builtin_aggregate_4_0_i1);
-	init_label(mercury__std_util__builtin_aggregate_4_0_i2);
-	init_label(mercury__std_util__builtin_aggregate_4_0_i3);
+	init_entry_sl(mercury__std_util__builtin_aggregate_4_0);
+	init_entry_sl(mercury__std_util__builtin_aggregate_4_1);
+	init_entry_sl(mercury__std_util__builtin_aggregate_4_2);
+	init_entry_sl(mercury__std_util__builtin_aggregate_4_3);
+	init_entry_sl(mercury__std_util__builtin_aggregate_4_4);
+	init_entry_sl(mercury__std_util__builtin_aggregate_4_5);
+	init_label_sl(mercury__std_util__builtin_aggregate_4_0_i1);
+	init_label_sl(mercury__std_util__builtin_aggregate_4_0_i2);
+	init_label_sl(mercury__std_util__builtin_aggregate_4_0_i3);
 BEGIN_CODE
 
 /*
@@ -1192,14 +1192,14 @@
 MR_MAKE_STACK_LAYOUT_ENTRY(mercury____Compare___std_util__type_info_0_0);
 
 BEGIN_MODULE(unify_univ_module)
-	init_entry(mercury____Unify___std_util__univ_0_0);
-	init_entry(mercury____Index___std_util__univ_0_0);
-	init_entry(mercury____Compare___std_util__univ_0_0);
-	init_label(mercury____Compare___std_util__univ_0_0_i1);
-
-	init_entry(mercury____Unify___std_util__type_info_0_0);
-	init_entry(mercury____Index___std_util__type_info_0_0);
-	init_entry(mercury____Compare___std_util__type_info_0_0);
+	init_entry_sl(mercury____Unify___std_util__univ_0_0);
+	init_entry_sl(mercury____Index___std_util__univ_0_0);
+	init_entry_sl(mercury____Compare___std_util__univ_0_0);
+	init_label_sl(mercury____Compare___std_util__univ_0_0_i1);
+
+	init_entry_sl(mercury____Unify___std_util__type_info_0_0);
+	init_entry_sl(mercury____Index___std_util__type_info_0_0);
+	init_entry_sl(mercury____Compare___std_util__type_info_0_0);
 BEGIN_CODE
 Define_entry(mercury____Unify___std_util__univ_0_0);
 {
cvs diff: Diffing lp_solve
cvs diff: Diffing lp_solve/lp_examples
cvs diff: Diffing profiler
cvs diff: Diffing runtime
Index: runtime/mercury_conf_param.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_conf_param.h,v
retrieving revision 1.1
diff -u -u -r1.1 mercury_conf_param.h
--- mercury_conf_param.h	1998/03/16 12:23:24	1.1
+++ mercury_conf_param.h	1998/03/31 10:17:55
@@ -90,7 +90,7 @@
 /*
 ** Debugging options:
 **
-** MR_USE_DEBUGGER:
+** MR_USE_EXTERNAL_DEBUGGER:
 **	Make MR_trace() use an external process debugger
 **	(with communication done via a socket interface)
 **	rather than using the debugger that is part of
Index: runtime/mercury_goto.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_goto.h,v
retrieving revision 1.7
diff -u -u -r1.7 mercury_goto.h
--- mercury_goto.h	1998/03/16 12:23:28	1.7
+++ mercury_goto.h	1998/03/30 08:56:14
@@ -35,22 +35,28 @@
 */
 
 #if defined(MR_INSERT_LABELS)
-  #define	make_label(n, a, l)	make_entry(n, a, l)
+  #define make_label(n, a, l)		make_entry(n, a, l)
+  #define make_label_sl(n, a, l)	make_entry_sl(n, a, l)
 #else
-  #define	make_label(n, a, l)	/* nothing */
+  #define make_label(n, a, l)		/* nothing */
+  #define make_label_sl(n, a, l)	/* nothing */
 #endif
 
 #if defined(MR_INSERT_LABELS) || defined(PROFILE_CALLS)
-  #define make_local(n, a, l)	make_entry(n, a, l)
+  #define make_local(n, a, l)		make_entry(n, a, l)
+  #define make_local_sl(n, a, l)	make_entry_sl(n, a, l)
 #else 
-  #define make_local(n, a, l)	/* nothing */
+  #define make_local(n, a, l)		/* nothing */
+  #define make_local_sl(n, a, l)	/* nothing */
 #endif
 
 #if defined(MR_INSERT_LABELS) || defined(PROFILE_CALLS) \
 		|| defined(MR_CHOOSE_ENTRY_POINT)
-  #define make_entry(n, a, l)	insert_entry(n, a, MR_STACK_LAYOUT(l))
+  #define make_entry(n, a, l)		insert_entry(n, a, NULL)
+  #define make_entry_sl(n, a, l)	insert_entry(n, a, MR_STACK_LAYOUT(l))
 #else
-  #define make_entry(n, a, l)	/* nothing */
+  #define make_entry(n, a, l)		/* nothing */
+  #define make_entry_sl(n, a, l)	/* nothing */
 #endif
 
 
@@ -471,6 +477,9 @@
     #define init_entry(label)	\
 	PRETEND_ADDRESS_IS_USED(&&label); \
 	make_entry(stringify(label), label, label)
+    #define init_entry_sl(label)	\
+	PRETEND_ADDRESS_IS_USED(&&label); \
+	make_entry_sl(stringify(label), label, label)
 
     #define ENTRY(label) 	(&label)
     #define STATIC(label) 	(&label)
@@ -498,6 +507,9 @@
     #define init_entry(label)	\
 	make_entry(stringify(label), &&label, label);	\
 	entry(label) = &&label
+    #define init_entry_sl(label)	\
+	make_entry_sl(stringify(label), &&label, label);	\
+	entry(label) = &&label
     #define ENTRY(label) 	(entry(label))
     #define STATIC(label) 	(entry(label))
 
@@ -514,13 +526,17 @@
 	label:	\
 	{
   #define init_local(label)	make_local(stringify(label), &&label, label)
+  #define init_local_sl(label)	make_local_sl(stringify(label), &&label, label)
   #define Define_label(label)	Define_local(label)
   #define Declare_label(label)	/* no declaration required */
   #ifdef MR_INSERT_LABELS
    #define init_label(label)	\
 	make_label(stringify(label), &&entry(label), label)
+   #define init_label_sl(label)	\
+	make_label_sl(stringify(label), &&entry(label), label)
   #else
    #define init_label(label)	make_label(stringify(label), &&label, label)
+   #define init_label_sl(label)	make_label_sl(stringify(label), &&label, label)
   #endif
 
   #define LOCAL(label)		(&&entry(label))
@@ -560,6 +576,7 @@
 	}			\
 	static Code* label(void) {
   #define init_entry(label)	make_entry(stringify(label), label, label)
+  #define init_entry_sl(label)	make_entry_sl(stringify(label), label, label)
 
   #define Declare_local(label)	static Code *label(void)
   #define Define_local(label)	\
@@ -567,6 +584,7 @@
 	}			\
 	static Code* label(void) {
   #define init_local(label)	make_local(stringify(label), label, label)
+  #define init_local_sl(label)	make_local_sl(stringify(label), label, label)
 
   #define Declare_label(label)	static Code *label(void)
   #define Define_label(label)	\
@@ -574,6 +592,7 @@
 	}			\
 	static Code* label(void) {
   #define init_label(label)	make_label(stringify(label), label, label)
+  #define init_label_sl(label)	make_label_sl(stringify(label), label, label)
 
   #define ENTRY(label) 		(label)
   #define STATIC(label) 	(label)
Index: runtime/mercury_memory.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_memory.c,v
retrieving revision 1.5
diff -u -u -r1.5 mercury_memory.c
--- mercury_memory.c	1998/03/30 03:08:36	1.5
+++ mercury_memory.c	1998/03/31 10:12:05
@@ -80,6 +80,7 @@
 #endif
 
 #include "mercury_imp.h"
+#include "mercury_trace.h"
 
 /*---------------------------------------------------------------------------*/
 
@@ -701,6 +702,7 @@
 	context_msg = explain_context(context);
 	write(STDERR, main_msg, strlen(main_msg));
 	write(STDERR, context_msg, strlen(context_msg));
+	MR_trace_report_raw(STDERR);
 
 	if (dump) {
 		print_dump_stack();
@@ -900,6 +902,7 @@
   #endif
 	fprintf(stderr, "address involved: %p\n", address);
 
+	MR_trace_report(stderr);
 	print_dump_stack();
 	dump_prev_locations();
 	fprintf(stderr, "exiting from signal handler\n");
@@ -990,6 +993,7 @@
 			(void *) info->si_addr);
 	} /* end if */
 
+	MR_trace_report(stderr);
 	print_dump_stack();
 	dump_prev_locations();
 	fprintf(stderr, "exiting from signal handler\n");
@@ -1063,6 +1067,7 @@
 		explain_segv(info, context);
 	}
 
+	MR_trace_report(stderr);
 	print_dump_stack();
 	dump_prev_locations();
 	fprintf(stderr, "exiting from signal handler\n");
Index: runtime/mercury_misc.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_misc.c,v
retrieving revision 1.5
diff -u -u -r1.5 mercury_misc.c
--- mercury_misc.c	1998/03/30 03:08:38	1.5
+++ mercury_misc.c	1998/03/30 10:28:12
@@ -7,6 +7,7 @@
 #include	"mercury_imp.h"
 #include	"mercury_dlist.h"
 #include	"mercury_regs.h"
+#include	"mercury_trace.h"
 #include	"mercury_misc.h"
 
 #include	<stdio.h>
@@ -468,6 +469,7 @@
 void 
 fatal_error(const char *message) {
 	fprintf(stderr, "Mercury runtime: %s\n", message);
+	MR_trace_report(stderr);
 	exit(1);
 }
 
Index: runtime/mercury_regorder.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_regorder.h,v
retrieving revision 1.2
diff -u -u -r1.2 mercury_regorder.h
--- mercury_regorder.h	1997/11/23 07:21:32	1.2
+++ mercury_regorder.h	1998/03/16 05:06:30
@@ -55,6 +55,11 @@
 #define r31		count_usage(R_RN(31), mr35)
 #define r32		count_usage(R_RN(32), mr36)
 
+/*
+** If you modify the following block, make sure that you update
+** the definitions of MR_NUM_SPECIAL_REG and MR_MAX_SPECIAL_REG_MR.
+*/
+
 #define MR_succip	LVALUE_CAST(Code *, count_usage(MR_SI_RN, mr1))
 #define succip		MR_succip
 #define MR_hp		LVALUE_CAST(Word *, count_usage(MR_HP_RN, mr5))
@@ -73,6 +78,12 @@
 #define MR_trail_ptr	count_usage(MR_TRAIL_PTR_RN, MR_trail_ptr_var)
 #define MR_ticket_counter	 \
 		count_usage(MR_TICKET_COUNTER_RN, MR_ticket_counter_var)
+
+/* the number of special, non rN registers */
+#define MR_NUM_SPECIAL_REG	10
+
+/* the maximum mrN number of special, non rN registers */
+#define	MR_MAX_SPECIAL_REG_MR	39
 
 #define VIRTUAL_REG_MAP_BODY	{ \
 	2, \
Index: runtime/mercury_stack_layout.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_stack_layout.h,v
retrieving revision 1.2
diff -u -u -r1.2 mercury_stack_layout.h
--- mercury_stack_layout.h	1998/03/11 22:07:30	1.2
+++ mercury_stack_layout.h	1998/03/31 10:17:18
@@ -10,6 +10,10 @@
 /*
 ** mercury_stack_layout.h -
 **	Definitions for the stack layout data structures. 
+**
+** NOTE: The constants and data-structures used here need to be kept in
+** sync with the ones generated in the compiler. If you change anything here,
+** you may need to change compiler/stack_layout.m as well.
 */
 
 /*
@@ -49,7 +53,8 @@
 
 #define MR_DETISM_FIRST_SOLN(d)		(((d) & 8) != 0)
 
-#define MR_DETISM_DET_CODE_MODEL(d)	(((d) & 1) == 0)
+#define MR_DETISM_DET_STACK(d)		(!MR_DETISM_AT_MOST_MANY(d) \
+					|| MR_DETISM_FIRST_SOLN(d))
 
 /*
 ** Definitions for "MR_Live_Lval"
@@ -112,7 +117,7 @@
 ** The data is encoded such that low values (less than
 ** TYPELAYOUT_MAX_VARINT) represent succip, hp, etc.  Higher values
 ** represent data variables, and are pointers to a 2 word cell, 
-** containing a type_info and an instantiation represention.
+** containing a pseudo type_info and an instantiation represention.
 **
 ** This data is generated in compiler/stack_layout.m, which must be kept
 ** in sync with the constants defined here.
@@ -130,7 +135,7 @@
 } MR_Lval_NonVar;
 
 typedef struct { 
-	Word	type;	/* contains a type_info */
+	Word	*pseudo_type_info;
 	Word	inst;	/* not yet used; currently always -1 */
 } MR_Var_Shape_Info;
 
@@ -140,10 +145,10 @@
 		((MR_Lval_NonVar) T)
 
 #define MR_LIVE_TYPE_GET_VAR_TYPE(T)   			\
-		((Word) ((MR_Var_Shape_Info *) T)->type)
+		(((MR_Var_Shape_Info *) T)->pseudo_type_info)
 
 #define MR_LIVE_TYPE_GET_VAR_INST(T)   			\
-		((Word) ((MR_Var_Shape_Info *) T)->inst)
+		(((MR_Var_Shape_Info *) T)->inst)
 
 /*
 ** Macros to support hand-written C code.
@@ -151,9 +156,10 @@
 
 /*
 ** Define a stack layout for a label that you know very little about.
-** It's just a generic entry label, no useful information, except
+** It is just a generic entry label, no useful information, except
 ** the code address for the label.
 */ 
+
 #ifdef MR_USE_STACK_LAYOUTS
  #define MR_MAKE_STACK_LAYOUT_ENTRY(l) 					\
  const struct mercury_data__stack_layout__##l##_struct {		\
@@ -178,6 +184,7 @@
 ** The only useful information in this structure is the code address
 ** and the reference to the entry for this label.
 */ 
+
 #ifdef MR_USE_STACK_LAYOUTS
  #define MR_MAKE_STACK_LAYOUT_INTERNAL_WITH_ENTRY(l, e)			\
  const struct mercury_data__stack_layout__##l##_struct {		\
@@ -208,6 +215,7 @@
 ** The only useful information in this structure is the code address
 ** and the reference to the entry for this label.
 */ 
+
 #ifdef MR_USE_STACK_LAYOUTS
  #define MR_MAKE_STACK_LAYOUT_INTERNAL(e, x)				\
  const struct mercury_data__stack_layout__##e##_i##x##_struct {		\
@@ -227,18 +235,25 @@
 ** Structs and macros to support stack layouts.
 */
 
-typedef	struct MR_stack_layout_var_struct {
+typedef	struct MR_Stack_Layout_Var_Struct {
 	MR_Live_Lval		MR_slv_locn;
 	MR_Live_Type		MR_slv_live_type;
-} MR_stack_layout_var;
+} MR_Stack_Layout_Var;
 
-typedef	struct MR_stack_layout_vars_struct {
-	MR_stack_layout_var	*MR_slvs_pairs;
+typedef	struct MR_Stack_Layout_Vars_Struct {
+	MR_Stack_Layout_Var	*MR_slvs_pairs;
 	String			*MR_slvs_names;
-	Word			*MR_slvs_tvars;
-} MR_stack_layout_vars;
+	Integer			MR_slvs_tvar_count;
+	MR_Live_Lval		*MR_slvs_tvars;
+} MR_Stack_Layout_Vars;
+
+#define	MR_name_if_present(vars, i)					\
+				((vars->MR_slvs_names != NULL		\
+				&& vars->MR_slvs_names[(i)] != NULL)	\
+				? vars->MR_slvs_names[(i)]		\
+				: "")
 
-typedef	struct MR_stack_layout_entry_struct {
+typedef	struct MR_Stack_Layout_Entry_Struct {
 	Code			*MR_sle_code_addr;
 	MR_Determinism		MR_sle_detism;
 	Integer			MR_sle_stack_slots;
@@ -251,20 +266,19 @@
 	Integer			MR_sle_arity;
 	Integer			MR_sle_mode;
 	/* the fields from here onwards are present only with trace layouts */
-	Integer			MR_sle_in_arg_count;
-	MR_stack_layout_vars	MR_sle_in_arg_info;
-	Integer			MR_sle_out_arg_count;
-	MR_stack_layout_vars	MR_sle_out_arg_info;
-} MR_stack_layout_entry;
-
-typedef	struct MR_stack_layout_label_struct {
-	MR_stack_layout_entry	*MR_sll_entry;
+	struct MR_Stack_Layout_Label_Struct
+				*MR_sle_call_label;
+} MR_Stack_Layout_Entry;
+
+typedef	struct MR_Stack_Layout_Label_Struct {
+	MR_Stack_Layout_Entry	*MR_sll_entry;
+	Integer			MR_sll_label_num;
 	Integer			MR_sll_var_count;
 	/* the last field is present only if MR_sll_var_count > 0 */
-	MR_stack_layout_vars	MR_sll_var_info;
-} MR_stack_layout_label;
+	MR_Stack_Layout_Vars	MR_sll_var_info;
+} MR_Stack_Layout_Label;
 
-/* The following macros support obsolete code. */
+/* The following macros support obsolete code (and probably don't work). */
 #define MR_ENTRY_STACK_LAYOUT_GET_LABEL_ADDRESS(s)		\
 		((Code *) field(0, (s), 0))
 
@@ -282,4 +296,3 @@
 
 /*---------------------------------------------------------------------------*/
 #endif /* not MERCURY_STACK_LAYOUT_H */
-
Index: runtime/mercury_stack_trace.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_stack_trace.c,v
retrieving revision 1.2
diff -u -u -r1.2 mercury_stack_trace.c
--- mercury_stack_trace.c	1998/03/16 12:23:37	1.2
+++ mercury_stack_trace.c	1998/03/20 08:11:17
@@ -17,13 +17,12 @@
 void
 MR_dump_stack(Code *success_pointer, Word *det_stack_pointer)
 {
-	Label *label;
-	MR_Live_Lval location;
-	MR_stack_layout_label *layout;
-	MR_stack_layout_entry *entry_layout;
-	MR_Lval_Type type;
-	int number, determinism;
-
+	Label			*label;
+	MR_Live_Lval		location;
+	MR_Stack_Layout_Label	*layout;
+	MR_Stack_Layout_Entry	*entry_layout;
+	MR_Lval_Type		type;
+	int			number, determinism;
 
 #ifndef MR_STACK_TRACE
 	fprintf(stderr, "Stack dump not available in this grade.\n");
@@ -36,7 +35,7 @@
 			fatal_error("internal label not found");
 		}
 
-		layout = (MR_stack_layout_label *) label->e_layout;
+		layout = (MR_Stack_Layout_Label *) label->e_layout;
 		entry_layout = layout->MR_sll_entry;
 		
 		label = lookup_label_addr(
@@ -65,4 +64,3 @@
 	} while (MR_DETISM_DET_CODE_MODEL(determinism));
 #endif /* MR_STACK_TRACE */
 }



More information about the developers mailing list