[m-rev.] for review: minimal model tabling enhancements
Zoltan Somogyi
zs at cs.mu.OZ.AU
Fri Mar 14 16:58:32 AEDT 2003
Since miminal model debugging is currently not operational, only the parts
of this diff that outside #ifdef MR_USE_MINIMAL_MODEL really need to be
reviewed.
Zoltan.
This change adds new facilities for debugging minimal model tabling, and
has several bug fixes found with the aid of those facilities. Most of the
diff affects the behavior of the system only in minimal model grades and/or
when debugging flags are defined.
compiler/ite_gen.m:
In minimal model grades, surround the conditions of if-then-elses
with calls to three functions. These functions detect when a
condition fails due to one or more suspensions, and abort the
program. (After resumptions, the condition may actually have
solutions, but by then the computation has committed to the wrong
path.)
compiler/table_gen.m:
Change the program transformation for model_non predicates
to use a switch instead of nested if-then-elses, to avoid the
overhead of wrapping the condition. The version with switches
is also a bit easier to debug.
The transformation for model_det and model_semi predicates
stays as before, because for such predicates finding the status
(which we want to switch on) requires computation, not just a lookup.
Switch to state variable syntax in the affacted predicates.
Make the error message for an internal error in loopcheck predicates
more precise.
Mark the code fragments that modify tabling data structures as impure
and code fragments that examine tabling data structures as semipure.
runtime/mercury_stacks.[ch]:
Implement the new stack of possibly negated contexts that we use
to detect false failures due to suspensions in negated contexts.
Fix a bug: don't refer to MR_cut_stack[-1].
Shorten the name of the generator stack.
runtime/mercury_context.[ch]:
runtime/mercury_memory.c:
runtime/mercury_wrapper.[ch]:
Allocate memory for the new stack of possibly negated contexts.
Use the shortened name of the generator stack.
runtime/mercury_regorder.h:
Allocate a pointer for the new stack of possibly negated contexts.
runtime/mercury_minimal_model.[ch]:
A new module holding the part of mercury_tabling.[ch]
that is specific to minimal model tabling. This version contains
tools to help debugging of minimal model tabling, as well as some
bug fixes found with the aid of those tools.
runtime/mercury_tabling.[ch]:
Remove the code moved to mercury_minimal_model.[ch], and add the
code moved here from trace/mercury_trace_internal.c.
Add prefixes to a bunch of structure fields to make it easier
to read code accessing those fields.
Add mechanisms to allocate and copy tabling structures with type
safety.
runtime/mercury_imp.h:
#include the new header file, if it is needed.
runtime/Mmakefile:
Mention the new module, and fix sortedness errors.
runtime/mercury_stack_trace.c:
Fix a bug that sometimes caused stack traces to abort in minimal model
grades: they were trying to get layout information from labels
that do not have them, such as do_fail.
If MR_TABLE_DEBUG is defined, print the locations of stack frames
when doing stack dumps.
runtime/mercury_trace_base.h:
Export to mercury_stack_trace.c the labels that we use to let the
debugger get control at redos and fails, since they don't have
layout information.
runtime/mercury_types.h:
Move typedefs here from mercury_tabling.h, and add typedefs for some
newly added types.
runtime/mercury_engine.[ch]:
Add a table mapping debugging flags to their offsets in the
MR_debugflag array, for use in the debugger.
runtime/mercury_misc.c:
Make the formatting of det stack pointers the same as nondet stack
pointers in debugging output.
library/table_builtin.m:
Conform to the new names of some fields.
Add a predicate to return the status of a subgoal.
Add conditionally compiled debugging code.
trace/mercury_trace.c:
Conform to the new names of some fields.
trace/mercury_trace_internal.c:
Add two new mdb commands, to print the cut stack and the new possibly
negated context stack.
Add two new mdb commands to print a subgoal and a consumer.
Move some of the code to print tabling-related
data structures to runtime/mercury_tabling.[ch].
Add a new mdb command to report the values of debugging flags and
to set and clear them. Previously, one had to turn on these debugging
flags with environment variables, which were problematic because they
turned on diagnostic printouts even in Mercury programs that *weren't*
being debugged, such as the Mercury compiler when being used to
generate the program to be debugged. Now the flags can be turned on
from a .mdbrc file, which eliminates much setting and unsetting of
environment variables.
doc/user_guide.tex:
Document the new mdb commands.
tests/debugger/mdb_command_test.inp:
Test the documentation of the new mdb commands.
tests/debugger/completion.exp:
Expect the new commands in the command completion test.
tests/debugger/all_solutions.exp3:
tests/debugger/exception_value.exp3:
tests/debugger/declarative/catch.exp3:
tests/debugger/declarative/ho5.exp3:
tests/debugger/declarative/throw.exp3:
New expected test cases for use in minimal model grades. They
differ from existing expected output files only in the precise
phrasing of error messages.
tests/tabling/Mmakefile:
Enable the mday test case, now that we pass it.
cvs diff: Diffing .
cvs diff: Diffing analysis
cvs diff: Diffing bindist
cvs diff: Diffing boehm_gc
cvs diff: Diffing boehm_gc/Mac_files
cvs diff: Diffing boehm_gc/cord
cvs diff: Diffing boehm_gc/cord/private
cvs diff: Diffing boehm_gc/doc
cvs diff: Diffing boehm_gc/include
cvs diff: Diffing boehm_gc/include/private
cvs diff: Diffing boehm_gc/tests
cvs diff: Diffing browser
cvs diff: Diffing bytecode
cvs diff: Diffing compiler
Index: compiler/ite_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/ite_gen.m,v
retrieving revision 1.68
diff -u -b -r1.68 ite_gen.m
--- compiler/ite_gen.m 9 Sep 2002 07:48:13 -0000 1.68
+++ compiler/ite_gen.m 19 Nov 2002 06:58:34 -0000
@@ -40,7 +40,7 @@
:- import_module backend_libs__builtin_ops.
:- import_module libs__options, libs__globals, libs__tree.
-:- import_module bool, set, term, list, map, std_util, require.
+:- import_module bool, string, set, term, list, map, std_util, require.
ite_gen__generate_ite(CodeModel, CondGoal0, ThenGoal, ElseGoal, IteGoalInfo,
Code) -->
@@ -177,6 +177,8 @@
label(EndLabel)
- "end of if-then-else"
]) },
+ { make_pneg_context_wrappers(Globals, PNegCondCode, PNegThenCode,
+ PNegElseCode) },
{ Code =
tree(FlushCode,
tree(SaveHpCode,
@@ -184,10 +186,12 @@
tree(PrepareHijackCode,
tree(EffectResumeCode,
tree(CondTraceCode,
+ tree(PNegCondCode,
tree(CondCode,
tree(ThenNeckCode,
tree(ResetTicketCode,
tree(ThenTraceCode,
+ tree(PNegThenCode,
tree(ThenCode,
tree(ThenSaveCode,
tree(JumpToEndCode,
@@ -196,9 +200,10 @@
tree(RestoreHpCode,
tree(RestoreTicketCode,
tree(ElseTraceCode,
+ tree(PNegElseCode,
tree(ElseCode,
tree(ElseSaveCode,
- EndLabelCode))))))))))))))))))))
+ EndLabelCode)))))))))))))))))))))))
},
code_info__after_all_branches(StoreMap, MaybeEnd).
@@ -349,6 +354,8 @@
trace__maybe_generate_negated_event_code(Goal, NotGoalInfo,
neg_success, SuccessTraceCode),
+ { make_pneg_context_wrappers(Globals, PNegCondCode, PNegThenCode,
+ PNegElseCode) },
{ Code =
tree(FlushCode,
tree(PrepareHijackCode,
@@ -356,16 +363,86 @@
tree(SaveHpCode,
tree(SaveTicketCode,
tree(EnterTraceCode,
+ tree(PNegCondCode,
tree(GoalCode,
tree(ThenNeckCode,
tree(PruneTicketCode,
tree(FailTraceCode,
+ tree(PNegThenCode,
tree(FailCode,
tree(ResumeCode,
tree(ElseNeckCode,
tree(RestoreTicketCode,
tree(RestoreHpCode,
- SuccessTraceCode)))))))))))))))
+ tree(SuccessTraceCode,
+ PNegElseCode))))))))))))))))))
}.
+
+%---------------------------------------------------------------------------%
+
+ % If the code in the condition depends on a consumer
+ % of a generator that is not complete by the time we finish
+ % executing the condition, then failure out of the condition
+ % does not necessarily mean that the condition has no solution;
+ % it may mean simply that the condition's solution depends on
+ % a generator solution that hasn't been produced yet and thus
+ % hasn't been given to the consumer yet.
+ %
+ % Detecting such situations requires knowing whether tabled
+ % subgoals (both generators and consumers) are started inside
+ % possibly negated contexts or not, which is why we wrap the
+ % condition inside MR_pneg_enter_{cond,then,exit}.
+
+:- pred make_pneg_context_wrappers(globals::in, code_tree::out, code_tree::out,
+ code_tree::out) is det.
+
+make_pneg_context_wrappers(Globals, PNegCondCode, PNegThenCode, PNegElseCode)
+ :-
+ globals__lookup_bool_option(Globals, use_minimal_model,
+ UseMinimalModel),
+ (
+ UseMinimalModel = yes,
+
+ PNegCondComponents = [
+ pragma_c_raw_code(
+ wrap_transient("\t\tMR_pneg_enter_cond();\n"),
+ live_lvals_info(set__init))
+ ],
+ PNegThenComponents = [
+ pragma_c_raw_code(
+ wrap_transient("\t\tMR_pneg_enter_then();\n"),
+ live_lvals_info(set__init))
+ ],
+ PNegElseComponents = [
+ pragma_c_raw_code(
+ wrap_transient("\t\tMR_pneg_enter_else();\n"),
+ live_lvals_info(set__init))
+ ],
+ PNegCondCode = node([
+ pragma_c([], PNegCondComponents, will_not_call_mercury,
+ no, no, no, no, no) - ""
+ ]),
+ PNegThenCode = node([
+ pragma_c([], PNegThenComponents, will_not_call_mercury,
+ no, no, no, no, no) - ""
+ ]),
+ PNegElseCode = node([
+ pragma_c([], PNegElseComponents, will_not_call_mercury,
+ no, no, no, no, no) - ""
+ ])
+ ;
+ UseMinimalModel = no,
+ PNegCondCode = empty,
+ PNegThenCode = empty,
+ PNegElseCode = empty
+ ).
+
+:- func wrap_transient(string) = string.
+
+wrap_transient(Code) =
+ string__append_list([
+ "\t\tMR_save_transient_registers();\n",
+ Code,
+ "\t\tMR_restore_transient_registers();\n"]).
%---------------------------------------------------------------------------%
Index: compiler/table_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/table_gen.m,v
retrieving revision 1.44
diff -u -b -r1.44 table_gen.m
--- compiler/table_gen.m 28 Feb 2003 00:21:38 -0000 1.44
+++ compiler/table_gen.m 3 Mar 2003 07:29:06 -0000
@@ -100,20 +100,20 @@
% % Look up the input arguments, and set up the table.
% impure table_lookup_insert_int(T0, A, T1),
% impure table_nondet_setup(T1, T2),
-% (if
-% semipure table_nondet_is_complete(T2)
-% then
+% impure table_subgoal_status(T2, Status),
+% (
+% Status = complete,
% % Return all the answers from the complete
% % table.
% impure table_nondet_return_all_ans(T2, Ans),
% impure table_restore_int_ans(Ans, 0, B)
-% else if
-% semipure table_nondet_is_active(T2)
-% then
+% ;
+% Status = active,
% % Suspend the current computational branch.
% impure table_nondet_suspend(T2, Ans),
% impure table_restore_int_ans(Ans, 0, B)
-% else
+% ;
+% Status = inactive,
% (
% % Mark that this subgoal is being
% % evaluated.
@@ -713,7 +713,7 @@
instmap_delta_restrict(RestoreAnsInstMapDelta0,
RestoreAnsNonLocals, RestoreAnsInstMapDelta),
goal_info_init(RestoreAnsNonLocals, RestoreAnsInstMapDelta,
- det, pure, Context, RestoreAnsGoalInfo0),
+ det, semipure, Context, RestoreAnsGoalInfo0),
goal_info_add_feature(RestoreAnsGoalInfo0, hide_debug_event,
RestoreAnsGoalInfo),
RestoreAnsGoal = RestoreAnsGoalEx - RestoreAnsGoalInfo
@@ -749,7 +749,7 @@
instmap_delta_restrict(CallSaveAnsInstMapDelta0,
CallSaveAnsNonLocals, CallSaveAnsInstMapDelta),
goal_info_init(CallSaveAnsNonLocals, CallSaveAnsInstMapDelta, det,
- pure, Context, CallSaveAnsGoalInfo0),
+ impure, Context, CallSaveAnsGoalInfo0),
goal_info_add_feature(CallSaveAnsGoalInfo0, hide_debug_event,
CallSaveAnsGoalInfo),
CallSaveAnsGoal = CallSaveAnsGoalEx - CallSaveAnsGoalInfo,
@@ -761,7 +761,7 @@
set__insert(OrigNonLocals, TableVar, GenIfNecNonLocals),
instmap_delta_restrict(GenIfNecInstMapDelta0, GenIfNecNonLocals,
GenIfNecInstMapDelta),
- goal_info_init(GenIfNecNonLocals, GenIfNecInstMapDelta, det, pure,
+ goal_info_init(GenIfNecNonLocals, GenIfNecInstMapDelta, det, impure,
Context, GenIfNecGoalInfo0),
goal_info_add_feature(GenIfNecGoalInfo0, hide_debug_event,
GenIfNecGoalInfo),
@@ -775,7 +775,7 @@
instmap_delta_restrict(CheckAndGenAnsInstMapDelta0,
CheckAndGenAnsNonLocals, CheckAndGenAnsInstMapDelta),
goal_info_init(CheckAndGenAnsNonLocals, CheckAndGenAnsInstMapDelta,
- det, pure, Context, CheckAndGenAnsGoalInfo0),
+ det, impure, Context, CheckAndGenAnsGoalInfo0),
goal_info_add_feature(CheckAndGenAnsGoalInfo0, hide_debug_event,
CheckAndGenAnsGoalInfo),
CheckAndGenAnsGoal = CheckAndGenAnsGoalEx - CheckAndGenAnsGoalInfo,
@@ -786,7 +786,7 @@
BodyInstMapDelta0),
instmap_delta_restrict(BodyInstMapDelta0, OrigNonLocals,
BodyInstMapDelta),
- goal_info_init(OrigNonLocals, BodyInstMapDelta, det, pure,
+ goal_info_init(OrigNonLocals, BodyInstMapDelta, det, impure,
Context, BodyGoalInfo0),
goal_info_add_feature(BodyGoalInfo0, hide_debug_event, BodyGoalInfo),
Goal = BodyGoalEx - BodyGoalInfo.
@@ -801,8 +801,8 @@
prog_var::out, hlds_goal::out, proc_table_info::out) is det.
table_gen__create_new_det_goal(EvalMethod, Detism, OrigGoal, PredId, ProcId,
- HeadVars, HeadVarModes, VarTypes0, VarTypes, VarSet0, VarSet,
- TableInfo0, TableInfo, TableVar, Goal, ProcTableInfo) :-
+ HeadVars, HeadVarModes, !VarTypes, !VarSet, !TableInfo,
+ TableVar, Goal, ProcTableInfo) :-
% even if the original goal doesn't use all of the headvars,
% the code generated by the tabling transformation does,
% so we need to compute the nonlocals from the headvars rather
@@ -812,28 +812,25 @@
goal_info_get_instmap_delta(OrigGoalInfo, OrigInstMapDelta),
goal_info_get_context(OrigGoalInfo, Context),
- ModuleInfo = TableInfo0 ^ table_module_info,
+ ModuleInfo = !.TableInfo ^ table_module_info,
get_input_output_vars(HeadVars, HeadVarModes, ModuleInfo, InputVars,
OutputVars),
generate_simple_lookup_goal(InputVars, PredId, ProcId, Context,
- VarTypes0, VarTypes1, VarSet0, VarSet1, TableInfo0, TableInfo1,
- TableVar, LookUpGoal, Steps),
+ !VarTypes, !VarSet, !TableInfo, TableVar, LookUpGoal, Steps),
generate_call("table_simple_is_complete", [TableVar], semidet,
yes(semipure), [], ModuleInfo, Context, CompleteCheckGoal),
allocate_slot_numbers(OutputVars, 0, NumberedOutputVars),
list__length(NumberedOutputVars, BlockSize),
generate_save_goal(NumberedOutputVars, TableVar, BlockSize,
- Context, VarTypes1, VarTypes2, VarSet1, VarSet2,
- TableInfo1, TableInfo, SaveAnsGoal0),
+ Context, !VarTypes, !VarSet, !TableInfo, SaveAnsGoal0),
generate_restore_goal(NumberedOutputVars, TableVar,
- ModuleInfo, Context, VarTypes2, VarTypes3, VarSet2, VarSet3,
- RestoreAnsGoal0),
+ ModuleInfo, Context, !VarTypes, !VarSet, RestoreAnsGoal0),
generate_call("table_simple_mark_as_inactive", [TableVar], det,
yes(impure), [], ModuleInfo, Context, MarkAsInactiveGoal),
- generate_loop_error_goal(TableInfo, Context, VarTypes3, VarTypes,
- VarSet3, VarSet, LoopErrorGoal),
+ generate_loop_error_goal(!.TableInfo, Context, infinite_recursion_msg,
+ !VarTypes, !VarSet, LoopErrorGoal),
( Detism = erroneous ->
% In this case, the RestoreAnsGoal will never be reached,
% but to ensure that the generated code is determinism-correct,
@@ -866,7 +863,7 @@
NoLoopGenInstMapDelta0),
instmap_delta_restrict(NoLoopGenInstMapDelta0, GenAnsNonLocals,
NoLoopGenInstMapDelta),
- goal_info_init(GenAnsNonLocals, NoLoopGenInstMapDelta, det, pure,
+ goal_info_init(GenAnsNonLocals, NoLoopGenInstMapDelta, det, impure,
Context, NoLoopGenGoalInfo0),
goal_info_add_feature(NoLoopGenGoalInfo0, hide_debug_event,
NoLoopGenGoalInfo),
@@ -878,7 +875,7 @@
NoLoopGenAnsGoal], GenAnsInstMapDelta0),
instmap_delta_restrict(GenAnsInstMapDelta0, GenAnsNonLocals,
GenAnsInstMapDelta),
- goal_info_init(GenAnsNonLocals, GenAnsInstMapDelta, det, pure,
+ goal_info_init(GenAnsNonLocals, GenAnsInstMapDelta, det, impure,
Context, GenAnsGoalInfo0),
goal_info_add_feature(GenAnsGoalInfo0, hide_debug_event,
GenAnsGoalInfo),
@@ -890,17 +887,17 @@
ITEInstMapDelta0),
instmap_delta_restrict(ITEInstMapDelta0, GenAnsNonLocals,
ITEInstMapDelta),
- goal_info_init(GenAnsNonLocals, ITEInstMapDelta, det, pure,
+ goal_info_init(GenAnsNonLocals, ITEInstMapDelta, det, impure,
Context, ITEGoalInfo0),
goal_info_add_feature(ITEGoalInfo0, hide_debug_event, ITEGoalInfo),
ITEGoal = ITEGoalEx - ITEGoalInfo,
GoalEx = conj([LookUpGoal, ITEGoal]),
- goal_info_init(OrigNonLocals, OrigInstMapDelta, det, pure,
+ goal_info_init(OrigNonLocals, OrigInstMapDelta, det, impure,
Context, GoalInfo0),
goal_info_add_feature(GoalInfo0, hide_debug_event, GoalInfo),
Goal = GoalEx - GoalInfo,
- generate_gen_proc_table_info(TableInfo, Steps, InputVars, OutputVars,
+ generate_gen_proc_table_info(!.TableInfo, Steps, InputVars, OutputVars,
ProcTableInfo).
%-----------------------------------------------------------------------------%
@@ -915,8 +912,8 @@
prog_var::out, hlds_goal::out, proc_table_info::out) is det.
table_gen__create_new_semi_goal(EvalMethod, Detism, OrigGoal, PredId, ProcId,
- HeadVars, HeadVarModes, VarTypes0, VarTypes, VarSet0, VarSet,
- TableInfo0, TableInfo, TableVar, Goal, ProcTableInfo) :-
+ HeadVars, HeadVarModes, !VarTypes, !VarSet, !TableInfo,
+ TableVar, Goal, ProcTableInfo) :-
% even if the original goal doesn't use all of the headvars,
% the code generated by the tabling transformation does,
% so we need to compute the nonlocals from the headvars rather
@@ -926,25 +923,22 @@
goal_info_get_instmap_delta(OrigGoalInfo, OrigInstMapDelta),
goal_info_get_context(OrigGoalInfo, Context),
- ModuleInfo = TableInfo0 ^ table_module_info,
+ ModuleInfo = !.TableInfo ^ table_module_info,
get_input_output_vars(HeadVars, HeadVarModes, ModuleInfo, InputVars,
OutputVars),
generate_simple_lookup_goal(InputVars, PredId, ProcId, Context,
- VarTypes0, VarTypes1, VarSet0, VarSet1, TableInfo0, TableInfo1,
- TableVar, LookUpGoal, Steps),
+ !VarTypes, !VarSet, !TableInfo, TableVar, LookUpGoal, Steps),
generate_call("table_simple_is_complete", [TableVar], semidet,
yes(semipure), [], ModuleInfo, Context, CompleteCheckGoal),
allocate_slot_numbers(OutputVars, 0, NumberedOutputVars),
list__length(NumberedOutputVars, BlockSize),
generate_save_goal(NumberedOutputVars, TableVar, BlockSize,
- Context, VarTypes1, VarTypes2, VarSet1, VarSet2,
- TableInfo1, TableInfo, SaveAnsGoal0),
+ Context, !VarTypes, !VarSet, !TableInfo, SaveAnsGoal0),
generate_restore_goal(NumberedOutputVars, TableVar,
- ModuleInfo, Context, VarTypes2, VarTypes3, VarSet2, VarSet3,
- RestoreTrueAnsGoal),
- generate_loop_error_goal(TableInfo, Context,
- VarTypes3, VarTypes, VarSet3, VarSet, LoopErrorGoal),
+ ModuleInfo, Context, !VarTypes, !VarSet, RestoreTrueAnsGoal),
+ generate_loop_error_goal(!.TableInfo, Context, infinite_recursion_msg,
+ !VarTypes, !VarSet, LoopErrorGoal),
generate_call("table_simple_mark_as_failed", [TableVar],
det, yes(impure), [], ModuleInfo, Context, MarkAsFailedGoal0),
append_fail(MarkAsFailedGoal0, MarkAsFailedGoal),
@@ -980,7 +974,7 @@
instmap_delta_restrict(NoLoopGenInstMapDelta0, GenAnsNonLocals,
NoLoopGenInstMapDelta),
goal_info_init(GenAnsNonLocals, NoLoopGenInstMapDelta, semidet,
- pure, Context, NoLoopGenGoalInfo0),
+ impure, Context, NoLoopGenGoalInfo0),
goal_info_add_feature(NoLoopGenGoalInfo0, hide_debug_event,
NoLoopGenGoalInfo),
NoLoopGenAnsGoal = NoLoopGenAnsGoalEx - NoLoopGenGoalInfo,
@@ -992,7 +986,7 @@
instmap_delta_restrict(GenTrueAnsInstMapDelta0,
GenAnsNonLocals, GenTrueAnsInstMapDelta),
goal_info_init(GenAnsNonLocals, GenTrueAnsInstMapDelta,
- semidet, pure, Context, GenTrueAnsGoalInfo0),
+ semidet, impure, Context, GenTrueAnsGoalInfo0),
goal_info_add_feature(GenTrueAnsGoalInfo0, hide_debug_event,
GenTrueAnsGoalInfo),
GenTrueAnsGoal = GenTrueAnsGoalEx - GenTrueAnsGoalInfo
@@ -1017,7 +1011,7 @@
instmap_delta_restrict(GenTrueAnsInstMapDelta0,
GenAnsNonLocals, GenTrueAnsInstMapDelta),
goal_info_init(GenAnsNonLocals, GenTrueAnsInstMapDelta,
- semidet, pure, Context, GenTrueAnsGoalInfo0),
+ semidet, impure, Context, GenTrueAnsGoalInfo0),
goal_info_add_feature(GenTrueAnsGoalInfo0, hide_debug_event,
GenTrueAnsGoalInfo),
GenTrueAnsGoal = GenTrueAnsGoalEx - GenTrueAnsGoalInfo
@@ -1049,7 +1043,7 @@
instmap_delta_restrict(RestInstMapDelta0, RestNonLocals,
RestInstMapDelta),
goal_info_init(RestNonLocals, RestInstMapDelta, semidet,
- pure, Context, RestAnsGoalInfo0),
+ semipure, Context, RestAnsGoalInfo0),
goal_info_add_feature(RestAnsGoalInfo0, hide_debug_event,
RestAnsGoalInfo),
RestoreAnsGoal = RestAnsGoalEx - RestAnsGoalInfo
@@ -1061,8 +1055,8 @@
GenAnsGoalInstMapDelta0),
instmap_delta_restrict(GenAnsGoalInstMapDelta0, GenAnsNonLocals,
GenAnsGoalInstMapDelta),
- goal_info_init(GenAnsNonLocals, GenAnsGoalInstMapDelta, semidet, pure,
- Context, GenAnsGoalInfo0),
+ goal_info_init(GenAnsNonLocals, GenAnsGoalInstMapDelta, semidet,
+ impure, Context, GenAnsGoalInfo0),
goal_info_add_feature(GenAnsGoalInfo0, hide_debug_event,
GenAnsGoalInfo),
GenAnsGoal = GenAnsGoalEx - GenAnsGoalInfo,
@@ -1073,17 +1067,17 @@
ITEInstMapDelta0),
instmap_delta_restrict(ITEInstMapDelta0, GenAnsNonLocals,
ITEInstMapDelta),
- goal_info_init(GenAnsNonLocals, ITEInstMapDelta, semidet, pure,
+ goal_info_init(GenAnsNonLocals, ITEInstMapDelta, semidet, impure,
Context, ITEGoalInfo0),
goal_info_add_feature(ITEGoalInfo0, hide_debug_event, ITEGoalInfo),
ITEGoal = ITEGoalEx - ITEGoalInfo,
GoalEx = conj([LookUpGoal, ITEGoal]),
- goal_info_init(OrigNonLocals, OrigInstMapDelta, semidet, pure,
+ goal_info_init(OrigNonLocals, OrigInstMapDelta, semidet, impure,
Context, GoalInfo0),
goal_info_add_feature(GoalInfo0, hide_debug_event, GoalInfo),
Goal = GoalEx - GoalInfo,
- generate_gen_proc_table_info(TableInfo, Steps, InputVars, OutputVars,
+ generate_gen_proc_table_info(!.TableInfo, Steps, InputVars, OutputVars,
ProcTableInfo).
%-----------------------------------------------------------------------------%
@@ -1098,8 +1092,8 @@
prog_var::out, hlds_goal::out, proc_table_info::out) is det.
table_gen__create_new_non_goal(EvalMethod, Detism, OrigGoal, PredId, ProcId,
- HeadVars, HeadVarModes, VarTypes0, VarTypes, VarSet0, VarSet,
- TableInfo0, TableInfo, TableVar, Goal, ProcTableInfo) :-
+ HeadVars, HeadVarModes, !VarTypes, !VarSet, !TableInfo,
+ TableVar, Goal, ProcTableInfo) :-
% even if the original goal doesn't use all of the headvars,
% the code generated by the tabling transformation does,
% so we need to compute the nonlocals from the headvars rather
@@ -1109,95 +1103,95 @@
goal_info_get_instmap_delta(OrigGoalInfo, OrigInstMapDelta),
goal_info_get_context(OrigGoalInfo, Context),
- ModuleInfo = TableInfo0 ^ table_module_info,
+ ModuleInfo = !.TableInfo ^ table_module_info,
get_input_output_vars(HeadVars, HeadVarModes, ModuleInfo, InputVars,
OutputVars),
allocate_slot_numbers(OutputVars, 0, NumberedOutputVars),
list__length(NumberedOutputVars, BlockSize),
generate_non_lookup_goal(InputVars, PredId, ProcId, Context,
- VarTypes0, VarTypes1, VarSet0, VarSet1, TableInfo0, TableInfo1,
- TableVar, LookUpGoal, Steps),
- generate_call("table_nondet_is_complete", [TableVar], semidet,
- yes(semipure), [], ModuleInfo, Context, CompleteCheckGoal),
+ !VarTypes, !VarSet, !TableInfo, TableVar, LookUpGoal, Steps),
+
+ generate_new_table_var("Status", status_type, !VarTypes, !VarSet,
+ StatusVar),
+
+ generate_call("table_subgoal_status", [TableVar, StatusVar], det,
+ yes(semipure), [StatusVar - ground(unique, none)],
+ ModuleInfo, Context, StatusGoal),
generate_non_save_goal(NumberedOutputVars, TableVar, BlockSize, Context,
- VarTypes1, VarTypes2, VarSet1, VarSet2, TableInfo1, TableInfo,
- SaveAnsGoal0),
+ !VarTypes, !VarSet, !TableInfo, SaveAnsGoal),
generate_restore_all_goal(Detism, NumberedOutputVars, TableVar,
- ModuleInfo, Context, VarTypes2, VarTypes3, VarSet2, VarSet3,
- RestoreAllAnsGoal),
- generate_call("table_nondet_is_active", [TableVar], semidet,
- yes(semipure), [], ModuleInfo, Context, IsActiveCheckGoal),
- generate_suspend_goal(NumberedOutputVars, TableVar,
- ModuleInfo, Context, VarTypes3, VarTypes4, VarSet3, VarSet4,
- SuspendGoal),
- generate_loop_error_goal(TableInfo, Context, VarTypes4, VarTypes,
- VarSet4, VarSet, LoopErrorGoal),
+ ModuleInfo, Context, !VarTypes, !VarSet, RestoreAllAnsGoal),
+ generate_loop_error_goal(!.TableInfo, Context, infinite_recursion_msg,
+ !VarTypes, !VarSet, LoopErrorGoal),
generate_call("table_nondet_mark_as_active", [TableVar], det,
yes(impure), [], ModuleInfo, Context, MarkAsActiveGoal),
- generate_call("table_nondet_resume", [TableVar], det, yes(impure),
- [], ModuleInfo, Context, ResumeGoal0),
- append_fail(ResumeGoal0, ResumeGoal1),
true_goal(TrueGoal),
- fail_goal(FailGoal),
- ( EvalMethod = eval_memo ->
- SaveAnsGoal = SaveAnsGoal0,
- ActiveGoal = LoopErrorGoal
- ; EvalMethod = eval_loop_check ->
- SaveAnsGoal = TrueGoal,
- ActiveGoal = LoopErrorGoal
- ; EvalMethod = eval_minimal ->
- SaveAnsGoal = SaveAnsGoal0,
- ActiveGoal = SuspendGoal
+ (
+ EvalMethod = eval_memo,
+ AfterOrigGoal = SaveAnsGoal,
+ ActiveGoal = LoopErrorGoal,
+ CompleteGoal = RestoreAllAnsGoal
+ ;
+ EvalMethod = eval_loop_check,
+ generate_loop_error_goal(!.TableInfo, Context,
+ "detected internal error", !VarTypes, !VarSet,
+ LoopInternalErrorGoal),
+ AfterOrigGoal = TrueGoal,
+ ActiveGoal = LoopErrorGoal,
+ CompleteGoal = LoopInternalErrorGoal
;
- error(
- "table_gen__create_new_non_goal: unsupported evaluation model")
+ EvalMethod = eval_minimal,
+ generate_suspend_goal(NumberedOutputVars, TableVar,
+ ModuleInfo, Context, !VarTypes, !VarSet, SuspendGoal),
+ AfterOrigGoal = SaveAnsGoal,
+ ActiveGoal = SuspendGoal,
+ CompleteGoal = RestoreAllAnsGoal
+ ;
+ EvalMethod = eval_table_io(_, _),
+ error("table_gen__create_new_non_goal: table_io")
+ ;
+ EvalMethod = eval_normal,
+ error("table_gen__create_new_non_goal: normal")
),
- GenAnsGoalPart1Ex = conj([MarkAsActiveGoal, OrigGoal, SaveAnsGoal]),
- set__insert(OrigNonLocals, TableVar, GenAnsGoalPart1NonLocals),
+ MainEx = conj([MarkAsActiveGoal, OrigGoal, AfterOrigGoal]),
+ set__insert(OrigNonLocals, TableVar, MainNonLocals),
create_instmap_delta([MarkAsActiveGoal, OrigGoal, SaveAnsGoal],
- GenAnsGoalPart1IMD0),
- instmap_delta_restrict(GenAnsGoalPart1IMD0, GenAnsGoalPart1NonLocals,
- GenAnsGoalPart1IMD),
- goal_info_init(GenAnsGoalPart1NonLocals, GenAnsGoalPart1IMD, nondet,
- pure, Context, GenAnsGoalPart1GoalInfo0),
- goal_info_add_feature(GenAnsGoalPart1GoalInfo0, hide_debug_event,
- GenAnsGoalPart1GoalInfo),
- GenAnsGoalPart1 = GenAnsGoalPart1Ex - GenAnsGoalPart1GoalInfo,
+ MainIMD0),
+ instmap_delta_restrict(MainIMD0, MainNonLocals, MainIMD),
+ goal_info_init(MainNonLocals, MainIMD, nondet, impure, Context,
+ MainGoalInfo0),
+ goal_info_add_feature(MainGoalInfo0, hide_debug_event, MainGoalInfo),
+ MainGoal = MainEx - MainGoalInfo,
( EvalMethod = eval_minimal ->
- ResumeGoal = ResumeGoal1
- ;
- ResumeGoal = FailGoal
- ),
- GenAnsGoalEx = disj([GenAnsGoalPart1, ResumeGoal]),
- GenAnsGoal = GenAnsGoalEx - GenAnsGoalPart1GoalInfo,
-
- ITE1GoalEx = if_then_else([], IsActiveCheckGoal, ActiveGoal,
- GenAnsGoal),
- goal_info_add_feature(GenAnsGoalPart1GoalInfo, hide_debug_event,
- ITE1GoalInfo),
- ITE1Goal = ITE1GoalEx - ITE1GoalInfo,
-
- ( EvalMethod = eval_loop_check ->
- ITE2Goal = ITE1Goal
- ;
- ITE2GoalEx = if_then_else([], CompleteCheckGoal,
- RestoreAllAnsGoal, ITE1Goal),
- goal_info_add_feature(GenAnsGoalPart1GoalInfo,
- hide_debug_event, ITE2GoalInfo),
- ITE2Goal = ITE2GoalEx - ITE2GoalInfo
- ),
+ generate_call("table_nondet_resume", [TableVar], det,
+ yes(impure), [], ModuleInfo, Context, ResumeGoal0),
+ append_fail(ResumeGoal0, ResumeGoal),
+ InactiveEx = disj([MainGoal, ResumeGoal]),
+ InactiveGoal = InactiveEx - MainGoalInfo
+ ;
+ InactiveGoal = MainGoal
+ ),
+
+ mercury_table_builtin_module(TB),
+ SwitchArms = [
+ case(cons(qualified(TB, "inactive"), 0), InactiveGoal),
+ case(cons(qualified(TB, "complete"), 0), CompleteGoal),
+ case(cons(qualified(TB, "active"), 0), ActiveGoal)],
+ SwitchEx = switch(StatusVar, cannot_fail, SwitchArms),
+ goal_info_add_feature(MainGoalInfo, hide_debug_event, SwitchGoalInfo),
+ SwitchGoal = SwitchEx - SwitchGoalInfo,
- GoalEx = conj([LookUpGoal, ITE2Goal]),
- goal_info_init(OrigNonLocals, OrigInstMapDelta, nondet, pure,
+ GoalEx = conj([LookUpGoal, StatusGoal, SwitchGoal]),
+ goal_info_init(OrigNonLocals, OrigInstMapDelta, nondet, impure,
Context, GoalInfo0),
goal_info_add_feature(GoalInfo0, hide_debug_event, GoalInfo),
Goal = GoalEx - GoalInfo,
- generate_gen_proc_table_info(TableInfo, Steps, InputVars, OutputVars,
+ generate_gen_proc_table_info(!.TableInfo, Steps, InputVars, OutputVars,
ProcTableInfo).
%-----------------------------------------------------------------------------%
@@ -1262,7 +1256,8 @@
set__singleton_set(NonLocals0, TableVar),
set__insert_list(NonLocals0, Vars, NonLocals),
instmap_delta_from_assoc_list([], InstMapDelta),
- goal_info_init(NonLocals, InstMapDelta, det, pure, Context, GoalInfo0),
+ goal_info_init(NonLocals, InstMapDelta, det, impure, Context,
+ GoalInfo0),
goal_info_get_features(GoalInfo0, Features0),
set__insert(Features0, call_table_gen, Features),
goal_info_set_features(GoalInfo0, Features, GoalInfo),
@@ -1299,7 +1294,8 @@
set__insert_list(NonLocals0, Vars, NonLocals),
create_instmap_delta(Goals, InstMapDelta0),
instmap_delta_restrict(InstMapDelta0, NonLocals, InstMapDelta),
- goal_info_init(NonLocals, InstMapDelta, det, pure, Context, GoalInfo0),
+ goal_info_init(NonLocals, InstMapDelta, det, impure, Context,
+ GoalInfo0),
goal_info_get_features(GoalInfo0, Features0),
set__insert(Features0, call_table_gen, Features),
goal_info_set_features(GoalInfo0, Features, GoalInfo),
@@ -1371,7 +1367,7 @@
set__insert_list(NonLocals0, [TableVar, ArgVar],
NonLocals),
instmap_delta_from_assoc_list([], InstMapDelta),
- goal_info_init(NonLocals, InstMapDelta, det, pure,
+ goal_info_init(NonLocals, InstMapDelta, det, impure,
Context, GoalInfo),
Goal = conj([RangeUnifyGoal, LookupGoal]) - GoalInfo,
Step = table_trie_step_enum(EnumRange),
@@ -1459,7 +1455,7 @@
create_instmap_delta([BlockSizeVarUnifyGoal, CreateAnsBlockGoal
| SaveGoals], InstMapDelta0),
instmap_delta_restrict(InstMapDelta0, NonLocals, InstMapDelta),
- goal_info_init(NonLocals, InstMapDelta, det, pure, Context,
+ goal_info_init(NonLocals, InstMapDelta, det, impure, Context,
GoalInfo),
Goal = GoalEx - GoalInfo
;
@@ -1523,7 +1519,7 @@
create_instmap_delta(Goals, InstMapDelta0),
instmap_delta_restrict(InstMapDelta0, NonLocals, InstMapDelta),
goal_info_init(NonLocals, InstMapDelta, semidet,
- pure, Context, GoalInfo),
+ impure, Context, GoalInfo),
Goal = GoalEx - GoalInfo.
:- pred generate_save_goals(assoc_list(prog_var, int)::in, prog_var::in,
@@ -1617,7 +1613,8 @@
set__insert_list(NonLocals0, OutputVars, NonLocals),
create_instmap_delta(RestoreGoals, InstMapDelta0),
instmap_delta_restrict(InstMapDelta0, NonLocals, InstMapDelta),
- goal_info_init(NonLocals, InstMapDelta, det, pure, Context, GoalInfo),
+ goal_info_init(NonLocals, InstMapDelta, det, semipure, Context,
+ GoalInfo),
Goal = GoalEx - GoalInfo.
:- pred generate_restore_all_goal(determinism::in,
@@ -1653,8 +1650,8 @@
create_instmap_delta([ReturnAnsBlocksGoal | RestoreGoals],
InstMapDelta0),
instmap_delta_restrict(InstMapDelta0, NonLocals, InstMapDelta),
- goal_info_init(NonLocals, InstMapDelta, nondet,
- pure, Context, GoalInfo),
+ goal_info_init(NonLocals, InstMapDelta, nondet, semipure, Context,
+ GoalInfo),
Goal = GoalEx - GoalInfo.
:- pred generate_restore_goals(assoc_list(prog_var, int)::in, prog_var::in,
@@ -1727,18 +1724,21 @@
create_instmap_delta([ReturnAnsBlocksGoal | RestoreGoals],
InstMapDelta0),
instmap_delta_restrict(InstMapDelta0, NonLocals, InstMapDelta),
- goal_info_init(NonLocals, InstMapDelta, nondet,
- pure, Context, GoalInfo),
+ goal_info_init(NonLocals, InstMapDelta, nondet, impure, Context,
+ GoalInfo),
Goal = GoalEx - GoalInfo.
%-----------------------------------------------------------------------------%
+:- func infinite_recursion_msg = string.
+
+infinite_recursion_msg = "detected infinite recursion".
+
:- pred generate_loop_error_goal(table_info::in, term__context::in,
- map(prog_var, type)::in, map(prog_var, type)::out,
+ string::in, map(prog_var, type)::in, map(prog_var, type)::out,
prog_varset::in, prog_varset::out, hlds_goal::out) is det.
-generate_loop_error_goal(TableInfo, Context, VarTypes0, VarTypes,
- VarSet0, VarSet, Goal) :-
+generate_loop_error_goal(TableInfo, Context, Msg, !VarTypes, !VarSet, Goal) :-
ModuleInfo = TableInfo ^ table_module_info,
PredInfo = TableInfo ^ table_cur_pred_info,
@@ -1749,20 +1749,19 @@
hlds_out__pred_or_func_to_str(PredOrFunc, PredOrFuncS),
prog_out__sym_name_to_string(qualified(Module, Name), NameS),
string__int_to_string(Arity, ArityS),
- string__append_list(["detected infinite recursion in ", PredOrFuncS,
+ string__append_list([Msg, " in ", PredOrFuncS,
" ", NameS, "/", ArityS], Message),
- gen_string_construction("MessageS", Message, VarTypes0, VarTypes,
- VarSet0, VarSet, MessageVar, MessageConsGoal),
+ gen_string_construction("MessageS", Message, !VarTypes, !VarSet,
+ MessageVar, MessageConsGoal),
generate_call("table_loopcheck_error", [MessageVar], erroneous,
no, [], ModuleInfo, Context, CallGoal),
GoalEx = conj([MessageConsGoal, CallGoal]),
set__init(NonLocals),
- create_instmap_delta([MessageConsGoal, CallGoal],
- InstMapDelta0),
+ create_instmap_delta([MessageConsGoal, CallGoal], InstMapDelta0),
instmap_delta_restrict(InstMapDelta0, NonLocals, InstMapDelta),
- goal_info_init(NonLocals, InstMapDelta, erroneous, pure,
+ goal_info_init(NonLocals, InstMapDelta, erroneous, impure,
Context, GoalInfo),
Goal = GoalEx - GoalInfo.
@@ -1795,8 +1794,8 @@
goal_info_get_nonlocals(GoalInfo, NonLocals),
goal_info_get_context(GoalInfo, Context),
instmap_delta_init_unreachable(UnreachInstMapDelta),
- goal_info_init(NonLocals, UnreachInstMapDelta, failure, pure, Context,
- ConjGoalInfo),
+ goal_info_init(NonLocals, UnreachInstMapDelta, failure, impure,
+ Context, ConjGoalInfo),
fail_goal(FailGoal),
GoalAndThenFail = conj([Goal, FailGoal]) - ConjGoalInfo.
@@ -1823,6 +1822,12 @@
:- func node_type = (type).
node_type = c_pointer_type.
+
+:- func status_type = (type).
+
+status_type = Type :-
+ mercury_table_builtin_module(TB),
+ construct_type(qualified(TB, "subgoal_status") - 0, [], Type).
:- pred get_input_output_vars(list(prog_var)::in, list(mode)::in,
module_info::in, list(prog_var)::out, list(prog_var)::out) is det.
cvs diff: Diffing compiler/notes
cvs diff: Diffing debian
cvs diff: Diffing deep_profiler
cvs diff: Diffing deep_profiler/notes
cvs diff: Diffing doc
Index: doc/user_guide.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/user_guide.texi,v
retrieving revision 1.360
diff -u -b -r1.360 user_guide.texi
--- doc/user_guide.texi 11 Mar 2003 02:44:21 -0000 1.360
+++ doc/user_guide.texi 13 Mar 2003 06:50:03 -0000
@@ -3183,10 +3183,35 @@
of the Mercury implementation.
@sp 1
@table @code
+ at item subgoal @var{n}
+ at kindex subgoal (mdb command)
+In minimal model grades,
+prints the details of the specified subgoal.
+In other grades, it reports an error.
+ at sp 1
+ at item consumer @var{n}
+ at kindex consumer (mdb command)
+In minimal model grades,
+prints the details of the specified consumer.
+In other grades, it reports an error.
+ at sp 1
@item gen_stack
@kindex gen_stack (mdb command)
-Prints the contents of the frames on the generator stack,
-which is part of the implementation of minimal model tabling.
+In minimal model grades,
+prints the contents of the frames on the generator stack.
+In other grades, it reports an error.
+ at sp 1
+ at item cut_stack
+ at kindex cut_stack (mdb command)
+In minimal model grades,
+prints the contents of the frames on the cut stack.
+In other grades, it reports an error.
+ at sp 1
+ at item pneg_stack
+ at kindex pneg_stack (mdb command)
+In minimal model grades,
+prints the contents of the frames on the possible negated context stack.
+In other grades, it reports an error.
@sp 1
@item nondet_stack [-d]
@kindex nondet_stack (mdb command)
cvs diff: Diffing extras
cvs diff: Diffing extras/aditi
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/concurrency
cvs diff: Diffing extras/curs
cvs diff: Diffing extras/curs/samples
cvs diff: Diffing extras/curses
cvs diff: Diffing extras/curses/sample
cvs diff: Diffing extras/dynamic_linking
cvs diff: Diffing extras/graphics
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/graphics/samples/pent
cvs diff: Diffing extras/lazy_evaluation
cvs diff: Diffing extras/lex
cvs diff: Diffing extras/lex/samples
cvs diff: Diffing extras/lex/tests
cvs diff: Diffing extras/logged_output
cvs diff: Diffing extras/moose
cvs diff: Diffing extras/moose/samples
cvs diff: Diffing extras/morphine
cvs diff: Diffing extras/morphine/non-regression-tests
cvs diff: Diffing extras/morphine/scripts
cvs diff: Diffing extras/morphine/source
cvs diff: Diffing extras/odbc
cvs diff: Diffing extras/posix
cvs diff: Diffing extras/quickcheck
cvs diff: Diffing extras/quickcheck/tutes
cvs diff: Diffing extras/references
cvs diff: Diffing extras/references/samples
cvs diff: Diffing extras/references/tests
cvs diff: Diffing extras/stream
cvs diff: Diffing extras/trailed_update
cvs diff: Diffing extras/trailed_update/samples
cvs diff: Diffing extras/trailed_update/tests
cvs diff: Diffing extras/xml
cvs diff: Diffing extras/xml/samples
cvs diff: Diffing java
cvs diff: Diffing java/library
cvs diff: Diffing java/runtime
cvs diff: Diffing library
Index: library/table_builtin.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/table_builtin.m,v
retrieving revision 1.27
diff -u -b -r1.27 table_builtin.m
--- library/table_builtin.m 3 Mar 2003 03:29:38 -0000 1.27
+++ library/table_builtin.m 12 Mar 2003 08:30:07 -0000
@@ -685,6 +685,17 @@
:- semipure pred table_multi_return_all_ans(ml_subgoal_table_node::in,
ml_answer_block::out) is multi.
+ % This type should correspond exactly to the type MR_SubgoalStatus
+ % defined in runtime/mercury_tabling.h.
+
+:- type subgoal_status
+ ---> inactive
+ ; active
+ ; complete.
+
+:- semipure pred table_subgoal_status(ml_subgoal_table_node::in,
+ subgoal_status::out) is det.
+
% N.B. interface continued below
%-----------------------------------------------------------------------------%
@@ -721,25 +732,51 @@
subgoal = MR_TABLE_NEW(MR_Subgoal);
- subgoal->status = MR_SUBGOAL_INACTIVE;
- subgoal->leader = NULL;
- subgoal->followers = MR_TABLE_NEW(MR_SubgoalListNode);
- subgoal->followers->item = subgoal;
- subgoal->followers->next = NULL;
- subgoal->followers_tail = &(subgoal->followers->next);
- subgoal->answer_table = (MR_Word) NULL;
- subgoal->num_ans = 0;
- subgoal->answer_list = NULL;
- subgoal->answer_list_tail = &subgoal->answer_list;
- subgoal->consumer_list = NULL;
- subgoal->consumer_list_tail = &subgoal->consumer_list;
+ subgoal->MR_sg_status = MR_SUBGOAL_INACTIVE;
+ subgoal->MR_sg_leader = NULL;
+ subgoal->MR_sg_followers = MR_TABLE_NEW(MR_SubgoalListNode);
+ subgoal->MR_sg_followers->MR_sl_item = subgoal;
+ subgoal->MR_sg_followers->MR_sl_next = NULL;
+ subgoal->MR_sg_followers_tail =
+ &(subgoal->MR_sg_followers->MR_sl_next);
+ subgoal->MR_sg_answer_table = (MR_Word) NULL;
+ subgoal->MR_sg_num_ans = 0;
+ subgoal->MR_sg_answer_list = NULL;
+ subgoal->MR_sg_answer_list_tail =
+ &subgoal->MR_sg_answer_list;
+ subgoal->MR_sg_consumer_list = NULL;
+ subgoal->MR_sg_consumer_list_tail =
+ &subgoal->MR_sg_consumer_list;
#ifdef MR_TABLE_DEBUG
+ /*
+ ** MR_subgoal_debug_cur_proc refers to the last procedure
+ ** that executed a call event, if any. If the procedure that is
+ ** executing table_nondet_setup is traced, this will be that
+ ** procedure, and recording the layout structure of the
+ ** processor in the subgoal allows us to interpret the contents
+ ** of the subgoal's answer tables. If the procedure executing
+ ** table_nondet_setup is not traced, then the layout structure
+ ** belongs to another procedure and the any use of the
+ ** MR_sg_proc_layout field will probably cause a core dump.
+ ** For implementors debugging minimal model tabling, this is
+ ** the right tradeoff.
+ */
+ subgoal->MR_sg_proc_layout = MR_subgoal_debug_cur_proc;
+
+ MR_enter_subgoal_debug(subgoal);
+
if (MR_tabledebug) {
- printf(""setting up table %p -> %p, "",
- table, subgoal);
+ printf(""setting up subgoal %p -> %s, "",
+ table, MR_subgoal_addr_name(subgoal));
printf(""answer slot %p\\n"",
- subgoal->answer_list_tail);
+ subgoal->MR_sg_answer_list_tail);
+ if (subgoal->MR_sg_proc_layout != NULL) {
+ printf(""proc: "");
+ MR_print_proc_id(stdout,
+ subgoal->MR_sg_proc_layout);
+ printf(""\\n"");
+ }
}
if (MR_maxfr != MR_curfr) {
@@ -747,13 +784,7 @@
""MR_maxfr != MR_curfr at table setup\\n"");
}
#endif
-#ifdef MR_HIGHLEVEL_CODE
- MR_fatal_error(""sorry, not implemented: ""
- ""minimal_model tabling with --high-level-code"");
-#else
- subgoal->generator_maxfr = MR_prevfr_slot(MR_maxfr);
- subgoal->generator_sp = MR_sp;
-#endif
+ subgoal->MR_sg_generator_fr = MR_curfr;
table->MR_subgoal = subgoal;
}
T = T0;
@@ -801,7 +832,7 @@
table = T;
SUCCESS_INDICATOR =
- (table->MR_subgoal->status == MR_SUBGOAL_COMPLETE);
+ (table->MR_subgoal->MR_sg_status == MR_SUBGOAL_COMPLETE);
#else
MR_fatal_error(""minimal model code entered when not enabled"");
#endif
@@ -817,7 +848,7 @@
table = T;
SUCCESS_INDICATOR =
- (table->MR_subgoal->status == MR_SUBGOAL_ACTIVE);
+ (table->MR_subgoal->MR_sg_status == MR_SUBGOAL_ACTIVE);
#else
MR_fatal_error(""minimal model code entered when not enabled"");
#endif
@@ -834,7 +865,7 @@
MR_push_generator(MR_curfr, table);
MR_register_generator_ptr(table);
- table->MR_subgoal->status = MR_SUBGOAL_ACTIVE;
+ table->MR_subgoal->MR_sg_status = MR_SUBGOAL_ACTIVE;
#else
MR_fatal_error(""minimal model code entered when not enabled"");
#endif
@@ -849,7 +880,7 @@
table = T;
- AT = (MR_TrieNode) &(table->MR_subgoal->answer_table);
+ AT = (MR_TrieNode) &(table->MR_subgoal->MR_sg_answer_table);
#else
MR_fatal_error(""minimal model code entered when not enabled"");
#endif
@@ -893,7 +924,7 @@
table = T;
subgoal = table->MR_subgoal;
- subgoal->num_ans++;
+ subgoal->MR_sg_num_ans++;
/*
**
@@ -903,22 +934,25 @@
*/
answer_node = MR_TABLE_NEW(MR_AnswerListNode);
- answer_node->answer_num = subgoal->num_ans;
- answer_node->answer_data.MR_integer = 0;
- answer_node->next_answer = NULL;
+ answer_node->MR_aln_answer_num = subgoal->MR_sg_num_ans;
+ answer_node->MR_aln_answer_data.MR_integer = 0;
+ answer_node->MR_aln_next_answer = NULL;
#ifdef MR_TABLE_DEBUG
if (MR_tabledebug) {
- printf(""new answer slot %d at %p(%p), storing into %p\\n"",
- subgoal->num_ans, answer_node,
- &answer_node->answer_data, subgoal->answer_list_tail);
+ printf(""%s: new answer slot %d at %p(%p)\n"",
+ MR_subgoal_addr_name(subgoal),
+ subgoal->MR_sg_num_ans, answer_node,
+ &answer_node->MR_aln_answer_data);
+ printf(""\tstoring into %p\\n"",
+ subgoal->MR_sg_answer_list_tail);
}
#endif
- *(subgoal->answer_list_tail) = answer_node;
- subgoal->answer_list_tail = &(answer_node->next_answer);
+ *(subgoal->MR_sg_answer_list_tail) = answer_node;
+ subgoal->MR_sg_answer_list_tail = &(answer_node->MR_aln_next_answer);
- Slot = (MR_Word) &(answer_node->answer_data);
+ Slot = (MR_TrieNode) &(answer_node->MR_aln_answer_data);
#endif
").
@@ -961,12 +995,12 @@
MR_TrieNode table;
table = T;
- CurNode = table->MR_subgoal->answer_list;
+ CurNode = table->MR_subgoal->MR_sg_answer_list;
#ifdef MR_TABLE_DEBUG
if (MR_tabledebug) {
- printf(""restoring all answers in %p -> %p\\n"",
- table, table->MR_subgoal);
+ printf(""restoring all answers in %p -> %s\\n"",
+ table, MR_subgoal_addr_name(table->MR_subgoal));
}
#endif
#else
@@ -985,8 +1019,8 @@
if (CurNode0 == NULL) {
SUCCESS_INDICATOR = MR_FALSE;
} else {
- AnswerBlock = &CurNode0->answer_data;
- CurNode = CurNode0->next_answer;
+ AnswerBlock = &CurNode0->MR_aln_answer_data;
+ CurNode = CurNode0->MR_aln_next_answer;
SUCCESS_INDICATOR = MR_TRUE;
}
#else
@@ -994,6 +1028,17 @@
#endif
").
+:- pragma foreign_proc("C",
+ table_subgoal_status(T::in, Status::out),
+ [will_not_call_mercury],
+"
+#ifdef MR_USE_MINIMAL_MODEL
+ Status = MR_CONVERT_C_ENUM_CONSTANT(T->MR_subgoal->MR_sg_status);
+#else
+ MR_fatal_error(""minimal model code entered when not enabled"");
+#endif
+").
+
:- pragma promise_semipure(table_nondet_is_complete/1).
table_nondet_is_complete(_) :-
% This version is only used for back-ends for which there is no
@@ -1045,6 +1090,13 @@
% matching foreign_proc version.
impure private_builtin__imp,
private_builtin__sorry("return_next_answer").
+
+:- pragma promise_semipure(table_subgoal_status/2).
+table_subgoal_status(_, _) :-
+ % This version is only used for back-ends for which there is no
+ % matching foreign_proc version.
+ impure private_builtin__imp,
+ private_builtin__sorry("table_subgoal_status").
%-----------------------------------------------------------------------------%
cvs diff: Diffing profiler
cvs diff: Diffing robdd
cvs diff: Diffing runtime
Index: runtime/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/Mmakefile,v
retrieving revision 1.101
diff -u -b -r1.101 Mmakefile
--- runtime/Mmakefile 13 Mar 2003 01:47:03 -0000 1.101
+++ runtime/Mmakefile 14 Mar 2003 05:00:21 -0000
@@ -14,8 +14,8 @@
mercury_accurate_gc.h \
mercury_agc_debug.h \
mercury_array_macros.h \
- mercury_builtin_types.h \
mercury_bootstrap.h \
+ mercury_builtin_types.h \
mercury_calls.h \
mercury_conf.h \
mercury_conf_bootstrap.h \
@@ -28,8 +28,8 @@
mercury_deep_copy.h \
mercury_deep_profiling.h \
mercury_deep_profiling_hand.h \
- mercury_dummy.h \
mercury_dlist.h \
+ mercury_dummy.h \
mercury_dword.h \
mercury_engine.h \
mercury_file.h \
@@ -48,8 +48,9 @@
mercury_layout_util.h \
mercury_library_types.h \
mercury_memory.h \
- mercury_memory_zones.h \
mercury_memory_handlers.h \
+ mercury_memory_zones.h \
+ mercury_minimal_model.h \
mercury_misc.h \
mercury_overflow.h \
mercury_prof.h \
@@ -61,10 +62,10 @@
mercury_regs.h \
mercury_runtime_util.h \
mercury_signal.h \
- mercury_std.h \
mercury_stack_layout.h \
mercury_stack_trace.h \
mercury_stacks.h \
+ mercury_std.h \
mercury_string.h \
mercury_tabling.h \
mercury_tabling_macros.h \
@@ -73,10 +74,10 @@
mercury_timing.h \
mercury_trace_base.h \
mercury_trail.h \
- mercury_types.h \
mercury_type_desc.h \
mercury_type_info.h \
mercury_type_tables.h \
+ mercury_types.h \
mercury_wrapper.h \
$(LIB_DLL_H)
@@ -146,6 +147,7 @@
mercury_memory.c \
mercury_memory_handlers.c \
mercury_memory_zones.c \
+ mercury_minimal_model.c \
mercury_misc.c \
mercury_prof.c \
mercury_prof_mem.c \
Index: runtime/mercury_context.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_context.c,v
retrieving revision 1.35
diff -u -b -r1.35 mercury_context.c
--- runtime/mercury_context.c 12 Mar 2003 06:19:04 -0000 1.35
+++ runtime/mercury_context.c 12 Mar 2003 06:19:37 -0000
@@ -129,10 +129,9 @@
if (c->MR_ctxt_genstack_zone != NULL) {
MR_reset_redzone(c->MR_ctxt_genstack_zone);
} else {
- c->MR_ctxt_genstack_zone = MR_create_zone(
- "generatorstack", 0,
- MR_generatorstack_size, MR_next_offset(),
- MR_generatorstack_zone_size, MR_default_handler);
+ c->MR_ctxt_genstack_zone = MR_create_zone("genstack", 0,
+ MR_genstack_size, MR_next_offset(),
+ MR_genstack_zone_size, MR_default_handler);
}
c->MR_ctxt_gen_next = 0;
@@ -144,6 +143,15 @@
MR_cutstack_zone_size, MR_default_handler);
}
c->MR_ctxt_cut_next = 0;
+
+ if (c->MR_ctxt_pnegstack_zone != NULL) {
+ MR_reset_redzone(c->MR_ctxt_pnegstack_zone);
+ } else {
+ c->MR_ctxt_pnegstack_zone = MR_create_zone("pnegstack", 0,
+ MR_pnegstack_size, MR_next_offset(),
+ MR_pnegstack_zone_size, MR_default_handler);
+ }
+ c->MR_ctxt_pneg_next = 0;
#endif /* MR_USE_MINIMAL_MODEL */
#endif /* !MR_HIGHLEVEL_CODE */
Index: runtime/mercury_context.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_context.h,v
retrieving revision 1.22
diff -u -b -r1.22 mercury_context.h
--- runtime/mercury_context.h 21 Aug 2002 11:27:41 -0000 1.22
+++ runtime/mercury_context.h 13 Dec 2002 03:59:06 -0000
@@ -111,6 +111,10 @@
/* pointer to the cutstack_zone for this context */
MR_Integer MR_ctxt_cut_next;
/* saved cut stack index for this context */
+ MR_MemoryZone *MR_ctxt_pnegstack_zone;
+ /* pointer to the pnegstack_zone for this context */
+ MR_Integer MR_ctxt_pneg_next;
+ /* saved pneg stack index for this context */
#endif /* MR_USE_MINIMAL_MODEL */
#endif /* !MR_HIGHLEVEL_CODE */
@@ -352,6 +356,7 @@
MR_IF_USE_MINIMAL_MODEL( \
MR_gen_next = load_context_c->MR_ctxt_gen_next; \
MR_cut_next = load_context_c->MR_ctxt_cut_next; \
+ MR_pneg_next = load_context_c->MR_ctxt_pneg_next;\
) \
) \
MR_IF_USE_TRAIL( \
@@ -372,12 +377,17 @@
load_context_c->MR_ctxt_genstack_zone; \
MR_ENGINE(MR_eng_context).MR_ctxt_cutstack_zone = \
load_context_c->MR_ctxt_cutstack_zone; \
- MR_gen_stack = (MR_GeneratorStackFrame *) \
+ MR_ENGINE(MR_eng_context).MR_ctxt_pnegstack_zone = \
+ load_context_c->MR_ctxt_pnegstack_zone; \
+ MR_gen_stack = (MR_GenStackFrame *) \
MR_ENGINE(MR_eng_context). \
MR_ctxt_genstack_zone; \
MR_cut_stack = (MR_CutStackFrame *) \
MR_ENGINE(MR_eng_context). \
MR_ctxt_cutstack_zone; \
+ MR_pneg_stack = (MR_PNegStackFrame *) \
+ MR_ENGINE(MR_eng_context). \
+ MR_ctxt_pnegstack_zone; \
) \
) \
MR_set_min_heap_reclamation_point(load_context_c); \
@@ -396,6 +406,7 @@
MR_IF_USE_MINIMAL_MODEL( \
save_context_c->MR_ctxt_gen_next = MR_gen_next; \
save_context_c->MR_ctxt_cut_next = MR_cut_next; \
+ save_context_c->MR_ctxt_pneg_next = MR_pneg_next;\
) \
) \
MR_IF_USE_TRAIL( \
@@ -420,12 +431,18 @@
save_context_c->MR_ctxt_cutstack_zone = \
MR_ENGINE(MR_eng_context). \
MR_ctxt_cutstack_zone; \
- assert(MR_gen_stack == (MR_GeneratorStackFrame *) \
+ save_context_c->MR_ctxt_pnegstack_zone = \
+ MR_ENGINE(MR_eng_context). \
+ MR_ctxt_pnegstack_zone; \
+ assert(MR_gen_stack == (MR_GenStackFrame *) \
MR_ENGINE(MR_eng_context). \
MR_ctxt_genstack_zone); \
assert(MR_cut_stack == (MR_CutStackFrame *) \
MR_ENGINE(MR_eng_context). \
MR_ctxt_cutstack_zone); \
+ assert(MR_pneg_stack == (MR_PNegStackFrame *) \
+ MR_ENGINE(MR_eng_context). \
+ MR_ctxt_pnegstack_zone); \
) \
) \
MR_save_hp_in_context(save_context_c); \
Index: runtime/mercury_debug.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_debug.c,v
retrieving revision 1.13
diff -u -b -r1.13 mercury_debug.c
--- runtime/mercury_debug.c 17 Jan 2003 05:56:50 -0000 1.13
+++ runtime/mercury_debug.c 14 Mar 2003 04:39:01 -0000
@@ -681,7 +681,7 @@
void
MR_print_detstackptr(FILE *fp, const MR_Word *s)
{
- fprintf(fp, "det %3ld ",
+ fprintf(fp, "det %3ld",
(long) (MR_Integer)
(s - MR_CONTEXT(MR_ctxt_detstack_zone)->min));
Index: runtime/mercury_engine.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_engine.c,v
retrieving revision 1.40
diff -u -b -r1.40 mercury_engine.c
--- runtime/mercury_engine.c 3 Mar 2003 09:03:16 -0000 1.40
+++ runtime/mercury_engine.c 12 Mar 2003 08:09:52 -0000
@@ -37,6 +37,27 @@
MR_bool MR_debugflag[MR_MAXFLAG];
+MR_Debug_Flag_Info MR_debug_flag_info[MR_MAXFLAG] = {
+ { "prog", MR_PROGFLAG },
+ { "goto", MR_GOTOFLAG },
+ { "call", MR_CALLFLAG },
+ { "heap", MR_HEAPFLAG },
+ { "detstack", MR_DETSTACKFLAG },
+ { "nondstack", MR_NONDSTACKFLAG },
+ { "final", MR_FINALFLAG },
+ { "mem", MR_MEMFLAG },
+ { "sreg", MR_SREGFLAG },
+ { "trace", MR_TRACEFLAG },
+ { "table", MR_TABLEFLAG },
+ { "hash", MR_TABLEHASHFLAG },
+ { "tablestack", MR_TABLESTACKFLAG },
+ { "unbuf", MR_UNBUFFLAG },
+ { "agc", MR_AGC_FLAG },
+ { "ordreg", MR_ORDINARY_REG_FLAG },
+ { "anyreg", MR_ANY_REG_FLAG },
+ { "detail", MR_DETAILFLAG }
+};
+
#ifndef MR_THREAD_SAFE
MercuryEngine MR_engine_base;
#endif
Index: runtime/mercury_engine.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_engine.h,v
retrieving revision 1.28
diff -u -b -r1.28 mercury_engine.h
--- runtime/mercury_engine.h 3 Mar 2003 09:03:16 -0000 1.28
+++ runtime/mercury_engine.h 12 Mar 2003 08:40:19 -0000
@@ -39,7 +39,8 @@
/*
** These #defines, except MR_MAXFLAG, should not be used anywhere
-** except in the immediately following block of #defines.
+** except in the immediately following block of #defines, and in the
+** array that maps these names to their slots in the source file.
*/
#define MR_PROGFLAG 0
@@ -131,6 +132,13 @@
#define MR_ordregdebug MR_debugflag[MR_ORDINARY_REG_FLAG]
#define MR_anyregdebug MR_debugflag[MR_ANY_REG_FLAG]
#define MR_detaildebug MR_debugflag[MR_DETAILFLAG]
+
+typedef struct {
+ const char *MR_debug_flag_name;
+ int MR_debug_flag_index;
+} MR_Debug_Flag_Info;
+
+extern MR_Debug_Flag_Info MR_debug_flag_info[MR_MAXFLAG];
/*
** MR_setjmp and MR_longjmp are wrappers around setjmp and longjmp
Index: runtime/mercury_imp.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_imp.h,v
retrieving revision 1.19
diff -u -b -r1.19 mercury_imp.h
--- runtime/mercury_imp.h 13 Feb 2002 09:56:40 -0000 1.19
+++ runtime/mercury_imp.h 7 Mar 2003 10:18:52 -0000
@@ -1,5 +1,5 @@
/*
-** Copyright (C) 1993-1998, 2000 The University of Melbourne.
+** Copyright (C) 1993-1998,2000,2003 The University of Melbourne.
** This file may only be copied under the terms of the GNU Library General
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
@@ -80,8 +80,10 @@
#include "mercury_misc.h"
#include "mercury_tabling.h"
+#ifdef MR_USE_MINIMAL_MODEL
+#include "mercury_minimal_model.h"
+#endif
#include "mercury_grade.h"
-
#endif /* not MERCURY_IMP_H */
Index: runtime/mercury_memory.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_memory.c,v
retrieving revision 1.31
diff -u -b -r1.31 mercury_memory.c
--- runtime/mercury_memory.c 21 Aug 2002 11:27:43 -0000 1.31
+++ runtime/mercury_memory.c 7 Dec 2002 13:40:27 -0000
@@ -103,8 +103,9 @@
*/
#ifdef MR_USE_MINIMAL_MODEL
- MR_MemoryZone *MR_generatorstack_zone;
+ MR_MemoryZone *MR_genstack_zone;
MR_MemoryZone *MR_cutstack_zone;
+ MR_MemoryZone *MR_pnegstack_zone;
#endif
size_t MR_unit;
@@ -168,14 +169,18 @@
MR_nondstack_zone_size = MR_round_up(MR_nondstack_zone_size * 1024,
MR_unit);
#ifdef MR_USE_MINIMAL_MODEL
- MR_generatorstack_size = MR_round_up(MR_generatorstack_size * 1024,
+ MR_genstack_size = MR_round_up(MR_genstack_size * 1024,
MR_unit);
- MR_generatorstack_zone_size = MR_round_up(
- MR_generatorstack_zone_size * 1024,
+ MR_genstack_zone_size = MR_round_up(
+ MR_genstack_zone_size * 1024,
MR_unit);
MR_cutstack_size = MR_round_up(MR_cutstack_size * 1024,
MR_unit);
MR_cutstack_zone_size = MR_round_up(MR_cutstack_zone_size * 1024,
+ MR_unit);
+ MR_pnegstack_size = MR_round_up(MR_pnegstack_size * 1024,
+ MR_unit);
+ MR_pnegstack_zone_size = MR_round_up(MR_pnegstack_zone_size * 1024,
MR_unit);
#endif
Index: runtime/mercury_minimal_model.c
===================================================================
RCS file: runtime/mercury_minimal_model.c
diff -N runtime/mercury_minimal_model.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ runtime/mercury_minimal_model.c 14 Mar 2003 04:49:43 -0000
@@ -0,0 +1,1574 @@
+/*
+** vim: ts=4 sw=4 expandtab
+*/
+/*
+** Copyright (C) 2003 The University of Melbourne.
+** This file may only be copied under the terms of the GNU Library General
+** Public License - see the file COPYING.LIB in the Mercury distribution.
+*/
+
+/*
+** This module contains the functions related specifically to minimal model
+** tabling.
+*/
+
+#include "mercury_imp.h"
+#include "mercury_array_macros.h"
+#include "mercury_tabling.h"
+#include "mercury_minimal_model.h"
+
+#include <stdio.h>
+
+#ifdef MR_USE_MINIMAL_MODEL
+
+static MR_Word *nearest_common_ancestor(MR_Word *fr1, MR_Word *fr2);
+static void save_state(MR_SavedState *saved_state, MR_Word *generator_fr,
+ const char *who, const char *what);
+static void restore_state(MR_SavedState *saved_state, const char *who,
+ const char *what);
+static void extend_consumer_stacks(MR_Subgoal *leader,
+ MR_Consumer *suspension);
+static void make_subgoal_follow_leader(MR_Subgoal *this_follower,
+ MR_Subgoal *leader);
+static void print_saved_state(FILE *fp, MR_SavedState *saved_state);
+static void print_stack_segment(FILE *fp, MR_Word *segment,
+ MR_Integer size);
+
+/*---------------------------------------------------------------------------*/
+
+/*
+** This part of the file maintains data structures that can be used
+** to debug minimal model tabling. It does so by allowing the debugger
+** to refer to tabling data structures such as subgoals and consumers
+** by small, easily remembered numbers, not memory addresses.
+*/
+
+/* set by MR_trace_event, used by table_nondet_setup */
+MR_Proc_Layout *MR_subgoal_debug_cur_proc = NULL;
+
+struct MR_ConsumerDebug_Struct
+{
+ MR_Consumer *MR_cod_consumer;
+ int MR_cod_sequence_num;
+ int MR_cod_version_num;
+ int MR_cod_valid;
+};
+
+struct MR_SubgoalDebug_Struct
+{
+ MR_Subgoal *MR_sgd_subgoal;
+ int MR_sgd_sequence_num;
+ int MR_sgd_version_num;
+ int MR_sgd_valid;
+};
+
+#define MR_CONSUMER_DEBUG_INIT 10
+#define MR_SUBGOAL_DEBUG_INIT 10
+#define MR_NAME_BUF 1024
+
+static MR_ConsumerDebug *MR_consumer_debug_infos = NULL;
+static int MR_consumer_debug_info_next = 0;
+static int MR_consumer_debug_info_max = 0;
+
+static MR_SubgoalDebug *MR_subgoal_debug_infos = NULL;
+static int MR_subgoal_debug_info_next = 0;
+static int MR_subgoal_debug_info_max = 0;
+
+void
+MR_enter_consumer_debug(MR_Consumer *consumer)
+{
+ int i;
+
+ for (i = 0; i < MR_consumer_debug_info_next; i++) {
+ if (MR_consumer_debug_infos[i].MR_cod_consumer == consumer) {
+ MR_consumer_debug_infos[i].MR_cod_version_num++;
+ MR_consumer_debug_infos[i].MR_cod_valid = MR_TRUE;
+ return;
+ }
+ }
+
+ MR_ensure_room_for_next(MR_consumer_debug_info, MR_ConsumerDebug,
+ MR_CONSUMER_DEBUG_INIT);
+ i = MR_consumer_debug_info_next;
+ MR_consumer_debug_infos[i].MR_cod_consumer = consumer;
+ MR_consumer_debug_infos[i].MR_cod_sequence_num = i;
+ MR_consumer_debug_infos[i].MR_cod_version_num = 0;
+ MR_consumer_debug_infos[i].MR_cod_valid = MR_TRUE;
+ MR_consumer_debug_info_next++;
+}
+
+MR_ConsumerDebug *
+MR_lookup_consumer_debug_addr(MR_Consumer *consumer)
+{
+ int i;
+
+ for (i = 0; i < MR_consumer_debug_info_next; i++) {
+ if (MR_consumer_debug_infos[i].MR_cod_consumer == consumer) {
+ return &MR_consumer_debug_infos[i];
+ }
+ }
+
+ return NULL;
+}
+
+MR_ConsumerDebug *
+MR_lookup_consumer_debug_num(int consumer_index)
+{
+ int i;
+
+ for (i = 0; i < MR_consumer_debug_info_next; i++) {
+ if (MR_consumer_debug_infos[i].MR_cod_sequence_num == consumer_index) {
+ return &MR_consumer_debug_infos[i];
+ }
+ }
+
+ return NULL;
+}
+
+const char *
+MR_consumer_debug_name(MR_ConsumerDebug *consumer_debug)
+{
+ const char *warning;
+ char buf[MR_NAME_BUF];
+
+ if (consumer_debug == NULL) {
+ return "unknown";
+ }
+
+ if (consumer_debug->MR_cod_valid) {
+ warning = "";
+ } else {
+ warning = " INVALID";
+ }
+
+ if (consumer_debug->MR_cod_version_num > 0) {
+ sprintf(buf, "con %d/%d (%p)%s", consumer_debug->MR_cod_sequence_num,
+ consumer_debug->MR_cod_version_num,
+ consumer_debug->MR_cod_consumer, warning);
+ } else {
+ sprintf(buf, "con %d (%p)%s", consumer_debug->MR_cod_sequence_num,
+ consumer_debug->MR_cod_consumer, warning);
+ }
+
+ return strdup(buf);
+}
+
+const char *
+MR_consumer_addr_name(MR_Consumer *consumer)
+{
+ MR_ConsumerDebug *consumer_debug;
+
+ if (consumer == NULL) {
+ return "NULL";
+ }
+
+ consumer_debug = MR_lookup_consumer_debug_addr(consumer);
+ return MR_consumer_debug_name(consumer_debug);
+}
+
+const char *
+MR_consumer_num_name(int consumer_index)
+{
+ MR_ConsumerDebug *consumer_debug;
+
+ consumer_debug = MR_lookup_consumer_debug_num(consumer_index);
+ return MR_consumer_debug_name(consumer_debug);
+}
+
+void
+MR_enter_subgoal_debug(MR_Subgoal *subgoal)
+{
+ int i;
+
+ for (i = 0; i < MR_subgoal_debug_info_next; i++) {
+ if (MR_subgoal_debug_infos[i].MR_sgd_subgoal == subgoal) {
+ MR_subgoal_debug_infos[i].MR_sgd_version_num++;
+ MR_subgoal_debug_infos[i].MR_sgd_valid = MR_TRUE;
+ return;
+ }
+ }
+
+ MR_ensure_room_for_next(MR_subgoal_debug_info, MR_SubgoalDebug,
+ MR_SUBGOAL_DEBUG_INIT);
+ i = MR_subgoal_debug_info_next;
+ MR_subgoal_debug_infos[i].MR_sgd_subgoal = subgoal;
+ MR_subgoal_debug_infos[i].MR_sgd_sequence_num = i;
+ MR_subgoal_debug_infos[i].MR_sgd_version_num = 0;
+ MR_subgoal_debug_infos[i].MR_sgd_valid = MR_TRUE;
+ MR_subgoal_debug_info_next++;
+}
+
+MR_SubgoalDebug *
+MR_lookup_subgoal_debug_addr(MR_Subgoal *subgoal)
+{
+ int i;
+
+ for (i = 0; i < MR_subgoal_debug_info_next; i++) {
+ if (MR_subgoal_debug_infos[i].MR_sgd_subgoal == subgoal) {
+ return &MR_subgoal_debug_infos[i];
+ }
+ }
+
+ return NULL;
+}
+
+MR_SubgoalDebug *
+MR_lookup_subgoal_debug_num(int subgoal_index)
+{
+ int i;
+
+ for (i = 0; i < MR_subgoal_debug_info_next; i++) {
+ if (MR_subgoal_debug_infos[i].MR_sgd_sequence_num == subgoal_index) {
+ return &MR_subgoal_debug_infos[i];
+ }
+ }
+
+ return NULL;
+}
+
+const char *
+MR_subgoal_debug_name(MR_SubgoalDebug *subgoal_debug)
+{
+ const char *warning;
+ char buf[MR_NAME_BUF];
+
+ if (subgoal_debug == NULL) {
+ return "unknown";
+ }
+
+ if (subgoal_debug->MR_sgd_valid) {
+ warning = "";
+ } else {
+ warning = " INVALID";
+ }
+
+ if (subgoal_debug->MR_sgd_version_num > 0) {
+ sprintf(buf, "sub %d/%d (%p)%s", subgoal_debug->MR_sgd_sequence_num,
+ subgoal_debug->MR_sgd_version_num,
+ subgoal_debug->MR_sgd_subgoal, warning);
+ } else {
+ sprintf(buf, "sub %d (%p)%s", subgoal_debug->MR_sgd_sequence_num,
+ subgoal_debug->MR_sgd_subgoal, warning);
+ }
+
+ return strdup(buf);
+}
+
+const char *
+MR_subgoal_addr_name(MR_Subgoal *subgoal)
+{
+ MR_SubgoalDebug *subgoal_debug;
+
+ if (subgoal == NULL) {
+ return "NULL";
+ }
+
+ subgoal_debug = MR_lookup_subgoal_debug_addr(subgoal);
+ return MR_subgoal_debug_name(subgoal_debug);
+}
+
+const char *
+MR_subgoal_num_name(int subgoal_index)
+{
+ MR_SubgoalDebug *subgoal_debug;
+
+ subgoal_debug = MR_lookup_subgoal_debug_num(subgoal_index);
+ return MR_subgoal_debug_name(subgoal_debug);
+}
+
+const char *
+MR_subgoal_status(MR_SubgoalStatus status)
+{
+ switch (status) {
+ case MR_SUBGOAL_INACTIVE:
+ return "INACTIVE";
+
+ case MR_SUBGOAL_ACTIVE:
+ return "ACTIVE";
+
+ case MR_SUBGOAL_COMPLETE:
+ return "COMPLETE";
+ }
+
+ return "INVALID";
+}
+
+void
+MR_print_subgoal_debug(FILE *fp, const MR_Proc_Layout *proc,
+ MR_SubgoalDebug *subgoal_debug)
+{
+ if (subgoal_debug == NULL) {
+ fprintf(fp, "NULL subgoal_debug\n");
+ } else {
+ MR_print_subgoal(fp, proc, subgoal_debug->MR_sgd_subgoal);
+ }
+}
+
+void
+MR_print_subgoal(FILE *fp, const MR_Proc_Layout *proc, MR_Subgoal *subgoal)
+{
+ MR_SubgoalList follower;
+ MR_ConsumerList consumer;
+ MR_AnswerList answer_list;
+ MR_Word *answer;
+
+ if (subgoal == NULL) {
+ fprintf(fp, "NULL subgoal\n");
+ return;
+ }
+
+#ifdef MR_TABLE_DEBUG
+ if (proc == NULL && subgoal->MR_sg_proc_layout != NULL) {
+ proc = subgoal->MR_sg_proc_layout;
+ }
+#endif
+
+ fprintf(fp, "subgoal %s: status %s, generator frame ",
+ MR_subgoal_addr_name(subgoal),
+ MR_subgoal_status(subgoal->MR_sg_status));
+ MR_print_nondstackptr(fp, subgoal->MR_sg_generator_fr);
+ fprintf(fp, "\n");
+
+ if (proc != NULL) {
+ fprintf(fp, "proc: ");
+ MR_print_proc_id(fp, proc);
+ fprintf(fp, "\n");
+ }
+
+ fprintf(fp, "leader: %s, ",
+ MR_subgoal_addr_name(subgoal->MR_sg_leader));
+ fprintf(fp, "followers:");
+ for (follower = subgoal->MR_sg_followers;
+ follower != NULL; follower = follower->MR_sl_next)
+ {
+ fprintf(fp, " %s", MR_subgoal_addr_name(follower->MR_sl_item));
+ }
+
+ fprintf(fp, "\nconsumers:");
+ for (consumer = subgoal->MR_sg_consumer_list;
+ consumer != NULL; consumer = consumer->MR_cl_next)
+ {
+ fprintf(fp, " %s", MR_consumer_addr_name(consumer->MR_cl_item));
+ }
+
+ fprintf(fp, "\n");
+ fprintf(fp, "answers: %d, committed: %d\n",
+ subgoal->MR_sg_num_ans,
+ subgoal->MR_sg_num_committed_ans);
+
+ if (proc != NULL) {
+ answer_list = subgoal->MR_sg_answer_list;
+ while (answer_list != NULL) {
+ fprintf(fp, "answer #%d: <", answer_list->MR_aln_answer_num);
+ MR_print_answerblock(fp, proc,
+ answer_list->MR_aln_answer_data.MR_answerblock);
+ fprintf(fp, ">\n");
+ answer_list = answer_list->MR_aln_next_answer;
+ }
+ }
+}
+
+void
+MR_print_consumer_debug(FILE *fp, const MR_Proc_Layout *proc,
+ MR_ConsumerDebug *consumer_debug)
+{
+ if (consumer_debug == NULL) {
+ fprintf(fp, "NULL consumer_debug\n");
+ } else {
+ MR_print_consumer(fp, proc, consumer_debug->MR_cod_consumer);
+ }
+}
+
+void
+MR_print_consumer(FILE *fp, const MR_Proc_Layout *proc, MR_Consumer *consumer)
+{
+ if (consumer == NULL) {
+ fprintf(fp, "NULL consumer\n");
+ return;
+ }
+
+ fprintf(fp, "consumer %s", MR_consumer_addr_name(consumer));
+
+#ifdef MR_TABLE_DEBUG
+ fprintf(fp, ", of subgoal %s",
+ MR_subgoal_addr_name(consumer->MR_cns_subgoal));
+#endif
+
+ fprintf(fp, ", remaining answers %p\n",
+ consumer->MR_cns_remaining_answer_list_ptr);
+ print_saved_state(fp, &consumer->MR_cns_saved_state);
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+** This part of the file provides the utility functions needed for
+** suspensions and resumptions of derivations.
+*/
+
+#define RESUME_LABEL(name) MR_PASTE3(MR_RESUME_ENTRY, _, name)
+
+/*
+** Given pointers to two ordinary frames on the nondet stack, return the
+** address of the stack frame of their nearest common ancestor on that stack.
+*/
+
+static MR_Word *
+nearest_common_ancestor(MR_Word *fr1, MR_Word *fr2)
+{
+ while (fr1 != fr2) {
+ #ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("common ancestor search: ");
+ MR_printnondstackptr(fr1);
+ printf(" vs ");
+ MR_printnondstackptr(fr2);
+ printf("\n");
+ }
+ #endif
+
+ if (fr1 > fr2) {
+ fr1 = MR_succfr_slot(fr1);
+ } else {
+ fr2 = MR_succfr_slot(fr2);
+ }
+ }
+
+ #ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("the common ancestor is ");
+ MR_printnondstackptr(fr1);
+ printf("\n");
+ }
+ #endif
+
+ return fr1;
+}
+
+/*
+** Save the current state of the Mercury abstract machine, so that the
+** current computation may be suspended for a while, and restored later.
+** The generator_fr argument gives the point from which we need to copy the
+** nondet and (indirectly) the det stacks. The parts of those stacks below
+** the given points will not change between the suspension and the resumption
+** of this state, or if they do, the stack segments in the saved state
+** will be extended (via extend_consumer_stacks).
+*/
+
+static void
+save_state(MR_SavedState *saved_state, MR_Word *generator_fr,
+ const char *who, const char *what)
+{
+ MR_Word *common_ancestor_fr;
+ MR_Word *start_non;
+ MR_Word *start_det;
+
+ MR_restore_transient_registers();
+
+ common_ancestor_fr = nearest_common_ancestor(MR_curfr, generator_fr);
+ start_non = MR_prevfr_slot(common_ancestor_fr) + 1;
+ start_det = MR_table_detfr_slot(common_ancestor_fr) + 1;
+
+ saved_state->MR_ss_succ_ip = MR_succip;
+ saved_state->MR_ss_s_p = MR_sp;
+ saved_state->MR_ss_cur_fr = MR_curfr;
+ saved_state->MR_ss_max_fr = MR_maxfr;
+ saved_state->MR_ss_common_ancestor_fr = common_ancestor_fr;
+
+ /* we copy from start_non to MR_maxfr, both inclusive */
+ saved_state->MR_ss_non_stack_real_start = start_non;
+ if (MR_maxfr >= start_non) {
+ saved_state->MR_ss_non_stack_block_size = MR_maxfr + 1 - start_non;
+ saved_state->MR_ss_non_stack_saved_block = MR_table_allocate_words(
+ saved_state->MR_ss_non_stack_block_size);
+ MR_table_copy_words(saved_state->MR_ss_non_stack_saved_block,
+ saved_state->MR_ss_non_stack_real_start,
+ saved_state->MR_ss_non_stack_block_size);
+ } else {
+ saved_state->MR_ss_non_stack_block_size = 0;
+ saved_state->MR_ss_non_stack_saved_block = NULL;
+ }
+
+ /* we copy from start_det to MR_sp, both inclusive */
+ saved_state->MR_ss_det_stack_real_start = start_det;
+ if (MR_sp >= start_det) {
+ saved_state->MR_ss_det_stack_block_size = MR_sp + 1 - start_det;
+ saved_state->MR_ss_det_stack_saved_block = MR_table_allocate_words(
+ saved_state->MR_ss_det_stack_block_size);
+ MR_table_copy_words(saved_state->MR_ss_det_stack_saved_block,
+ saved_state->MR_ss_det_stack_real_start,
+ saved_state->MR_ss_det_stack_block_size);
+ } else {
+ saved_state->MR_ss_det_stack_block_size = 0;
+ saved_state->MR_ss_det_stack_saved_block = NULL;
+ }
+
+ saved_state->MR_ss_gen_next = MR_gen_next;
+ saved_state->MR_ss_gen_stack_saved_block = MR_table_allocate_structs(
+ saved_state->MR_ss_gen_next, MR_GenStackFrame);
+ MR_table_copy_structs(saved_state->MR_ss_gen_stack_saved_block,
+ MR_gen_stack, saved_state->MR_ss_gen_next, MR_GenStackFrame);
+
+ saved_state->MR_ss_cut_next = MR_cut_next;
+ saved_state->MR_ss_cut_stack_saved_block = MR_table_allocate_structs(
+ MR_cut_next, MR_CutStackFrame);
+ MR_table_copy_structs(saved_state->MR_ss_cut_stack_saved_block,
+ MR_cut_stack, saved_state->MR_ss_cut_next, MR_CutStackFrame);
+
+ saved_state->MR_ss_pneg_next = MR_pneg_next;
+ saved_state->MR_ss_pneg_stack_saved_block = MR_table_allocate_structs(
+ MR_pneg_next, MR_PNegStackFrame);
+ MR_table_copy_structs(saved_state->MR_ss_pneg_stack_saved_block,
+ MR_pneg_stack, saved_state->MR_ss_pneg_next, MR_PNegStackFrame);
+
+ #ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("\n%s saves %s stacks\n", who, what);
+ print_saved_state(stdout, saved_state);
+ }
+
+ if (MR_tablestackdebug) {
+ MR_dump_nondet_stack(stdout, MR_maxfr);
+ }
+ #endif /* MR_TABLE_DEBUG */
+
+ MR_save_transient_registers();
+}
+
+/*
+** Restore the state of the Mercury abstract machine from saved_state.
+*/
+
+static void
+restore_state(MR_SavedState *saved_state, const char *who, const char *what)
+{
+ MR_restore_transient_registers();
+
+ MR_succip = saved_state->MR_ss_succ_ip;
+ MR_sp = saved_state->MR_ss_s_p;
+ MR_curfr = saved_state->MR_ss_cur_fr;
+ MR_maxfr = saved_state->MR_ss_max_fr;
+
+ MR_table_copy_words(saved_state->MR_ss_non_stack_real_start,
+ saved_state->MR_ss_non_stack_saved_block,
+ saved_state->MR_ss_non_stack_block_size);
+
+ MR_table_copy_words(saved_state->MR_ss_det_stack_real_start,
+ saved_state->MR_ss_det_stack_saved_block,
+ saved_state->MR_ss_det_stack_block_size);
+
+ MR_gen_next = saved_state->MR_ss_gen_next;
+ MR_table_copy_structs(MR_gen_stack,
+ saved_state->MR_ss_gen_stack_saved_block,
+ saved_state->MR_ss_gen_next, MR_GenStackFrame);
+
+ MR_cut_next = saved_state->MR_ss_cut_next;
+ MR_table_copy_structs(MR_cut_stack,
+ saved_state->MR_ss_cut_stack_saved_block,
+ saved_state->MR_ss_cut_next, MR_CutStackFrame);
+
+ MR_pneg_next = saved_state->MR_ss_pneg_next;
+ MR_table_copy_structs(MR_pneg_stack,
+ saved_state->MR_ss_pneg_stack_saved_block,
+ saved_state->MR_ss_pneg_next, MR_PNegStackFrame);
+
+ #ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("\n%s restores %s stacks\n", who, what);
+ print_saved_state(stdout, saved_state);
+ }
+
+ if (MR_tablestackdebug) {
+ MR_dump_nondet_stack_from_layout(stdout, MR_maxfr, NULL,
+ MR_sp, MR_curfr);
+ }
+ #endif /* MR_TABLE_DEBUG */
+
+ MR_save_transient_registers();
+}
+
+/*
+** The saved state of a consumer for a subgoal (say subgoal A) includes
+** the stack segments between the tops of the stack at the time that
+** A's generator was entered and the time that A's consumer was entered.
+** When A becomes a follower of another subgoal B, the responsibility for
+** scheduling A's consumers passes to B's generator. Since by definition
+** B's nondet stack frame is lower in the stack than A's generator's,
+** we need to extend the stack segments of A's consumers to also include
+** the parts of the stacks between the generator of B and the generator of A.
+*/
+
+static void
+extend_consumer_stacks(MR_Subgoal *leader, MR_Consumer *consumer)
+{
+ MR_Word *arena_block;
+ MR_Word *arena_start;
+ MR_Word arena_size;
+ MR_Word extension_size;
+ MR_Word *new_common_ancestor_fr;
+ MR_Word *saved_fr;
+ MR_Word *real_fr;
+ MR_Word frame_size;
+ MR_Word offset;
+ MR_SavedState *cons_saved_state;
+
+ cons_saved_state = &consumer->MR_cns_saved_state;
+
+#ifdef MR_TABLE_DEBUG
+ if (MR_tablestackdebug) {
+ printf("\nextending saved consumer stacks\n");
+ print_saved_state(stdout, cons_saved_state);
+ }
+#endif /* MR_TABLE_DEBUG */
+
+ new_common_ancestor_fr = nearest_common_ancestor(
+ cons_saved_state->MR_ss_common_ancestor_fr,
+ leader->MR_sg_generator_fr);
+ cons_saved_state->MR_ss_common_ancestor_fr = new_common_ancestor_fr;
+
+ arena_start = MR_table_detfr_slot(leader->MR_sg_generator_fr) + 1;
+ extension_size = cons_saved_state->MR_ss_det_stack_real_start
+ - arena_start;
+ arena_size = extension_size
+ + cons_saved_state->MR_ss_det_stack_block_size;
+
+#if 0
+ if (arena_size != 0) {
+ assert(arena_start + arena_size == cons_saved_state->MR_ss_s_p - 1);
+ }
+#endif
+
+ arena_block = MR_table_allocate_words(arena_size);
+
+ MR_table_copy_words(arena_block, arena_start, extension_size);
+ MR_table_copy_words(arena_block + extension_size,
+ cons_saved_state->MR_ss_det_stack_saved_block,
+ cons_saved_state->MR_ss_det_stack_block_size);
+
+#ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("extending det stack of consumer %s for %s\n",
+ MR_consumer_addr_name(consumer), MR_subgoal_addr_name(leader));
+ printf("start: old %p, new %p\n",
+ cons_saved_state->MR_ss_det_stack_real_start, arena_start);
+ printf("size: old %d, new %d\n",
+ cons_saved_state->MR_ss_det_stack_block_size, arena_size);
+ printf("block: old %p, new %p\n",
+ cons_saved_state->MR_ss_det_stack_saved_block, arena_block);
+ }
+#endif /* MR_TABLE_DEBUG */
+
+ cons_saved_state->MR_ss_det_stack_saved_block = arena_block;
+ cons_saved_state->MR_ss_det_stack_block_size = arena_size;
+ cons_saved_state->MR_ss_det_stack_real_start = arena_start;
+
+ arena_start = leader->MR_sg_generator_fr + 1;
+ extension_size = cons_saved_state->MR_ss_non_stack_real_start
+ - arena_start;
+ arena_size = extension_size
+ + cons_saved_state->MR_ss_non_stack_block_size;
+
+#if 0
+ assert(arena_start + arena_size == cons_saved_state->MR_max_fr);
+#endif
+
+ arena_block = MR_table_allocate_words(arena_size);
+
+ MR_table_copy_words(arena_block, arena_start, extension_size);
+ MR_table_copy_words(arena_block + extension_size,
+ cons_saved_state->MR_ss_non_stack_saved_block,
+ cons_saved_state->MR_ss_non_stack_block_size);
+
+#ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("extending non stack of suspension %s for %s\n",
+ MR_consumer_addr_name(consumer), MR_subgoal_addr_name(leader));
+ printf("start: old %p, new %p\n",
+ cons_saved_state->MR_ss_non_stack_real_start, arena_start);
+ printf("size: old %d, new %d\n",
+ cons_saved_state->MR_ss_non_stack_block_size, arena_size);
+ printf("block: old %p, new %p\n",
+ cons_saved_state->MR_ss_non_stack_saved_block, arena_block);
+ }
+#endif /* MR_TABLE_DEBUG */
+
+ cons_saved_state->MR_ss_non_stack_saved_block = arena_block;
+ cons_saved_state->MR_ss_non_stack_block_size = arena_size;
+ cons_saved_state->MR_ss_non_stack_real_start = arena_start;
+
+#ifdef MR_TABLE_DEBUG
+ if (MR_tablestackdebug) {
+ printf("\nbefore pickling nondet stack\n");
+ print_saved_state(stdout, cons_saved_state);
+ }
+#endif /* MR_TABLE_DEBUG */
+
+ saved_fr = cons_saved_state->MR_ss_non_stack_saved_block +
+ cons_saved_state->MR_ss_non_stack_block_size - 1;
+ real_fr = cons_saved_state->MR_ss_non_stack_real_start +
+ cons_saved_state->MR_ss_non_stack_block_size - 1;
+ while (saved_fr > cons_saved_state->MR_ss_non_stack_saved_block) {
+ frame_size = real_fr - MR_prevfr_slot(saved_fr);
+
+ if (saved_fr - frame_size >
+ cons_saved_state->MR_ss_non_stack_saved_block)
+ {
+ *MR_redoip_addr(saved_fr) = (MR_Word) MR_ENTRY(MR_do_fail);
+
+#ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("do_fail to redoip at %p (%d)\n",
+ MR_redoip_addr(saved_fr),
+ MR_redoip_addr(saved_fr) -
+ cons_saved_state->MR_ss_non_stack_saved_block);
+ }
+#endif /* MR_TABLE_DEBUG */
+ } else {
+ *MR_redoip_addr(saved_fr) = (MR_Word) MR_ENTRY(MR_RESUME_ENTRY);
+#ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("resume to redoip at %p (%d)\n",
+ MR_redoip_addr(saved_fr),
+ MR_redoip_addr(saved_fr) -
+ cons_saved_state->MR_ss_non_stack_saved_block);
+ }
+#endif /* MR_TABLE_DEBUG */
+ } /*** else cut_stack XXX */
+
+ saved_fr -= frame_size;
+ real_fr -= frame_size;
+ }
+
+#ifdef MR_TABLE_DEBUG
+ if (MR_tablestackdebug) {
+ printf("\nfinished extending saved consumer stacks\n");
+ print_saved_state(stdout, cons_saved_state);
+ }
+#endif /* MR_TABLE_DEBUG */
+}
+
+/*
+** When we discover that two subgoals depend on each other, neither can be
+** completed alone. We therefore pass responsibility for completing all
+** the subgoals in an SCC to the subgoal whose nondet stack frame is
+** lowest in the nondet stack.
+*/
+
+static void
+make_subgoal_follow_leader(MR_Subgoal *this_follower, MR_Subgoal *leader)
+{
+ MR_Consumer *suspension;
+ MR_SubgoalList sub_follower;
+ MR_ConsumerList suspend_list;
+
+ MR_restore_transient_registers();
+
+#ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("making %s follow %s\n",
+ MR_subgoal_addr_name(this_follower),
+ MR_subgoal_addr_name(leader));
+ }
+#endif /* MR_TABLE_DEBUG */
+
+ for (sub_follower = this_follower->MR_sg_followers;
+ sub_follower != NULL; sub_follower = sub_follower->MR_sl_next)
+ {
+ for (suspend_list = sub_follower->MR_sl_item->MR_sg_consumer_list;
+ suspend_list != NULL;
+ suspend_list = suspend_list->MR_cl_next)
+ {
+ MR_save_transient_registers();
+ extend_consumer_stacks(leader, suspend_list->MR_cl_item);
+ MR_restore_transient_registers();
+ /* suspend_list->item->leader = leader; XXX */
+ }
+ }
+
+ /* XXX extend saved state of this_follower */
+
+ this_follower->MR_sg_leader = leader;
+ *(leader->MR_sg_followers_tail) = this_follower->MR_sg_followers;
+ this_follower->MR_sg_followers = NULL;
+
+ MR_save_transient_registers();
+}
+
+static void
+print_saved_state(FILE *fp, MR_SavedState *saved_state)
+{
+ fprintf(fp, "saved state parameters:\n");
+ fprintf(fp, "succip:\t");
+ MR_printlabel(fp, saved_state->MR_ss_succ_ip);
+ fprintf(fp, "sp:\t");
+ MR_print_detstackptr(fp, saved_state->MR_ss_s_p);
+ fprintf(fp, "\ncurfr:\t");
+ MR_print_nondstackptr(fp, saved_state->MR_ss_cur_fr);
+ fprintf(fp, "\nmaxfr:\t");
+ MR_print_nondstackptr(fp, saved_state->MR_ss_max_fr);
+ fprintf(fp, "\n");
+
+ fprintf(fp,
+ "slots saved: %d non, %d det, %d generator, %d cut, %d pneg\n",
+ saved_state->MR_ss_non_stack_block_size,
+ saved_state->MR_ss_det_stack_block_size,
+ saved_state->MR_ss_gen_next,
+ saved_state->MR_ss_cut_next,
+ saved_state->MR_ss_pneg_next);
+
+ if (saved_state->MR_ss_non_stack_block_size > 0) {
+ fprintf(fp, "non region from ");
+ MR_print_nondstackptr(fp, saved_state->MR_ss_non_stack_real_start);
+ fprintf(fp, " to ");
+ MR_print_nondstackptr(fp, saved_state->MR_ss_non_stack_real_start +
+ saved_state->MR_ss_non_stack_block_size - 1);
+ fprintf(fp, " (both inclusive)\n");
+ }
+
+ #ifdef MR_TABLE_SEGMENT_DEBUG
+ if (saved_state->MR_ss_non_stack_block_size > 0) {
+ fprintf(fp, "stored at %p to %p (both inclusive)\n",
+ saved_state->MR_ss_non_stack_saved_block,
+ saved_state->MR_ss_non_stack_saved_block +
+ saved_state->MR_ss_non_stack_block_size - 1);
+
+ fprint_stack_segment(fp, saved_state->MR_ss_non_stack_saved_block,
+ saved_state->MR_ss_non_stack_block_size);
+ }
+ #endif /* MR_TABLE_SEGMENT_DEBUG */
+
+ if (saved_state->MR_ss_det_stack_block_size > 0) {
+ fprintf(fp, "det region from ");
+ MR_print_detstackptr(fp, saved_state->MR_ss_det_stack_real_start);
+ fprintf(fp, " to ");
+ MR_print_detstackptr(fp, saved_state->MR_ss_det_stack_real_start +
+ saved_state->MR_ss_det_stack_block_size - 1);
+ fprintf(fp, " (both inclusive)\n");
+ }
+
+ #ifdef MR_TABLE_SEGMENT_DEBUG
+ if (saved_state->MR_ss_det_stack_block_size > 0) {
+ fprintf(fp, "stored at %p to %p (both inclusive)\n",
+ saved_state->MR_ss_det_stack_saved_block,
+ saved_state->MR_ss_det_stack_saved_block +
+ saved_state->MR_ss_det_stack_block_size - 1);
+
+ print_stack_segment(fp, saved_state->MR_ss_det_stack_saved_block,
+ saved_state->MR_ss_det_stack_block_size);
+ }
+ #endif /* MR_TABLE_SEGMENT_DEBUG */
+
+ MR_print_any_gen_stack(fp, saved_state->MR_ss_gen_next,
+ saved_state->MR_ss_gen_stack_saved_block);
+ MR_print_any_cut_stack(fp, saved_state->MR_ss_cut_next,
+ saved_state->MR_ss_cut_stack_saved_block);
+ MR_print_any_pneg_stack(fp, saved_state->MR_ss_pneg_next,
+ saved_state->MR_ss_pneg_stack_saved_block);
+
+ fprintf(fp, "\n");
+}
+
+static void
+print_stack_segment(FILE *fp, MR_Word *segment, MR_Integer size)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ fprintf(fp, "%2d %p: %ld (%lx)\n", i, &segment[i],
+ (long) segment[i], (long) segment[i]);
+ }
+}
+
+#endif /* MR_USE_MINIMAL_MODEL */
+
+/*---------------------------------------------------------------------------*/
+
+/*
+** This part of the file implements the suspension and and resumption
+** of derivations.
+**
+** We need to define stubs for table_nondet_suspend and table_nondet_resume,
+** even if MR_USE_MINIMAL_MODEL is not enabled, since they are declared as
+** `:- external', and hence for profiling grades the generated code will take
+** their address to store in the label table.
+**
+** We provide three definitions for those two procedures: one for high level
+** code (which is incompatible with minimal model tabling), and two for low
+** level code. The first of the latter two is for grades without minimal model
+** tabling, the second is for grades with minimal model tabling.
+*/
+
+#ifdef MR_HIGHLEVEL_CODE
+
+/* Declare them first, to avoid warnings from gcc -Wmissing-decls */
+void MR_CALL mercury__table_builtin__table_nondet_resume_1_p_0(
+ MR_C_Pointer subgoal_table_node, MR_C_Pointer *answer_block,
+ MR_Cont cont, void *cont_env_ptr);
+void MR_CALL mercury__table_builtin__table_nondet_suspend_2_p_0(
+ MR_C_Pointer subgoal_table_node);
+
+void MR_CALL
+mercury__table_builtin__table_nondet_resume_1_p_0(
+ MR_C_Pointer subgoal_table_node, MR_C_Pointer *answer_block,
+ MR_Cont cont, void *cont_env_ptr)
+{
+ MR_fatal_error("sorry, not implemented: "
+ "minimal model tabling with --high-level-code");
+}
+
+void MR_CALL
+mercury__table_builtin__table_nondet_suspend_2_p_0(
+ MR_C_Pointer subgoal_table_node)
+{
+ MR_fatal_error("sorry, not implemented: "
+ "minimal model tabling with --high-level-code");
+}
+
+#else /* ! MR_HIGHLEVEL_CODE */
+
+#ifndef MR_USE_MINIMAL_MODEL
+
+MR_define_extern_entry(MR_SUSPEND_ENTRY);
+MR_define_extern_entry(MR_RESUME_ENTRY);
+MR_MAKE_PROC_LAYOUT(MR_SUSPEND_ENTRY,
+ MR_DETISM_NON, 0, MR_LONG_LVAL_TYPE_UNKNOWN,
+ MR_PREDICATE, "table_builtin", "table_nondet_suspend", 2, 0);
+MR_MAKE_PROC_LAYOUT(MR_RESUME_ENTRY,
+ MR_DETISM_NON, 0, MR_LONG_LVAL_TYPE_UNKNOWN,
+ MR_PREDICATE, "table_builtin", "table_nondet_resume", 1, 0);
+
+MR_BEGIN_MODULE(table_nondet_suspend_resume_module)
+ MR_init_entry_sl(MR_SUSPEND_ENTRY);
+ MR_init_entry_sl(MR_RESUME_ENTRY);
+ MR_INIT_PROC_LAYOUT_ADDR(MR_SUSPEND_ENTRY);
+ MR_INIT_PROC_LAYOUT_ADDR(MR_RESUME_ENTRY);
+MR_BEGIN_CODE
+
+MR_define_entry(MR_SUSPEND_ENTRY);
+ MR_fatal_error("call to table_nondet_suspend/2 in a grade "
+ "without minimal model tabling");
+
+MR_define_entry(MR_RESUME_ENTRY);
+ MR_fatal_error("call to table_nondet_resume/1 in a grade "
+ "without minimal model tabling");
+MR_END_MODULE
+
+#else /* MR_USE_MINIMAL_MODEL */
+
+MR_Subgoal *MR_cur_leader;
+
+MR_declare_entry(MR_do_trace_redo_fail);
+MR_declare_entry(MR_table_nondet_commit);
+
+MR_define_extern_entry(MR_SUSPEND_ENTRY);
+
+MR_define_extern_entry(MR_RESUME_ENTRY);
+MR_declare_label(RESUME_LABEL(ChangeLoop));
+MR_declare_label(RESUME_LABEL(ReachedFixpoint));
+MR_declare_label(RESUME_LABEL(LoopOverSubgoals));
+MR_declare_label(RESUME_LABEL(LoopOverSuspensions));
+MR_declare_label(RESUME_LABEL(ReturnAnswer));
+MR_declare_label(RESUME_LABEL(RedoPoint));
+MR_declare_label(RESUME_LABEL(RestartPoint));
+
+MR_define_extern_entry(MR_table_nondet_commit);
+
+MR_MAKE_PROC_LAYOUT(MR_SUSPEND_ENTRY,
+ MR_DETISM_NON, 0, MR_LONG_LVAL_TYPE_UNKNOWN,
+ MR_PREDICATE, "table_builtin", "table_nondet_suspend", 2, 0);
+
+MR_MAKE_PROC_LAYOUT(MR_RESUME_ENTRY,
+ MR_DETISM_NON, 0, MR_LONG_LVAL_TYPE_UNKNOWN,
+ MR_PREDICATE, "table_builtin", "table_nondet_resume", 1, 0);
+MR_MAKE_INTERNAL_LAYOUT_WITH_ENTRY(
+ RESUME_LABEL(ChangeLoop), MR_RESUME_ENTRY);
+MR_MAKE_INTERNAL_LAYOUT_WITH_ENTRY(
+ RESUME_LABEL(ReachedFixpoint), MR_RESUME_ENTRY);
+MR_MAKE_INTERNAL_LAYOUT_WITH_ENTRY(
+ RESUME_LABEL(LoopOverSubgoals), MR_RESUME_ENTRY);
+MR_MAKE_INTERNAL_LAYOUT_WITH_ENTRY(
+ RESUME_LABEL(LoopOverSuspensions), MR_RESUME_ENTRY);
+MR_MAKE_INTERNAL_LAYOUT_WITH_ENTRY(
+ RESUME_LABEL(ReturnAnswer), MR_RESUME_ENTRY);
+MR_MAKE_INTERNAL_LAYOUT_WITH_ENTRY(
+ RESUME_LABEL(RedoPoint), MR_RESUME_ENTRY);
+MR_MAKE_INTERNAL_LAYOUT_WITH_ENTRY(
+ RESUME_LABEL(RestartPoint), MR_RESUME_ENTRY);
+
+MR_BEGIN_MODULE(table_nondet_suspend_resume_module)
+ MR_init_entry_sl(MR_SUSPEND_ENTRY);
+ MR_INIT_PROC_LAYOUT_ADDR(MR_SUSPEND_ENTRY);
+
+ MR_init_entry_sl(MR_RESUME_ENTRY);
+ MR_INIT_PROC_LAYOUT_ADDR(MR_RESUME_ENTRY);
+ MR_init_label_sl(RESUME_LABEL(ChangeLoop));
+ MR_init_label_sl(RESUME_LABEL(ReachedFixpoint));
+ MR_init_label_sl(RESUME_LABEL(LoopOverSubgoals));
+ MR_init_label_sl(RESUME_LABEL(LoopOverSuspensions));
+ MR_init_label_sl(RESUME_LABEL(ReturnAnswer));
+ MR_init_label_sl(RESUME_LABEL(RedoPoint));
+ MR_init_label_sl(RESUME_LABEL(RestartPoint));
+
+ MR_init_entry_an(MR_table_nondet_commit);
+MR_BEGIN_CODE
+
+MR_define_entry(MR_SUSPEND_ENTRY);
+ /*
+ ** The suspend procedure saves the state of the Mercury runtime so that
+ ** it may be used in the table_nondet_resume procedure below to return
+ ** answers through this saved state. The procedure table_nondet_suspend is
+ ** declared as nondet but the code below is obviously of detism failure;
+ ** the reason for this is quite simple. Normally when a nondet proc is
+ ** called it will first return all of its answers and then fail. In the
+ ** case of calls to this procedure this is reversed: first the call will
+ ** fail then later on, when the answers are found, answers will be
+ ** returned. It is also important to note that the answers are returned
+ ** not from the procedure that was originally called (table_nondet_suspend)
+ ** but from the procedure table_nondet_resume. So essentially what is
+ ** below is the code to do the initial fail; the code to return the
+ ** answers is in table_nondet_resume.
+ */
+
+{
+ MR_TrieNode table;
+ MR_Subgoal *subgoal;
+ MR_Consumer *consumer;
+ MR_ConsumerList listnode;
+ MR_Integer cur_gen;
+ MR_Integer cur_cut;
+ MR_Integer cur_pneg;
+ MR_Word *fr;
+ MR_Word *prev_fr;
+ MR_Word *stop_addr;
+ MR_Word offset;
+ MR_Word *clobber_addr;
+
+ /*
+ ** This frame is not used in table_nondet_suspend, but it is copied
+ ** to the suspend list as part of the saved nondet stack fragment,
+ ** and it *will* be used when table_nondet_resume copies back the
+ ** nondet stack fragment. The framevar slot is for use by
+ ** table_nondet_resume.
+ */
+ MR_mkframe(MR_STRINGIFY(MR_SUSPEND_ENTRY), 1, MR_ENTRY(MR_do_fail));
+
+ table = (MR_TrieNode) MR_r1;
+ subgoal = table->MR_subgoal;
+ MR_register_suspension(subgoal);
+ consumer = MR_table_allocate_struct(MR_Consumer);
+ consumer->MR_cns_remaining_answer_list_ptr = &subgoal->MR_sg_answer_list;
+
+#ifdef MR_TABLE_DEBUG
+ consumer->MR_cns_subgoal = subgoal;
+ MR_enter_consumer_debug(consumer);
+
+ if (MR_tabledebug) {
+ printf("setting up consumer %s\n", MR_consumer_addr_name(consumer));
+ }
+#endif
+
+ MR_save_transient_registers();
+ save_state(&(consumer->MR_cns_saved_state), subgoal->MR_sg_generator_fr,
+ "suspension", "consumer");
+ MR_restore_transient_registers();
+
+ cur_gen = MR_gen_next - 1;
+ cur_cut = MR_cut_next - 1;
+ cur_pneg = MR_pneg_next - 1;
+ stop_addr = consumer->MR_cns_saved_state.MR_ss_non_stack_real_start;
+ for (fr = MR_maxfr; fr > stop_addr; fr = MR_prevfr_slot(fr)) {
+ offset = MR_redoip_addr(fr) -
+ consumer->MR_cns_saved_state.MR_ss_non_stack_real_start;
+ clobber_addr = consumer->MR_cns_saved_state.MR_ss_non_stack_saved_block
+ + offset;
+#if 0
+ if (MR_tablestackdebug) {
+ printf("redoip addr ");
+ MR_printnondstackptr(MR_redoip_addr(fr));
+ printf(", offset %d from start, ", offset);
+ printf("saved copy at %p\n", clobber_addr);
+ }
+#endif
+
+ if (fr == MR_gen_stack[cur_gen].MR_generator_frame) {
+ if (MR_gen_stack[cur_gen].MR_generator_table->MR_subgoal
+ == subgoal)
+ {
+ /*
+ ** This is the nondet stack frame of the
+ ** generator corresponding to this consumer.
+ */
+
+ *clobber_addr = (MR_Word) MR_ENTRY(MR_RESUME_ENTRY);
+ #ifdef MR_TABLE_DEBUG
+ if (MR_tablestackdebug) {
+ printf("completing redoip of frame at ");
+ MR_printnondstackptr(fr);
+ printf(" (in saved copy)\n");
+ }
+ #endif /* MR_TABLE_DEBUG */
+
+ consumer->MR_cns_saved_state.MR_ss_gen_next = cur_gen + 1;
+ #ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("saved gen_next set to %d\n", cur_gen + 1);
+ }
+ #endif /* MR_TABLE_DEBUG */
+ } else {
+ /*
+ ** This is the nondet stack frame of some other generator.
+ */
+
+ #if 0
+ assert(MR_prevfr_slot(fr) != (stop_addr - 1));
+ #endif
+
+ *clobber_addr = (MR_Word) MR_ENTRY(MR_do_fail);
+ #ifdef MR_TABLE_DEBUG
+ if (MR_tablestackdebug) {
+ printf("clobbering redoip of frame at ");
+ MR_printnondstackptr(fr);
+ printf(" (in saved copy)\n");
+ }
+ #endif /* MR_TABLE_DEBUG */
+
+ MR_save_transient_registers();
+ make_subgoal_follow_leader(MR_gen_stack[cur_gen].
+ MR_generator_table->MR_subgoal, subgoal);
+ MR_restore_transient_registers();
+ }
+
+ cur_gen--;
+ /* XXX can we be at a generator AND a cut? */
+ } else if (cur_cut > 0 && fr == MR_cut_stack[cur_cut].MR_cut_frame) {
+ *clobber_addr = (MR_Word) MR_ENTRY(MR_table_nondet_commit);
+ #ifdef MR_TABLE_DEBUG
+ if (MR_tablestackdebug) {
+ printf("committing redoip of frame at ");
+ MR_printnondstackptr(fr);
+ printf(" (in saved copy)\n");
+ }
+ #endif /* MR_TABLE_DEBUG */
+
+ cur_cut--;
+ } else {
+ *clobber_addr = (MR_Word) MR_ENTRY(MR_do_fail);
+ #ifdef MR_TABLE_DEBUG
+ if (MR_tablestackdebug) {
+ printf("clobbering redoip of frame at ");
+ MR_printnondstackptr(fr);
+ printf(" (in saved copy)\n");
+ }
+ #endif /* MR_TABLE_DEBUG */
+ }
+ }
+
+ #ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("adding suspension node %s to table %s",
+ MR_consumer_addr_name(consumer),
+ MR_subgoal_addr_name(subgoal));
+ printf("\n\tat slot %p\n", subgoal->MR_sg_consumer_list_tail);
+ }
+ #endif /* MR_TABLE_DEBUG */
+
+ assert(*(subgoal->MR_sg_consumer_list_tail) == NULL);
+ listnode = MR_table_allocate_struct(MR_ConsumerListNode);
+ *(subgoal->MR_sg_consumer_list_tail) = listnode;
+ subgoal->MR_sg_consumer_list_tail = &(listnode->MR_cl_next);
+ listnode->MR_cl_item = consumer;
+ listnode->MR_cl_next = NULL;
+}
+ MR_fail();
+
+MR_define_entry(MR_RESUME_ENTRY);
+
+ /*
+ ** The resume procedure restores answers to suspended consumers.
+ ** It works by restoring the consumer state saved by the consumer's call
+ ** to table_nondet_suspend. By restoring such states and then returning
+ ** answers, table_nondet_resume is essentially returning answers out of
+ ** the call to table_nondet_suspend, not out of the call to
+ ** table_nondet_resume.
+ **
+ ** The code is arranged as a three level iteration to a fixpoint. The
+ ** three levels are: iterating over all subgoals in a connected component,
+ ** iterating over all consumers of each of those subgoals, and iterating
+ ** over all the answers to be returned to each of those consumers.
+ ** Note that returning an answer could lead to further answers for
+ ** any of the subgoals in the connected component; it can even lead
+ ** to the expansion of the component (i.e. the addition of more subgoals
+ ** to it).
+ */
+
+ MR_cur_leader = MR_top_generator_table();
+
+ if (MR_cur_leader->MR_sg_leader != NULL) {
+ /*
+ ** The predicate that called table_nondet_resume is not the leader
+ ** of its component. We will leave all answers to be returned
+ ** by the leader.
+ */
+
+ #ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("non-leader table_nondet_resume fails\n");
+ }
+ #endif /* MR_TABLE_DEBUG */
+
+ (void) MR_pop_generator();
+ MR_redo();
+ }
+
+#ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("table_nondet_resume enter: current leader is %s\n",
+ MR_subgoal_addr_name(MR_cur_leader));
+ }
+#endif /* MR_TABLE_DEBUG */
+
+ if (MR_cur_leader->MR_sg_resume_info != NULL) {
+#ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("using existing resume info %p\n",
+ MR_cur_leader->MR_sg_resume_info);
+ }
+#endif /* MR_TABLE_DEBUG */
+ } else {
+ MR_cur_leader->MR_sg_resume_info = MR_TABLE_NEW(MR_ResumeInfo);
+ MR_cur_leader->MR_sg_resume_info->MR_ri_saved_succip = MR_succip;/*NEW*/
+
+#ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("resume info succip ");
+ MR_print_label(stdout, MR_succip);
+ }
+#endif /* MR_TABLE_DEBUG */
+
+ /*
+ ** we should compute, for all followers, the common ancestor
+ ** of the follower and this generator, and save to the deepest
+ ** common ancestor XXX
+ **
+ ** special case the situation where there are no answers
+ ** we have not yet returned to consumers
+ */
+
+ MR_save_transient_registers();
+ save_state(&(MR_cur_leader->MR_sg_resume_info->MR_ri_leader_state),
+ MR_cur_leader->MR_sg_generator_fr, "resumption", "generator");
+ MR_restore_transient_registers();
+
+#ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("creating new resume info %p\n",
+ MR_cur_leader->MR_sg_resume_info);
+ }
+#endif /* MR_TABLE_DEBUG */
+ }
+
+ /* XXX try doing the test at the bottom */
+ MR_cur_leader->MR_sg_resume_info->MR_ri_changed = MR_TRUE;
+
+MR_define_label(RESUME_LABEL(ChangeLoop));
+{
+ MR_ResumeInfo *resume_info;
+
+ resume_info = MR_cur_leader->MR_sg_resume_info;
+
+ if (resume_info->MR_ri_changed) {
+#ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("changed flag set\n");
+ }
+#endif /* MR_TABLE_DEBUG */
+ } else {
+ MR_SubgoalList table_list;
+
+ /* XXX make sure subgoal_list is initialized early */
+ for (table_list = resume_info->MR_ri_subgoal_list;
+ table_list != NULL;
+ table_list = table_list->MR_sl_next)
+ {
+ if (table_list->MR_sl_item->MR_sg_num_committed_ans
+ != table_list->MR_sl_item->MR_sg_num_ans)
+ {
+ resume_info->MR_ri_changed = MR_TRUE;
+#ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("table %s has new answers\n",
+ MR_subgoal_addr_name(table_list->MR_sl_item));
+ }
+#endif /* MR_TABLE_DEBUG */
+ }
+ }
+ }
+
+ if (! resume_info->MR_ri_changed) {
+#ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("no more changes\n");
+ }
+#endif /* MR_TABLE_DEBUG */
+
+ MR_GOTO_LABEL(RESUME_LABEL(ReachedFixpoint));
+ }
+
+ resume_info->MR_ri_subgoal_list = MR_cur_leader->MR_sg_followers;
+ if (resume_info->MR_ri_subgoal_list == NULL) {
+ resume_info->MR_ri_changed = MR_FALSE; /* XXX NEW */
+ }
+}
+
+ /* For each of the subgoals on our list of followers */
+MR_define_label(RESUME_LABEL(LoopOverSubgoals));
+{
+ MR_ResumeInfo *resume_info;
+
+ resume_info = MR_cur_leader->MR_sg_resume_info;
+
+ if (resume_info->MR_ri_subgoal_list == NULL) {
+#ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("no more subgoals in the followers list\n");
+ }
+#endif /* MR_TABLE_DEBUG */
+
+ MR_GOTO_LABEL(RESUME_LABEL(ChangeLoop));
+ }
+
+ resume_info->MR_ri_cur_subgoal =
+ resume_info->MR_ri_subgoal_list->MR_sl_item;
+ resume_info->MR_ri_subgoal_list =
+ resume_info->MR_ri_subgoal_list->MR_sl_next;
+
+ resume_info->MR_ri_consumer_list =
+ resume_info->MR_ri_cur_subgoal->MR_sg_consumer_list;
+
+ resume_info->MR_ri_changed = MR_FALSE;
+ resume_info->MR_ri_cur_subgoal->MR_sg_num_committed_ans =
+ resume_info->MR_ri_cur_subgoal->MR_sg_num_ans;
+}
+
+ /* For each of the suspended nodes for cur_subgoal */
+MR_define_label(RESUME_LABEL(LoopOverSuspensions));
+{
+ MR_ResumeInfo *resume_info;
+
+ resume_info = MR_cur_leader->MR_sg_resume_info;
+
+ if (resume_info->MR_ri_consumer_list == NULL) {
+#ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("no more suspensions for current subgoal\n");
+ }
+#endif /* MR_TABLE_DEBUG */
+ MR_GOTO_LABEL(RESUME_LABEL(LoopOverSubgoals));
+ }
+
+ resume_info->MR_ri_cur_consumer =
+ resume_info->MR_ri_consumer_list->MR_cl_item;
+ resume_info->MR_ri_consumer_list =
+ resume_info->MR_ri_consumer_list->MR_cl_next;
+
+ resume_info->MR_ri_cur_consumer_answer_list =
+ *(resume_info->MR_ri_cur_consumer->MR_cns_remaining_answer_list_ptr);
+
+ if (resume_info->MR_ri_cur_consumer_answer_list == NULL) {
+#ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("no first answer for this suspension\n");
+ }
+#endif /* MR_TABLE_DEBUG */
+ MR_GOTO_LABEL(RESUME_LABEL(LoopOverSuspensions));
+ }
+
+#ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("resuming consumer %s from table %s\n",
+ MR_consumer_addr_name(resume_info->MR_ri_cur_consumer),
+ MR_subgoal_addr_name(resume_info->MR_ri_cur_subgoal));
+ }
+#endif /* MR_TABLE_DEBUG */
+
+ MR_save_transient_registers();
+ restore_state(&(resume_info->MR_ri_cur_consumer->MR_cns_saved_state),
+ "resumption", "consumer");
+ MR_restore_transient_registers();
+
+ /* check that there is room for exactly one framevar */
+ assert((MR_maxfr - MR_prevfr_slot(MR_maxfr)) ==
+ (MR_NONDET_FIXED_SIZE + 1));
+
+ MR_gen_next = resume_info->MR_ri_leader_state.MR_ss_gen_next;
+ MR_redoip_slot(MR_maxfr) = MR_LABEL(RESUME_LABEL(RedoPoint));
+ MR_redofr_slot(MR_maxfr) = MR_maxfr;
+ MR_based_framevar(MR_maxfr, 1) = (MR_Word) MR_cur_leader;
+}
+
+MR_define_label(RESUME_LABEL(ReturnAnswer));
+{
+ MR_ResumeInfo *resume_info;
+
+ resume_info = MR_cur_leader->MR_sg_resume_info;
+
+ /*
+ ** Return the next answer in MR_cur_leader->MR_sg_resume_info->
+ ** cur_consumer_answer_list to the current consumer. Since we have
+ ** already restored the context of the suspended consumer before
+ ** we returned the first answer, we don't need to restore it again,
+ ** since will not have changed in the meantime.
+ */
+
+ MR_r1 = (MR_Word)
+ &resume_info->MR_ri_cur_consumer_answer_list->MR_aln_answer_data;
+ resume_info->MR_ri_cur_consumer->MR_cns_remaining_answer_list_ptr =
+ &(resume_info->MR_ri_cur_consumer_answer_list->MR_aln_next_answer);
+ resume_info->MR_ri_cur_consumer_answer_list =
+ resume_info->MR_ri_cur_consumer_answer_list->MR_aln_next_answer;
+
+ /*
+ ** Return the answer. Since we just restored the state of the
+ ** computation that existed when suspend was called, the code
+ ** that we return to is the code following the call to suspend.
+ */
+ MR_succeed();
+}
+
+MR_define_label(RESUME_LABEL(RedoPoint));
+ MR_update_prof_current_proc(MR_LABEL(MR_RESUME_ENTRY));
+
+ /*
+ ** This is where the current consumer suspension will go on
+ ** backtracking when it wants the next solution. If there is a solution
+ ** we haven't returned to this consumer yet, we do so, otherwise we
+ ** remember how many answers we have returned to this consumer so far
+ ** and move on to the next suspended consumer of the current subgoal.
+ */
+
+ MR_cur_leader = (MR_Subgoal *) MR_based_framevar(MR_maxfr, 1);
+
+MR_define_label(RESUME_LABEL(RestartPoint));
+{
+ MR_ResumeInfo *resume_info;
+ MR_Subgoal *cur_subgoal;
+
+ resume_info = MR_cur_leader->MR_sg_resume_info;
+
+#ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("cur_consumer_answer_list: %p\n",
+ resume_info->MR_ri_cur_consumer_answer_list);
+ printf("*cur_consumer->remaining_answer_list_ptr: %p\n",
+ *(resume_info->MR_ri_cur_consumer->
+ MR_cns_remaining_answer_list_ptr));
+ }
+#endif
+
+ if (resume_info->MR_ri_cur_consumer_answer_list != NULL) {
+ MR_GOTO_LABEL(RESUME_LABEL(ReturnAnswer));
+ }
+
+#ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("no more unreturned answers for this suspension\n");
+ }
+#endif /* MR_TABLE_DEBUG */
+
+ cur_subgoal = resume_info->MR_ri_cur_subgoal;
+ if (cur_subgoal->MR_sg_num_committed_ans != cur_subgoal->MR_sg_num_ans) {
+ resume_info->MR_ri_changed = MR_TRUE;
+ }
+
+ MR_GOTO_LABEL(RESUME_LABEL(LoopOverSuspensions));
+}
+MR_define_label(RESUME_LABEL(ReachedFixpoint));
+{
+ MR_SubgoalList table_list;
+ MR_ResumeInfo *resume_info;
+
+ for (table_list = MR_cur_leader->MR_sg_followers;
+ table_list != NULL;
+ table_list = table_list->MR_sl_next)
+ {
+#ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("marking table %s complete\n",
+ MR_subgoal_addr_name(table_list->MR_sl_item));
+ }
+#endif
+
+ table_list->MR_sl_item->MR_sg_status = MR_SUBGOAL_COMPLETE;
+ table_list->MR_sl_item->MR_sg_num_committed_ans = -1;
+ }
+
+ resume_info = MR_cur_leader->MR_sg_resume_info;
+
+ /* Restore the state we had when table_nondet_resume was called */
+ MR_save_transient_registers();
+ restore_state(&(resume_info->MR_ri_leader_state),
+ "resumption", "generator");
+ MR_restore_transient_registers();
+
+ /* XXX this will go code that does fail() */
+ MR_succip = resume_info->MR_ri_saved_succip;
+
+#ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("using resume info succip ");
+ MR_print_label(stdout, MR_succip);
+ }
+#endif /* MR_TABLE_DEBUG */
+
+ /* YYY OLD */
+ /* we should free the old resume_info structure */
+ MR_cur_leader->MR_sg_resume_info = NULL;
+
+ /* YYY OLD */
+ /* We are done with this generator */
+ (void) MR_pop_generator();
+
+ MR_proceed();
+}
+
+MR_define_entry(MR_table_nondet_commit);
+ MR_commit_cut();
+ MR_fail();
+
+MR_END_MODULE
+
+#endif /* MR_USE_MINIMAL_MODEL */
+#endif /* MR_HIGHLEVEL_CODE */
+
+/* Ensure that the initialization code for the above modules gets to run. */
+/*
+INIT mercury_sys_init_table_modules
+*/
+
+MR_MODULE_STATIC_OR_EXTERN MR_ModuleFunc table_nondet_suspend_resume_module;
+
+/* forward declarations to suppress gcc -Wmissing-decl warnings */
+void mercury_sys_init_table_modules_init(void);
+void mercury_sys_init_table_modules_init_type_tables(void);
+#ifdef MR_DEEP_PROFILING
+void mercury_sys_init_table_modules_write_out_proc_statics(FILE *fp);
+#endif
+
+void mercury_sys_init_table_modules_init(void)
+{
+#ifndef MR_HIGHLEVEL_CODE
+ table_nondet_suspend_resume_module();
+#endif /* MR_HIGHLEVEL_CODE */
+}
+
+void mercury_sys_init_table_modules_init_type_tables(void)
+{
+ /* no types to register */
+}
+
+#ifdef MR_DEEP_PROFILING
+void mercury_sys_init_table_modules_write_out_proc_statics(FILE *fp)
+{
+ /* no proc_statics to write out */
+}
+#endif
Index: runtime/mercury_minimal_model.h
===================================================================
RCS file: runtime/mercury_minimal_model.h
diff -N runtime/mercury_minimal_model.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ runtime/mercury_minimal_model.h 13 Mar 2003 06:46:09 -0000
@@ -0,0 +1,225 @@
+/*
+** Copyright (C) 2003 The University of Melbourne.
+** This file may only be copied under the terms of the GNU Library General
+** Public License - see the file COPYING.LIB in the Mercury distribution.
+*/
+
+/*
+** mercury_minimal_model.h - definitions of some basic stuff used for tabling.
+** For tabling code, the Mercury compiler (compiler/table_gen.m) generates
+** references to special procedures defined in library/table_builtin.m.
+** The types and macros defined here are used by the procedures defined in
+** library/table_builtin.m.
+*/
+
+#ifndef MERCURY_MINIMAL_MODEL_H
+#define MERCURY_MINIMAL_MODEL_H
+
+#include "mercury_imp.h"
+#include "mercury_tabling.h"
+#include "mercury_reg_workarounds.h"
+#include "mercury_goto.h" /* for MR_declare_entry */
+
+struct MR_AnswerListNode_Struct {
+ MR_Integer MR_aln_answer_num;
+ MR_TableNode MR_aln_answer_data;
+ /* always uses the MR_answerblock member */
+ MR_AnswerList MR_aln_next_answer;
+};
+
+/*
+** The saved state of a generator or a consumer. While consumers get
+** suspended while they are waiting for generators to produce more solutions,
+** generators need their state saved when they restore the state of a consumer
+** to consume a new solution.
+**
+** The saved state contains copies of
+**
+** - several virtual machine registers:
+** MR_succip, MR_sp, MR_curfr and MR_maxfr
+**
+** - segments of the nondet and det stacks:
+** the parts that cannot possibly change between the times of saving
+** and restoring the saved state are not saved.
+**
+** The segments are described by three fields each. The *_real_start
+** field gives the address of the first word in the real stack
+** that is part of the saved segment, the *_block_size field
+** gives the size of the saved segment in words, and the *_saved_block
+** field points to the area of memory containing the saved segment.
+**
+** - the entire generator stack and the entire cut stack:
+** they are usually so small, it is faster to save them all
+** than to figure out which parts need saving.
+**
+** Each stack is described by its size in words and a pointer to
+** an area of memory containing the entire saved stack.
+*/
+
+typedef struct {
+ MR_Code *MR_ss_succ_ip;
+ MR_Word *MR_ss_s_p;
+ MR_Word *MR_ss_cur_fr;
+ MR_Word *MR_ss_max_fr;
+ MR_Word *MR_ss_common_ancestor_fr;
+
+ MR_Word *MR_ss_non_stack_real_start;
+ MR_Word MR_ss_non_stack_block_size;
+ MR_Word *MR_ss_non_stack_saved_block;
+
+ MR_Word *MR_ss_det_stack_real_start;
+ MR_Word MR_ss_det_stack_block_size;
+ MR_Word *MR_ss_det_stack_saved_block;
+
+ MR_Integer MR_ss_gen_next;
+ MR_GenStackFrame *MR_ss_gen_stack_saved_block;
+
+ MR_Integer MR_ss_cut_next;
+ MR_CutStackFrame *MR_ss_cut_stack_saved_block;
+
+ MR_Integer MR_ss_pneg_next;
+ MR_PNegStackFrame *MR_ss_pneg_stack_saved_block;
+} MR_SavedState;
+
+/* The state of a consumer subgoal */
+typedef struct {
+ MR_SavedState MR_cns_saved_state;
+ MR_AnswerList *MR_cns_remaining_answer_list_ptr;
+#ifdef MR_TABLE_DEBUG
+ MR_Subgoal *MR_cns_subgoal;
+#endif
+} MR_Consumer;
+
+struct MR_ConsumerListNode_Struct {
+ MR_Consumer *MR_cl_item;
+ MR_ConsumerList MR_cl_next;
+};
+
+/*
+** The following structure is used to hold the state and variables used in
+** the table_resume procedure.
+*/
+
+typedef struct {
+ MR_SavedState MR_ri_leader_state;
+ MR_SubgoalList MR_ri_subgoal_list;
+ MR_Subgoal *MR_ri_cur_subgoal;
+ MR_ConsumerList MR_ri_consumer_list; /* for the cur subgoal */
+ MR_Consumer *MR_ri_cur_consumer;
+ MR_AnswerList MR_ri_cur_consumer_answer_list;
+ MR_bool MR_ri_changed;
+ MR_Code *MR_ri_saved_succip;
+} MR_ResumeInfo;
+
+struct MR_SubgoalListNode_Struct {
+ MR_Subgoal *MR_sl_item;
+ MR_SubgoalList MR_sl_next;
+};
+
+/*
+** The subgoal structure represents a subgoal, i.e. a call to a minimal model
+** predicate with a given set of input arguments.
+**
+** The MR_sg_status obviously gives the current status of the subgoal.
+**
+** The MR_sg_leader field points to the leader of the clique of subgoals this
+** subgoal is a member of, if the leader is not the subgoal itself. If the
+** subgoal is the leader of its clique, then this field will be NULL.
+**
+** The MR_sg_followers field lists all the subgoals that follow this one.
+** Each subgoal occurs in its own followers list.
+**
+** The MR_sg_followers_tail field points to the NULL pointer at the tail of
+** the MR_sg_followers list, to allow us to add new elements at the tail in
+** constant time.
+**
+** The MR_sg_resume_info field, when non-NULL, points to a data structure
+** containing the local variables of the algorithm executed by the builtin
+** predicate table_nondet_resume. The execution of that algorithm invokes
+** general Mercury code and moves stack segments around many times, which
+** is why its local variables cannot be stored in a stack frame.
+**
+** The MR_sg_answer_table field points to the trie of answers returned for
+** this subgoal so far (to enable efficient checks for duplicate answers).
+**
+** The MR_sg_answer_list field also contains the answers so far, in a list.
+** The answers will be returned to consumers in the order given by this list.
+** The MR_sg_answer_list_tail field points to the NULL pointer at the tail
+** of this list, to allow us to add new elements to the list at the tail in
+** constant time.
+**
+** The MR_sg_num_ans field gives the number of answers computed so far, i.e.
+** the number of answers in MR_sg_answer_table and MR_sg_answer_list.
+** The MR_sg_num_committed_ans field gives the number of answers that the
+** leader is committed to returning to all consumers.
+**
+** The MR_sg_consumer_list gives the list of consumer goals, with the field
+** MR_sg_consumer_list_tail allowing fast appending to the end.
+**
+** The MR_sg_generator_fr points to the generator's nondet stack frame.
+*/
+
+struct MR_Subgoal_Struct {
+ MR_SubgoalStatus MR_sg_status;
+ MR_Subgoal *MR_sg_leader;
+ MR_SubgoalList MR_sg_followers;
+ MR_SubgoalList *MR_sg_followers_tail;
+ MR_ResumeInfo *MR_sg_resume_info;
+ MR_Word MR_sg_answer_table;
+ MR_Integer MR_sg_num_ans;
+ MR_Integer MR_sg_num_committed_ans;
+ MR_AnswerList MR_sg_answer_list;
+ MR_AnswerList *MR_sg_answer_list_tail;
+ MR_ConsumerList MR_sg_consumer_list;
+ MR_ConsumerList *MR_sg_consumer_list_tail;
+ MR_Word *MR_sg_generator_fr;
+#ifdef MR_TABLE_DEBUG
+ MR_Proc_Layout *MR_sg_proc_layout;
+#endif MR_TABLE_DEBUG
+};
+
+/*---------------------------------------------------------------------------*/
+
+extern MR_Proc_Layout *MR_subgoal_debug_cur_proc;
+
+typedef struct MR_ConsumerDebug_Struct MR_ConsumerDebug;
+typedef struct MR_SubgoalDebug_Struct MR_SubgoalDebug;
+
+extern void MR_enter_consumer_debug(MR_Consumer *consumer);
+extern MR_ConsumerDebug *MR_lookup_consumer_debug_addr(MR_Consumer *consumer);
+extern MR_ConsumerDebug *MR_lookup_consumer_debug_num(int consumer_index);
+extern const char *MR_consumer_debug_name(MR_ConsumerDebug *consumer_dbg);
+extern const char *MR_consumer_addr_name(MR_Consumer *consumer);
+extern const char *MR_consumer_num_name(int consumer_index);
+
+extern void MR_enter_subgoal_debug(MR_Subgoal *subgoal);
+extern MR_SubgoalDebug *MR_lookup_subgoal_debug_addr(MR_Subgoal *subgoal);
+extern MR_SubgoalDebug *MR_lookup_subgoal_debug_num(int subgoal_index);
+extern const char *MR_subgoal_debug_name(MR_SubgoalDebug *subgoal_debug);
+extern const char *MR_subgoal_addr_name(MR_Subgoal *subgoal);
+extern const char *MR_subgoal_num_name(int subgoal_index);
+extern const char *MR_subgoal_status(MR_SubgoalStatus status);
+
+extern void MR_print_subgoal_debug(FILE *fp,
+ const MR_Proc_Layout *proc,
+ MR_SubgoalDebug *subgoal_debug);
+extern void MR_print_subgoal(FILE *fp, const MR_Proc_Layout *proc,
+ MR_Subgoal *subgoal);
+extern void MR_print_consumer_debug(FILE *fp,
+ const MR_Proc_Layout *proc,
+ MR_ConsumerDebug *consumer_debug);
+extern void MR_print_consumer(FILE *fp, const MR_Proc_Layout *proc,
+ MR_Consumer *consumer);
+
+
+#ifndef MR_HIGHLEVEL_CODE
+
+ #define MR_SUSPEND_ENTRY mercury__table_builtin__table_nondet_suspend_2_0
+ #define MR_RESUME_ENTRY mercury__table_builtin__table_nondet_resume_1_0
+
+ MR_declare_entry(MR_SUSPEND_ENTRY);
+ MR_declare_entry(MR_RESUME_ENTRY);
+
+#endif /* !MR_HIGHLEVEL_CODE */
+
+#endif /* MERCURY_MINIMAL_MODEL_H */
Index: runtime/mercury_regorder.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_regorder.h,v
retrieving revision 1.17
diff -u -b -r1.17 mercury_regorder.h
--- runtime/mercury_regorder.h 23 Nov 2000 02:00:37 -0000 1.17
+++ runtime/mercury_regorder.h 10 Mar 2003 09:22:00 -0000
@@ -1,5 +1,5 @@
/*
-** Copyright (C) 1994-1995, 1997-2000 The University of Melbourne.
+** Copyright (C) 1994-1995,1997-2000,2003 The University of Melbourne.
** This file may only be copied under the terms of the GNU Library General
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
@@ -115,13 +115,18 @@
#define MR_gen_next MR_LVALUE_CAST(MR_Integer, \
MR_count_usage(MR_GEN_NEXT_RN, MR_mr(42)))
#define MR_gen_stack MR_LVALUE_CAST( \
- struct MR_GeneratorStackFrameStruct *, \
+ struct MR_GenStackFrameStruct *, \
MR_count_usage(MR_GEN_STACK_RN, MR_mr(43)))
#define MR_cut_next MR_LVALUE_CAST(MR_Integer, \
MR_count_usage(MR_CUT_NEXT_RN, MR_mr(44)))
#define MR_cut_stack MR_LVALUE_CAST( \
struct MR_CutStackFrameStruct *, \
MR_count_usage(MR_CUT_STACK_RN, MR_mr(45)))
+#define MR_pneg_next MR_LVALUE_CAST(MR_Integer, \
+ MR_count_usage(MR_CUT_NEXT_RN, MR_mr(46)))
+#define MR_pneg_stack MR_LVALUE_CAST( \
+ struct MR_PNegStackFrameStruct *, \
+ MR_count_usage(MR_CUT_STACK_RN, MR_mr(47)))
#define MR_trail_ptr MR_count_usage(MR_TRAIL_PTR_RN, \
MR_trail_ptr_var)
#define MR_ticket_counter MR_count_usage(MR_TICKET_COUNTER_RN, \
@@ -141,7 +146,7 @@
#define MR_NUM_SPECIAL_REG 16
/* the maximum MR_mrN number of special registers */
-#define MR_MAX_SPECIAL_REG_MR 45
+#define MR_MAX_SPECIAL_REG_MR 47
/*
** The MR_saved_foo macros are like MR_foo except that
@@ -170,13 +175,18 @@
#define MR_saved_gen_next(save_area) MR_LVALUE_CAST(MR_Integer, \
save_area[42])
#define MR_saved_gen_stack(save_area) MR_LVALUE_CAST(struct \
- MR_GeneratorStackFrameStruct *,\
+ MR_GenStackFrameStruct *, \
save_area[43])
#define MR_saved_cut_next(save_area) MR_LVALUE_CAST(MR_Integer, \
save_area[44])
#define MR_saved_cut_stack(save_area) MR_LVALUE_CAST(struct \
MR_CutStackFrameStruct *, \
save_area[45])
+#define MR_saved_pneg_next(save_area) MR_LVALUE_CAST(MR_Integer, \
+ save_area[46])
+#define MR_saved_pneg_stack(save_area) MR_LVALUE_CAST(struct \
+ MR_PNegStackFrameStruct *, \
+ save_area[47])
#define MR_VIRTUAL_REG_MAP_BODY { \
3, \
@@ -303,13 +313,18 @@
#define MR_gen_next MR_LVALUE_CAST(MR_Integer, \
MR_count_usage(MR_GEN_NEXT_RN, MR_mr(41)))
#define MR_gen_stack MR_LVALUE_CAST( \
- struct MR_GeneratorStackFrameStruct *, \
+ struct MR_GenStackFrameStruct *, \
MR_count_usage(MR_GEN_STACK_RN, MR_mr(42)))
#define MR_cut_next MR_LVALUE_CAST(MR_Integer, \
MR_count_usage(MR_CUT_NEXT_RN, MR_mr(43)))
#define MR_cut_stack MR_LVALUE_CAST( \
struct MR_CutStackFrameStruct *, \
MR_count_usage(MR_CUT_STACK_RN, MR_mr(44)))
+#define MR_pneg_next MR_LVALUE_CAST(MR_Integer, \
+ MR_count_usage(MR_CUT_NEXT_RN, MR_mr(45)))
+#define MR_pneg_stack MR_LVALUE_CAST( \
+ struct MR_PNegStackFrameStruct *, \
+ MR_count_usage(MR_CUT_STACK_RN, MR_mr(46)))
/*
** the number of "very special" registers, i.e. special registers that can
@@ -323,7 +338,7 @@
#define MR_NUM_SPECIAL_REG 15
/* the maximum MR_mrN number of special, non rN registers */
-#define MR_MAX_SPECIAL_REG_MR 44
+#define MR_MAX_SPECIAL_REG_MR 46
/*
** The MR_saved_foo macros are like MR_foo except that
@@ -352,13 +367,18 @@
#define MR_saved_gen_stack(save_area) MR_LVALUE_CAST(MR_Integer, \
save_area[41])
#define MR_saved_gen_next(save_area) MR_LVALUE_CAST(struct \
- MR_GeneratorStackFrameStruct *,\
+ MR_GenStackFrameStruct *, \
save_area[42])
#define MR_saved_cut_stack(save_area) MR_LVALUE_CAST(MR_Integer, \
save_area[43])
#define MR_saved_cut_next(save_area) MR_LVALUE_CAST(struct \
MR_CutStackFrameStruct *,\
save_area[44])
+#define MR_saved_pneg_stack(save_area) MR_LVALUE_CAST(MR_Integer, \
+ save_area[45])
+#define MR_saved_pneg_next(save_area) MR_LVALUE_CAST(struct \
+ MR_PNegStackFrameStruct *,\
+ save_area[46])
#define MR_VIRTUAL_REG_MAP_BODY { \
2, \
Index: runtime/mercury_stack_trace.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_stack_trace.c,v
retrieving revision 1.52
diff -u -b -r1.52 mercury_stack_trace.c
--- runtime/mercury_stack_trace.c 17 Jan 2003 05:56:51 -0000 1.52
+++ runtime/mercury_stack_trace.c 14 Mar 2003 04:45:42 -0000
@@ -19,19 +19,26 @@
#include "mercury_debug.h"
#include "mercury_array_macros.h"
#include "mercury_trace_base.h"
+#include "mercury_tabling.h"
#include <stdio.h>
#if defined(MR_HAVE__SNPRINTF) && ! defined(MR_HAVE_SNPRINTF)
#define snprintf _snprintf
#endif
+static MR_Stack_Walk_Step_Result
+ MR_stack_walk_succip_layout(MR_Code *success,
+ const MR_Label_Layout **return_label_layout,
+ const char **problem_ptr);
+
#ifndef MR_HIGHLEVEL_CODE
static const char *MR_step_over_nondet_frame(FILE *fp,
int level_number, MR_Word *fr);
static MR_bool MR_find_matching_branch(MR_Word *fr, int *branch_ptr);
static void MR_record_temp_redoip(MR_Word *fr);
-static MR_Code *MR_find_temp_redoip(MR_Word *fr);
+static MR_bool MR_nofail_ip(MR_Code *ip);
+static MR_Code *MR_find_nofail_temp_redoip(MR_Word *fr);
static void MR_erase_temp_redoip(MR_Word *fr);
#endif /* !MR_HIGHLEVEL_CODE */
@@ -183,7 +190,6 @@
MR_Word **stack_trace_sp_ptr, MR_Word **stack_trace_curfr_ptr,
const char **problem_ptr)
{
- MR_Internal *label;
MR_Long_Lval location;
MR_Long_Lval_Type type;
int number;
@@ -221,6 +227,16 @@
*stack_trace_curfr_ptr = MR_succfr_slot(*stack_trace_curfr_ptr);
}
+ return MR_stack_walk_succip_layout(success, return_label_layout,
+ problem_ptr);
+}
+
+static MR_Stack_Walk_Step_Result
+MR_stack_walk_succip_layout(MR_Code *success,
+ const MR_Label_Layout **return_label_layout, const char **problem_ptr)
+{
+ MR_Internal *label;
+
if (success == MR_stack_trace_bottom) {
return MR_STEP_OK;
}
@@ -405,6 +421,11 @@
fprintf(fp, " succfr: ");
MR_print_nondstackptr(fp, MR_succfr_slot(base_maxfr));
fprintf(fp, " \n");
+#ifdef MR_USE_MINIMAL_MODEL
+ fprintf(fp, " detfr: ");
+ MR_print_detstackptr(fp, MR_table_detfr_slot(base_maxfr));
+ fprintf(fp, " \n");
+#endif
level_number++;
if (print_vars && base_maxfr > MR_nondet_stack_trace_bottom) {
@@ -434,6 +455,8 @@
MR_Word *topfr;
const MR_Label_Layout *label_layout;
const MR_Proc_Layout *proc_layout;
+ MR_Code *redoip;
+ MR_Code *success;
const char *problem;
if (MR_find_matching_branch(fr, &branch)) {
@@ -503,13 +526,25 @@
MR_nondet_branch_infos[last].branch_topfr;
MR_nondet_branch_info_next--;
} else {
- MR_Code *redoip;
-
- redoip = MR_find_temp_redoip(fr);
- if (redoip == NULL) {
+ redoip = MR_find_nofail_temp_redoip(fr);
+ if (redoip == NULL && MR_nofail_ip(MR_redoip_slot(fr))) {
redoip = MR_redoip_slot(fr);
}
+ if (redoip == NULL) {
+
+ fprintf(fp, " terminal top frame of a nondet side branch ");
+ MR_printnondstackptr(fr);
+ fprintf(fp, "\n");
+ MR_erase_temp_redoip(fr);
+
+ success = MR_succip_slot(fr);
+ base_sp = NULL;
+ base_curfr = MR_succfr_slot(fr);
+ topfr = fr;
+ result = MR_stack_walk_succip_layout(success, &label_layout,
+ &problem);
+ } else {
internal = MR_lookup_internal_by_addr(redoip);
if (internal == NULL || internal->i_layout == NULL) {
return "cannot find redoip label's layout structure";
@@ -540,6 +575,7 @@
topfr = fr;
result = MR_stack_walk_step(proc_layout, &label_layout,
&base_sp, &base_curfr, &problem);
+ }
if (result != MR_STEP_OK) {
return problem;
@@ -644,13 +680,36 @@
MR_temp_frame_info_next++;
}
+static MR_bool
+MR_nofail_ip(MR_Code *ip)
+{
+ if (ip == MR_ENTRY(MR_do_fail)) {
+ return MR_FALSE;
+ }
+ if (ip == MR_ENTRY(MR_do_trace_redo_fail_shallow)) {
+ return MR_FALSE;
+ }
+ if (ip == MR_ENTRY(MR_do_trace_redo_fail_deep)) {
+ return MR_FALSE;
+ }
+#ifdef MR_USE_MINIMAL_MODEL
+ if (ip == MR_ENTRY(MR_RESUME_ENTRY)) {
+ return MR_FALSE;
+ }
+#endif
+
+ return MR_TRUE;
+}
+
static MR_Code *
-MR_find_temp_redoip(MR_Word *fr)
+MR_find_nofail_temp_redoip(MR_Word *fr)
{
int slot;
for (slot = 0; slot < MR_temp_frame_info_next; slot++) {
- if (fr == MR_temp_frame_infos[slot].temp_redofr) {
+ if (fr == MR_temp_frame_infos[slot].temp_redofr &&
+ MR_nofail_ip(MR_temp_frame_infos[slot].temp_redoip))
+ {
return MR_temp_frame_infos[slot].temp_redoip;
}
}
@@ -903,6 +962,7 @@
event_num = MR_event_num_framevar(base_curfr) + 1;
call_num = MR_call_num_framevar(base_curfr);
depth = MR_call_depth_framevar(base_curfr);
+
}
if (MR_standardize_event_details) {
@@ -922,6 +982,16 @@
/* ensure that the remaining columns line up */
fprintf(fp, "%21s", "");
}
+
+#ifdef MR_TABLE_DEBUG
+ if (MR_DETISM_DET_STACK(entry->MR_sle_detism)) {
+ MR_print_detstackptr(fp, base_sp);
+ } else {
+ MR_print_nondstackptr(fp, base_curfr);
+ }
+
+ fprintf(fp, " ");
+#endif
}
void
Index: runtime/mercury_stacks.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_stacks.c,v
retrieving revision 1.8
diff -u -b -r1.8 mercury_stacks.c
--- runtime/mercury_stacks.c 27 Dec 2001 07:25:23 -0000 1.8
+++ runtime/mercury_stacks.c 14 Mar 2003 03:35:46 -0000
@@ -33,6 +33,8 @@
#include "mercury_runtime_util.h"
#include <stdio.h>
+/***************************************************************************/
+
#ifdef MR_STACK_FRAME_STATS
#include "mercury_dword.h"
@@ -110,22 +112,37 @@
#endif /* MR_STACK_FRAME_STATS */
+/***************************************************************************/
+
#ifdef MR_USE_MINIMAL_MODEL
-static void MR_print_gen_stack_entry(FILE *fp, MR_Integer i);
+static int MR_pneg_cut_depth = 0;
+
+static void MR_print_gen_stack_entry(FILE *fp, MR_Integer i,
+ MR_GenStackFrame *p);
+
static void MR_cleanup_generator_ptr(MR_TrieNode generator_ptr);
+static void MR_print_cut_stack_entry(FILE *fp, MR_Integer i,
+ MR_CutStackFrame *p);
+
+static void MR_cleanup_consumer_ptr(MR_TrieNode consumer_ptr);
+static void MR_print_pneg_stack_entry(FILE *fp, MR_Integer i,
+ MR_PNegStackFrame *p);
+
+/***************************************************************************/
void
MR_push_generator(MR_Word *frame_addr, MR_TrieNode table_addr)
{
- MR_gen_stack[MR_gen_next].generator_frame = frame_addr;
- MR_gen_stack[MR_gen_next].generator_table = table_addr;
+ MR_gen_stack[MR_gen_next].MR_generator_frame = frame_addr;
+ MR_gen_stack[MR_gen_next].MR_generator_table = table_addr;
MR_gen_next++;
#ifdef MR_TABLE_DEBUG
if (MR_tabledebug) {
printf("push ");
- MR_print_gen_stack_entry(stdout, MR_gen_next - 1);
+ MR_print_gen_stack_entry(stdout, MR_gen_next - 1,
+ &MR_gen_stack[MR_gen_next - 1]);
}
#endif
}
@@ -136,11 +153,12 @@
#ifdef MR_TABLE_DEBUG
if (MR_tabledebug) {
printf("top ");
- MR_print_gen_stack_entry(stdout, MR_gen_next - 1);
+ MR_print_gen_stack_entry(stdout, MR_gen_next - 1,
+ &MR_gen_stack[MR_gen_next - 1]);
}
#endif
- return MR_gen_stack[MR_gen_next - 1].generator_table->MR_subgoal;
+ return MR_gen_stack[MR_gen_next - 1].MR_generator_table->MR_subgoal;
}
void
@@ -151,7 +169,8 @@
#ifdef MR_TABLE_DEBUG
if (MR_tabledebug) {
printf("pop ");
- MR_print_gen_stack_entry(stdout, MR_gen_next);
+ MR_print_gen_stack_entry(stdout, MR_gen_next,
+ &MR_gen_stack[MR_gen_next]);
}
#endif
}
@@ -159,38 +178,46 @@
void
MR_print_gen_stack(FILE *fp)
{
-#ifdef MR_TABLE_DEBUG
- int i;
+ MR_print_any_gen_stack(fp, MR_gen_next, MR_gen_stack);
+}
- if (MR_tabledebug) {
- for (i = MR_gen_next - 1; i >= 0; i--) {
- MR_print_gen_stack_entry(fp, i);
- }
+void
+MR_print_any_gen_stack(FILE *fp, MR_Integer gen_next,
+ MR_GenStackFrame *gen_block)
+{
+ MR_Integer i;
+
+ fprintf(fp, "gen stack size: %d:\n", (int) gen_next);
+ for (i = gen_next - 1; i >= 0; i--) {
+ MR_print_gen_stack_entry(fp, i, &MR_gen_stack[i]);
}
-#endif
}
static void
-MR_print_gen_stack_entry(FILE *fp, MR_Integer i)
+MR_print_gen_stack_entry(FILE *fp, MR_Integer i, MR_GenStackFrame *p)
{
-#ifdef MR_TABLE_DEBUG
- if (MR_tabledebug) {
+ MR_SubgoalDebug *subgoal_debug;
+
fprintf(fp, "gen %ld = <", (long) i);
- MR_print_nondstackptr(fp, MR_gen_stack[i].generator_frame);
- fprintf(fp, ", %p>\n", MR_gen_stack[i].generator_table);
- }
-#endif
+ MR_print_nondstackptr(fp, p->MR_generator_frame);
+ subgoal_debug = MR_lookup_subgoal_debug_addr(
+ p->MR_generator_table->MR_subgoal);
+ fprintf(fp, ", %s>\n", MR_subgoal_debug_name(subgoal_debug));
}
+/***************************************************************************/
+
void
MR_commit_mark(void)
{
MR_restore_transient_registers();
- MR_cut_stack[MR_cut_next].frame = MR_maxfr;
- MR_cut_stack[MR_cut_next].gen_next = MR_gen_next;
- MR_cut_stack[MR_cut_next].generators = NULL;
+ MR_cut_stack[MR_cut_next].MR_cut_frame = MR_maxfr;
+ MR_cut_stack[MR_cut_next].MR_cut_gen_next = MR_gen_next;
+ MR_cut_stack[MR_cut_next].MR_cut_generators = NULL;
+ MR_cut_stack[MR_cut_next].MR_cut_depth = MR_pneg_cut_depth;
MR_cut_next++;
+ MR_pneg_cut_depth++;
#ifdef MR_TABLE_DEBUG
if (MR_tabledebug) {
@@ -207,17 +234,19 @@
MR_CutGeneratorList g;
--MR_cut_next;
+ --MR_pneg_cut_depth;
#ifdef MR_TABLE_DEBUG
if (MR_tabledebug) {
printf("commit stack next down to %ld\n",
(long) MR_cut_next);
printf("setting generator stack next back to %ld from %ld\n",
- (long) MR_cut_stack[MR_cut_next].gen_next,
+ (long) MR_cut_stack[MR_cut_next].MR_cut_gen_next,
(long) MR_gen_next);
- if (MR_gen_next != MR_cut_stack[MR_cut_next].gen_next) {
- if (MR_gen_next <= MR_cut_stack[MR_cut_next].gen_next)
+ if (MR_gen_next != MR_cut_stack[MR_cut_next].MR_cut_gen_next) {
+ if (MR_gen_next <=
+ MR_cut_stack[MR_cut_next].MR_cut_gen_next)
{
printf("MR_gen_next %ld, MR_cut_next %ld, "
"MR_cut_stack[MR_cut_next].gen_next "
@@ -225,21 +254,21 @@
(long) MR_gen_next,
(long) MR_cut_next,
(long) MR_cut_stack[MR_cut_next].
- gen_next);
+ MR_cut_gen_next);
MR_fatal_error("GEN_NEXT ASSERTION FAILURE");
}
}
}
#endif
- for (g = MR_cut_stack[MR_cut_next].generators; g != NULL;
- g = g->next_generator)
+ for (g = MR_cut_stack[MR_cut_next].MR_cut_generators; g != NULL;
+ g = g->MR_cut_next_generator)
{
- MR_cleanup_generator_ptr(g->generator_ptr);
+ MR_cleanup_generator_ptr(g->MR_cut_generator_ptr);
}
- MR_cut_stack[MR_cut_next].generators = NULL;
- MR_gen_next = MR_cut_stack[MR_cut_next].gen_next;
+ MR_cut_stack[MR_cut_next].MR_cut_generators = NULL;
+ MR_gen_next = MR_cut_stack[MR_cut_next].MR_cut_gen_next;
}
void
@@ -247,16 +276,22 @@
{
struct MR_CutGeneratorListNode *node;
+ if (MR_cut_next <= 0) {
+ return;
+ }
+
node = MR_GC_NEW(struct MR_CutGeneratorListNode);
- node->generator_ptr = generator_ptr;
- node->next_generator = MR_cut_stack[MR_cut_next - 1].generators;
- MR_cut_stack[MR_cut_next - 1].generators = node;
+ node->MR_cut_generator_ptr = generator_ptr;
+ node->MR_cut_next_generator =
+ MR_cut_stack[MR_cut_next - 1].MR_cut_generators;
+ MR_cut_stack[MR_cut_next - 1].MR_cut_generators = node;
#ifdef MR_TABLE_DEBUG
if (MR_tabledebug) {
- printf("registering generator %p -> %p "
+ printf("registering generator %p -> %s "
"at commit stack level %d\n",
- generator_ptr, generator_ptr->MR_subgoal,
+ generator_ptr,
+ MR_subgoal_addr_name(generator_ptr->MR_subgoal),
MR_cut_next - 1);
}
#endif
@@ -265,25 +300,219 @@
static void
MR_cleanup_generator_ptr(MR_TrieNode generator_ptr)
{
- if (generator_ptr->MR_subgoal->status == MR_SUBGOAL_COMPLETE) {
+ if (generator_ptr->MR_subgoal->MR_sg_status == MR_SUBGOAL_COMPLETE) {
/* there is nothing to do, everything is OK */
#ifdef MR_TABLE_DEBUG
if (MR_tabledebug) {
- printf("no cleanup: generator %p -> %p is complete\n",
- generator_ptr, generator_ptr->MR_subgoal);
+ printf("no cleanup: generator %p -> %s is complete\n",
+ generator_ptr, MR_subgoal_addr_name(
+ generator_ptr->MR_subgoal));
}
#endif
} else {
/* this generator will never complete the subgoal */
#ifdef MR_TABLE_DEBUG
if (MR_tabledebug) {
- printf("cleanup: generator %p -> %p deleted\n",
- generator_ptr, generator_ptr->MR_subgoal);
+ printf("cleanup: generator %p -> %s deleted\n",
+ generator_ptr, MR_subgoal_addr_name(
+ generator_ptr->MR_subgoal));
}
#endif
generator_ptr->MR_subgoal = NULL;
}
}
+
+void
+MR_print_cut_stack(FILE *fp)
+{
+ MR_print_any_cut_stack(fp, MR_cut_next, MR_cut_stack);
+}
+
+void
+MR_print_any_cut_stack(FILE *fp, MR_Integer cut_next,
+ MR_CutStackFrame *cut_block)
+{
+ MR_Integer i;
+
+ fprintf(fp, "cut stack size: %d:\n", (int) cut_next);
+ for (i = cut_next - 1; i >= 0; i--) {
+ MR_print_cut_stack_entry(fp, i, &cut_block[i]);
+ }
+}
+
+static void
+MR_print_cut_stack_entry(FILE *fp, MR_Integer i, MR_CutStackFrame *p)
+{
+ MR_SubgoalDebug *subgoal_debug;
+ MR_CutGeneratorList gen_list;
+
+ fprintf(fp, "cut %ld = <", (long) i);
+ MR_print_nondstackptr(fp, p->MR_cut_frame);
+ fprintf(fp, ", %d>:", p->MR_cut_gen_next);
+
+ gen_list = p->MR_cut_generators;
+ while (gen_list != NULL) {
+ if (gen_list->MR_cut_generator_ptr == NULL) {
+ fprintf(fp, " <NULL>");
+ } else {
+ subgoal_debug = MR_lookup_subgoal_debug_addr(
+ gen_list->MR_cut_generator_ptr->MR_subgoal);
+ fprintf(fp, " <%s>",
+ MR_subgoal_debug_name(subgoal_debug));
+ }
+
+ gen_list = gen_list->MR_cut_next_generator;
+ }
+
+ fprintf(fp, "\n");
+}
+
+/***************************************************************************/
+
+void
+MR_register_suspension(MR_Subgoal *subgoal)
+{
+ MR_PNegConsumerList node_ptr;
+
+ if (MR_pneg_next <= 0) {
+ return;
+ }
+
+ node_ptr = MR_TABLE_NEW(MR_PNegConsumerListNode);
+ node_ptr->MR_pneg_consumer_ptr = subgoal;
+ node_ptr->MR_pneg_next_consumer =
+ MR_pneg_stack[MR_pneg_next - 1].MR_pneg_consumers;
+ MR_pneg_stack[MR_pneg_next - 1].MR_pneg_consumers = node_ptr;
+}
+
+void
+MR_pneg_enter_cond(void)
+{
+ MR_restore_transient_registers();
+
+ MR_pneg_stack[MR_pneg_next].MR_pneg_frame = MR_maxfr;
+ MR_pneg_stack[MR_pneg_next].MR_pneg_gen_next = MR_gen_next;
+ MR_pneg_stack[MR_pneg_next].MR_pneg_depth = MR_pneg_cut_depth;
+ MR_pneg_stack[MR_pneg_next].MR_pneg_consumers = NULL;
+ MR_pneg_next++;
+ MR_pneg_cut_depth++;
+
+#ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("pneg stack next up to %ld\n", (long) MR_pneg_next);
+ }
+#endif
+
+ MR_save_transient_registers();
+}
+
+void
+MR_pneg_enter_then(void)
+{
+ MR_PNegConsumerList l;
+ MR_PNegConsumerList next;
+
+ MR_restore_transient_registers();
+
+ --MR_pneg_next;
+ --MR_pneg_cut_depth;
+
+#ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("pneg stack down up to %ld (then)\n",
+ (long) MR_pneg_next);
+ }
+#endif
+
+ for (l = MR_pneg_stack[MR_pneg_next].MR_pneg_consumers; l != NULL;
+ l = next)
+ {
+ next = l->MR_pneg_next_consumer;
+ MR_table_free(l);
+ }
+
+ MR_save_transient_registers();
+}
+
+void
+MR_pneg_enter_else(void)
+{
+ MR_PNegConsumerList l;
+ MR_PNegConsumerList next;
+
+ MR_restore_transient_registers();
+
+ --MR_pneg_next;
+ --MR_pneg_cut_depth;
+
+#ifdef MR_TABLE_DEBUG
+ if (MR_tabledebug) {
+ printf("pneg stack down up to %ld (else)\n",
+ (long) MR_pneg_next);
+ }
+#endif
+
+ for (l = MR_pneg_stack[MR_pneg_next].MR_pneg_consumers; l != NULL;
+ l = next)
+ {
+ next = l->MR_pneg_next_consumer;
+ if (l->MR_pneg_consumer_ptr->MR_sg_status !=
+ MR_SUBGOAL_COMPLETE)
+ {
+ MR_fatal_error("MR_pneg_enter_else: failing out of "
+ "negated context with incomplete consumer");
+ }
+
+ MR_table_free(l);
+ }
+
+ MR_save_transient_registers();
+}
+
+void
+MR_print_pneg_stack(FILE *fp)
+{
+ MR_print_pneg_stack_entry(fp, MR_pneg_next, MR_pneg_stack);
+}
+
+void
+MR_print_any_pneg_stack(FILE *fp, MR_Integer pneg_next,
+ MR_PNegStackFrame *pneg_block)
+{
+ MR_Integer i;
+
+ fprintf(fp, "pneg stack size: %d:\n", (int) pneg_next);
+ for (i = MR_pneg_next - 1; i >= 0; i--) {
+ MR_print_pneg_stack_entry(fp, i, &pneg_block[i]);
+ }
+}
+
+static void
+MR_print_pneg_stack_entry(FILE *fp, MR_Integer i, MR_PNegStackFrame *p)
+{
+ MR_PNegConsumerList l;
+
+ fprintf(fp, "pneg stack entry %d:\n", (int) i);
+ fprintf(fp, "gen next: %d\n", (int) p->MR_pneg_gen_next);
+ fprintf(fp, "frame: ");
+ MR_print_nondstackptr(fp, p->MR_pneg_frame);
+ fprintf(fp, "\npneg+cut stack depth %d:\n", (int) p->MR_pneg_depth);
+
+ if (p->MR_pneg_consumers == NULL) {
+ fprintf(fp, "no consumers\n");
+ } else {
+ int n;
+
+ for (n = 1, l = p->MR_pneg_consumers; l != NULL;
+ l = l->MR_pneg_next_consumer, n++)
+ {
+ fprintf(fp, "consumer %d: %s\n", n,
+ MR_subgoal_addr_name(l->MR_pneg_consumer_ptr));
+ }
+ }
+}
+
+/***************************************************************************/
#endif /* MR_USE_MINIMAL_MODEL */
Index: runtime/mercury_stacks.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_stacks.h,v
retrieving revision 1.37
diff -u -b -r1.37 mercury_stacks.h
--- runtime/mercury_stacks.h 22 Nov 2002 03:17:53 -0000 1.37
+++ runtime/mercury_stacks.h 10 Mar 2003 08:28:43 -0000
@@ -460,35 +460,67 @@
/* DEFINITIONS FOR GENERATOR STACK FRAMES */
-typedef struct MR_GeneratorStackFrameStruct {
- MR_Word *generator_frame;
- MR_TrieNode generator_table;
-} MR_GeneratorStackFrame;
+struct MR_GenStackFrameStruct {
+ MR_Word *MR_generator_frame;
+ MR_TrieNode MR_generator_table;
+};
extern void MR_push_generator(MR_Word *frame_addr,
MR_TrieNode table_addr);
extern MR_Subgoal *MR_top_generator_table(void);
extern void MR_pop_generator(void);
extern void MR_print_gen_stack(FILE *fp);
+extern void MR_print_any_gen_stack(FILE *fp,
+ MR_Integer gen_next,
+ MR_GenStackFrame *gen_block);
/* DEFINITIONS FOR CUT STACK FRAMES */
typedef struct MR_CutGeneratorListNode *MR_CutGeneratorList;
struct MR_CutGeneratorListNode {
- MR_TrieNode generator_ptr;
- MR_CutGeneratorList next_generator;
+ MR_TrieNode MR_cut_generator_ptr;
+ MR_CutGeneratorList MR_cut_next_generator;
};
-typedef struct MR_CutStackFrameStruct {
- MR_Word *frame;
- MR_Integer gen_next;
- MR_CutGeneratorList generators;
-} MR_CutStackFrame;
+struct MR_CutStackFrameStruct {
+ MR_Word *MR_cut_frame;
+ MR_Integer MR_cut_gen_next;
+ MR_CutGeneratorList MR_cut_generators;
+ int MR_cut_depth;
+};
extern void MR_commit_mark(void);
extern void MR_commit_cut(void);
extern void MR_register_generator_ptr(MR_TrieNode);
+extern void MR_print_cut_stack(FILE *fp);
+extern void MR_print_any_cut_stack(FILE *fp,
+ MR_Integer cut_next,
+ MR_CutStackFrame *cut_block);
+
+/* DEFINITIONS FOR PNEG STACK FRAMES */
+
+struct MR_PNegConsumerListNodeStruct {
+ MR_Subgoal *MR_pneg_consumer_ptr;
+ MR_PNegConsumerList MR_pneg_next_consumer;
+};
+
+struct MR_PNegStackFrameStruct {
+ MR_Word *MR_pneg_frame;
+ MR_Integer MR_pneg_gen_next;
+ MR_PNegConsumerList MR_pneg_consumers;
+ int MR_pneg_depth;
+};
+
+extern void MR_register_suspension(MR_Subgoal *subgoal);
+extern void MR_pneg_enter_cond(void);
+extern void MR_pneg_enter_then(void);
+extern void MR_pneg_enter_else(void);
+
+extern void MR_print_pneg_stack(FILE *fp);
+extern void MR_print_any_pneg_stack(FILE *fp,
+ MR_Integer pneg_next,
+ MR_PNegStackFrame *pneg_block);
#endif /* MR_USE_MINIMAL_MODEL */
Index: runtime/mercury_tabling.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_tabling.c,v
retrieving revision 1.55
diff -u -b -r1.55 mercury_tabling.c
--- runtime/mercury_tabling.c 10 Feb 2003 17:12:02 -0000 1.55
+++ runtime/mercury_tabling.c 10 Mar 2003 08:22:08 -0000
@@ -7,11 +7,16 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
+/*
+** This module contains the functions related to tabling that are not
+** specific to minimal model tabling.
+*/
+
#include "mercury_imp.h"
#include "mercury_type_info.h"
-#include "mercury_ho_call.h"
#include "mercury_array_macros.h"
+#include "mercury_builtin_types.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -1256,1081 +1261,53 @@
/*---------------------------------------------------------------------------*/
-#ifdef MR_USE_MINIMAL_MODEL
-
-/*
-** Save the current state of the Mercury abstract machine, so that the
-** current computation may be suspended for a while, and restored later.
-** The generator_{maxfr,sp} arguments give the points from which we need
-** to copy the nondet and the det stacks. The parts of those stacks below
-** the given points will not change between the suspension and the resumption
-** of this state, or if they do, the stack segments in the saved state
-** will be extended (via extend_consumer_stacks).
-*/
-
-static void
-save_state(MR_SavedState *saved_state,
- MR_Word *generator_maxfr, MR_Word *generator_sp,
- const char *who, const char *what)
-{
- MR_restore_transient_registers();
-
- #ifdef MR_HIGHLEVEL_CODE
- MR_fatal_error("sorry, not implemented: "
- "minimal model tabling with --high-level-code");
- #else
- saved_state->succ_ip = MR_succip;
- saved_state->s_p = MR_sp;
- saved_state->cur_fr = MR_curfr;
- saved_state->max_fr = MR_maxfr;
-
- saved_state->non_stack_block_start = generator_maxfr + 1;
- if (MR_maxfr > generator_maxfr) {
- saved_state->non_stack_block_size = MR_maxfr - generator_maxfr;
- saved_state->non_stack_block =
- MR_table_allocate_words(saved_state->non_stack_block_size);
- MR_table_copy_words(saved_state->non_stack_block,
- saved_state->non_stack_block_start,
- saved_state->non_stack_block_size);
- } else {
- saved_state->non_stack_block_size = 0;
- saved_state->non_stack_block = NULL;
- }
-
- saved_state->det_stack_block_start = generator_sp;
- if (MR_sp > generator_sp) {
- saved_state->det_stack_block_size = (MR_sp - 1) - generator_sp;
- saved_state->det_stack_block =
- MR_table_allocate_words(saved_state->det_stack_block_size);
- MR_table_copy_words(saved_state->det_stack_block,
- saved_state->det_stack_block_start,
- saved_state->det_stack_block_size);
- } else {
- saved_state->det_stack_block_size = 0;
- saved_state->det_stack_block = NULL;
- }
-
- #endif /* ! MR_HIGHLEVEL_CODE */
-
- saved_state->gen_next = MR_gen_next;
- saved_state->generator_stack_block = MR_table_allocate_bytes(
- MR_gen_next * sizeof(MR_GeneratorStackFrame));
- MR_table_copy_bytes(saved_state->generator_stack_block,
- MR_gen_stack, MR_gen_next * sizeof(MR_GeneratorStackFrame));
-
- saved_state->cut_next = MR_cut_next;
- saved_state->cut_stack_block = MR_table_allocate_bytes(
- MR_cut_next * sizeof(MR_CutStackFrame));
- MR_table_copy_bytes(saved_state->cut_stack_block,
- MR_cut_stack, MR_cut_next * sizeof(MR_CutStackFrame));
-
- #ifdef MR_USE_TRAIL
- /*
- ** Saving the trail state here would not be sufficient to handle
- ** the combination of trailing and minimal model tabling.
- ** Consider the following sequence of events:
- **
- ** execution enters a goal being committed across
- ** a new entry is pushed on the trail
- ** a tabled goal suspends,
- ** causing the saving of a trail segment
- ** and then a failure
- ** the goal being committed across fails,
- ** which invokes a failed commit on the trail entry
- ** ...
- ** the tabled goal is resumed,
- ** causing the restoring of the saved trail segment
- ** and then a success
- ** the goal being committed across now succeeds,
- ** which invokes a successful commit on the trail entry
- **
- ** The trail handler will be thoroughly confused by such a sequence.
- */
-
- MR_fatal_error("Sorry, not implemented: "
- "can't have both minimal model tabling and trailing");
- #endif
-
- #ifdef MR_TABLE_DEBUG
- if (MR_tabledebug) {
- printf("\n%s saves %s stacks: ", who, what);
- printf("%d non, %d det, %d generator, %d cut\n",
- saved_state->non_stack_block_size,
- saved_state->det_stack_block_size,
- MR_gen_next, MR_cut_next);
-
- #ifdef MR_HIGHLEVEL_CODE
- MR_fatal_error("sorry, not implemented: "
- "minimal model tabling with --high-level-code");
- #else
- printf("non region from ");
- MR_printnondstackptr(saved_state->non_stack_block_start);
- printf(" to ");
- MR_printnondstackptr(MR_maxfr);
- printf(" (both inclusive)\n");
- printf("stored at %p to %p (both inclusive)\n",
- saved_state->non_stack_block,
- saved_state->non_stack_block +
- saved_state->non_stack_block_size - 1);
-
- printf("det region from ");
- MR_printdetstackptr(saved_state->det_stack_block_start);
- printf(" to ");
- MR_printdetstackptr(MR_sp);
- printf(" (both inclusive)\n");
- printf("stored at %p to %p (both inclusive)\n",
- saved_state->det_stack_block,
- saved_state->det_stack_block +
- saved_state->det_stack_block_size - 1);
-
- printf("succip = %p, sp = ", (void *) MR_succip);
- MR_printdetstackptr(MR_sp);
- printf("\nmaxfr = ");
- MR_printnondstackptr(MR_maxfr);
- printf(", curfr = ");
- MR_printnondstackptr(MR_curfr);
- printf("\n\n");
- #endif
-
- MR_print_gen_stack(stdout);
-
- #ifndef MR_HIGHLEVEL_CODE
- if (MR_tablestackdebug) {
- MR_dump_nondet_stack(stdout, MR_maxfr);
- }
- #endif
- }
- #endif /* MR_TABLE_DEBUG */
-
- MR_save_transient_registers();
-}
-
-/*
-** Restore the state of the Mercury abstract machine from saved_state.
-*/
-
-static void
-restore_state(MR_SavedState *saved_state, const char *who, const char *what)
-{
- MR_restore_transient_registers();
-
- #ifdef MR_HIGHLEVEL_CODE
-
- MR_fatal_error("sorry, not implemented: "
- "minimal model tabling with --high-level-code");
-
- #else
-
- MR_succip = saved_state->succ_ip;
- MR_sp = saved_state->s_p;
- MR_curfr = saved_state->cur_fr;
- MR_maxfr = saved_state->max_fr;
-
- MR_table_copy_words(saved_state->non_stack_block_start,
- saved_state->non_stack_block,
- saved_state->non_stack_block_size);
-
- MR_table_copy_words(saved_state->det_stack_block_start,
- saved_state->det_stack_block,
- saved_state->det_stack_block_size);
-
- #endif
-
- MR_gen_next = saved_state->gen_next;
- MR_table_copy_bytes(MR_gen_stack, saved_state->generator_stack_block,
- saved_state->gen_next * sizeof(MR_GeneratorStackFrame));
-
- MR_cut_next = saved_state->cut_next;
- MR_table_copy_bytes(MR_cut_stack, saved_state->cut_stack_block,
- saved_state->cut_next * sizeof(MR_CutStackFrame));
-
- #ifdef MR_TABLE_DEBUG
- if (MR_tabledebug) {
- printf("\n%s restores %s stacks: ", who, what);
- printf("%d non, %d det, %d generator, %d cut\n",
- saved_state->non_stack_block_size,
- saved_state->det_stack_block_size,
- saved_state->gen_next, saved_state->cut_next);
-
- printf("non region from ");
- MR_printnondstackptr(saved_state->non_stack_block_start);
- printf(" to ");
- MR_printnondstackptr(saved_state->non_stack_block_start +
- saved_state->non_stack_block_size - 1);
- printf(" (both inclusive)\n");
- printf("stored at %p to %p (both inclusive)\n",
- saved_state->non_stack_block,
- saved_state->non_stack_block +
- saved_state->non_stack_block_size - 1);
-
- printf("det region from ");
- MR_printdetstackptr(saved_state->det_stack_block_start);
- printf(" to ");
- MR_printdetstackptr(saved_state->det_stack_block_start +
- saved_state->det_stack_block_size - 1);
- printf(" (both inclusive)\n");
- printf("stored at %p to %p (both inclusive)\n",
- saved_state->det_stack_block,
- saved_state->det_stack_block +
- saved_state->det_stack_block_size - 1);
-
- printf("succip = %p, sp = ", (void *) MR_succip);
- MR_printdetstackptr(MR_sp);
- printf("\nmaxfr = ");
- MR_printnondstackptr(MR_maxfr);
- printf(", curfr = ");
- MR_printnondstackptr(MR_curfr);
- printf("\n");
-
- MR_print_gen_stack(stdout);
-
- if (MR_tablestackdebug) {
- MR_dump_nondet_stack_from_layout(stdout, MR_maxfr);
- }
- }
- #endif /* MR_table_debug */
-
- MR_save_transient_registers();
-}
-
-static void
-print_saved_state_stacks(MR_SavedState *saved_state)
+void
+MR_print_answerblock(FILE *fp, const MR_Proc_Layout *proc,
+ MR_Word *answer_block)
{
+ const MR_PseudoTypeInfo *ptis;
+ MR_PseudoTypeInfo pti;
+ MR_TypeCtorInfo tci;
+ int num_inputs;
+ int num_outputs;
int i;
- printf("saved state parameters:\n");
- printf("succip:\t");
- MR_printlabel(stdout, saved_state->succ_ip);
- printf("sp:\t");
- MR_printdetstackptr(saved_state->s_p);
- printf("\ncurfr:\t");
- MR_printnondstackptr(saved_state->cur_fr);
- printf("\nmaxfr:\t");
- MR_printnondstackptr(saved_state->max_fr);
-
- printf("\n\nnondet stack block: %d words from %p\n",
- saved_state->non_stack_block_size,
- saved_state->non_stack_block_start);
- for (i = 0; i < saved_state->non_stack_block_size; i++) {
- printf("%2d: %x\n", i, saved_state->non_stack_block[i]);
- }
-
- printf("\ndet stack block: %d words from %p\n",
- saved_state->det_stack_block_size,
- saved_state->det_stack_block_start);
- for (i = 0; i < saved_state->det_stack_block_size; i++) {
- printf("%2d: %x\n", i, saved_state->det_stack_block[i]);
- }
-
- printf("\n");
-}
-
-/*
-** The saved state of a consumer for a subgoal (say subgoal A) includes
-** the stack segments between the tops of the stack at the time that
-** A's generator was entered and the time that A's consumer was entered.
-** When A becomes a follower of another subgoal B, the responsibility for
-** scheduling A's consumers passes to B's generator. Since by definition
-** B's nondet stack frame is lower in the stack than A's generator's,
-** we need to extend the stack segments of A's consumers to also include
-** the parts of the stacks between the generator of B and the generator of A.
-*/
-
-MR_declare_entry(mercury__table_builtin__table_nondet_resume_1_0);
-
-static void
-extend_consumer_stacks(MR_Subgoal *leader, MR_Consumer *suspension)
-{
- MR_Word *arena_block;
- MR_Word *arena_start;
- MR_Word arena_size;
- MR_Word extension_size;
- MR_Word *saved_fr;
- MR_Word *real_fr;
- MR_Word frame_size;
- MR_Word offset;
-
-#ifdef MR_TABLE_DEBUG
- if (MR_tablestackdebug) {
- printf("\nextending saved consumer stacks\n");
- print_saved_state_stacks(&suspension->saved_state);
- }
-#endif
-
- arena_start = leader->generator_sp;
- extension_size = suspension->saved_state.det_stack_block_start
- - arena_start;
- arena_size = extension_size
- + suspension->saved_state.det_stack_block_size;
- if (arena_size != 0) {
- assert(arena_start + arena_size
- == suspension->saved_state.s_p - 1);
- }
-
- arena_block = MR_table_allocate_words(arena_size);
-
- MR_table_copy_words(arena_block, arena_start, extension_size);
- MR_table_copy_words(arena_block + extension_size,
- suspension->saved_state.det_stack_block,
- suspension->saved_state.det_stack_block_size);
-
-#ifdef MR_TABLE_DEBUG
- if (MR_tabledebug) {
- printf("extending det stack of suspension %p for %p\n",
- suspension, leader);
- printf("start: old %p, new %p\n",
- suspension->saved_state.det_stack_block_start,
- arena_start);
- printf("size: old %d, new %d\n",
- suspension->saved_state.det_stack_block_size,
- arena_size);
- printf("block: old %p, new %p\n",
- suspension->saved_state.det_stack_block,
- arena_block);
- }
-#endif
-
- suspension->saved_state.det_stack_block = arena_block;
- suspension->saved_state.det_stack_block_size = arena_size;
- suspension->saved_state.det_stack_block_start = arena_start;
-
- arena_start = leader->generator_maxfr + 1;
- extension_size = suspension->saved_state.non_stack_block_start
- - arena_start;
- arena_size = extension_size
- + suspension->saved_state.non_stack_block_size;
- assert(leader->generator_maxfr + arena_size
- == suspension->saved_state.max_fr);
-
- arena_block = MR_table_allocate_words(arena_size);
-
- MR_table_copy_words(arena_block, arena_start, extension_size);
- MR_table_copy_words(arena_block + extension_size,
- suspension->saved_state.non_stack_block,
- suspension->saved_state.non_stack_block_size);
-
-#ifdef MR_TABLE_DEBUG
- if (MR_tabledebug) {
- printf("extending non stack of suspension %p for %p\n",
- suspension, leader);
- printf("start: old %p, new %p\n",
- suspension->saved_state.non_stack_block_start,
- arena_start);
- printf("size: old %d, new %d\n",
- suspension->saved_state.non_stack_block_size,
- arena_size);
- printf("block: old %p, new %p\n",
- suspension->saved_state.non_stack_block,
- arena_block);
- }
-#endif
-
- suspension->saved_state.non_stack_block = arena_block;
- suspension->saved_state.non_stack_block_size = arena_size;
- suspension->saved_state.non_stack_block_start = arena_start;
-
-#ifdef MR_TABLE_DEBUG
- if (MR_tablestackdebug) {
- printf("\nbefore pickling nondet stack\n");
- print_saved_state_stacks(&suspension->saved_state);
- }
-#endif
-
- saved_fr = suspension->saved_state.non_stack_block +
- suspension->saved_state.non_stack_block_size - 1;
- real_fr = suspension->saved_state.non_stack_block_start +
- suspension->saved_state.non_stack_block_size - 1;
- while (saved_fr > suspension->saved_state.non_stack_block) {
- frame_size = real_fr - MR_prevfr_slot(saved_fr);
-
- if (saved_fr - frame_size
- > suspension->saved_state.non_stack_block)
- {
- *MR_redoip_addr(saved_fr) =
- (MR_Word) MR_ENTRY(MR_do_fail);
-
-#ifdef MR_TABLE_DEBUG
- if (MR_tabledebug) {
- printf("do_fail to redoip at %p (%d)\n",
- MR_redoip_addr(saved_fr),
- MR_redoip_addr(saved_fr) -
- suspension->
- saved_state.non_stack_block);
- }
-#endif
- } else {
- *MR_redoip_addr(saved_fr) = (MR_Word)
- MR_ENTRY(mercury__table_builtin__table_nondet_resume_1_0);
-#ifdef MR_TABLE_DEBUG
- if (MR_tabledebug) {
- printf("resume to redoip at %p (%d)\n",
- MR_redoip_addr(saved_fr),
- MR_redoip_addr(saved_fr) -
- suspension->
- saved_state.non_stack_block);
- }
-#endif
- }
-
- saved_fr -= frame_size;
- real_fr -= frame_size;
- }
-
-#ifdef MR_TABLE_DEBUG
- if (MR_tablestackdebug) {
- printf("\nfinished extending saved consumer stacks\n");
- print_saved_state_stacks(&suspension->saved_state);
- }
-#endif
-}
-
-/*
-** When we discover that two subgoals depend on each other, neither can be
-** completed alone. We therefore pass responsibility for completing all
-** the subgoals in an SCC to the subgoal whose nondet stack frame is
-** lowest in the nondet stack.
-*/
-
-static void
-make_subgoal_follow_leader(MR_Subgoal *this_follower, MR_Subgoal *leader)
-{
- MR_Consumer *suspension;
- MR_SubgoalList sub_followers;
- MR_ConsumerList suspend_list;
-
- MR_restore_transient_registers();
-
-#ifdef MR_TABLE_DEBUG
- if (MR_tabledebug) {
- printf("making %p follow %p\n", this_follower, leader);
- }
-#endif
-
- for (sub_followers = this_follower->followers;
- sub_followers != NULL; sub_followers = sub_followers->next)
- {
- for (suspend_list = sub_followers->item->consumer_list;
- suspend_list != NULL;
- suspend_list = suspend_list->next)
- {
- MR_save_transient_registers();
- extend_consumer_stacks(leader, suspend_list->item);
- MR_restore_transient_registers();
- }
- }
-
- this_follower->leader = leader;
- *(leader->followers_tail) = this_follower->followers;
- this_follower->followers = NULL;
-
- MR_save_transient_registers();
-}
-
-/*
-** The following procedure saves the state of the Mercury runtime
-** so that it may be used in the table_nondet_resume procedure below to return
-** answers through this saved state. The procedure table_nondet_suspend is
-** declared as nondet but the code below is obviously of detism failure;
-** the reason for this is quite simple. Normally when a nondet proc
-** is called it will first return all of its answers and then fail. In the
-** case of calls to this procedure this is reversed: first the call will fail
-** then later on, when the answers are found, answers will be returned.
-** It is also important to note that the answers are returned not from the
-** procedure that was originally called (table_nondet_suspend) but from the
-** procedure table_nondet_resume. So essentially what is below is the code
-** to do the initial fail; the code to return the answers is in
-** table_nondet_resume.
-*/
-
-#ifndef MR_HIGHLEVEL_CODE
-
-MR_declare_entry(mercury__table_builtin__table_nondet_resume_1_0);
-MR_declare_entry(MR_do_trace_redo_fail);
-MR_declare_entry(MR_table_nondet_commit);
-MR_define_extern_entry(mercury__table_builtin__table_nondet_suspend_2_0);
-MR_MAKE_PROC_LAYOUT(mercury__table_builtin__table_nondet_suspend_2_0,
- MR_DETISM_NON, 0, MR_LONG_LVAL_TYPE_UNKNOWN,
- MR_PREDICATE, "table_builtin", "table_nondet_suspend", 2, 0);
-MR_BEGIN_MODULE(table_nondet_suspend_module)
- MR_init_entry_sl(mercury__table_builtin__table_nondet_suspend_2_0);
- MR_INIT_PROC_LAYOUT_ADDR(mercury__table_builtin__table_nondet_suspend_2_0);
-MR_BEGIN_CODE
-
-MR_define_entry(mercury__table_builtin__table_nondet_suspend_2_0);
-{
- MR_TrieNode table;
- MR_Subgoal *subgoal;
- MR_Consumer *consumer;
- MR_ConsumerList listnode;
- MR_Integer cur_gen;
- MR_Integer cur_cut;
- MR_Word *fr;
- MR_Word *prev_fr;
- MR_Word *stop_addr;
- MR_Word offset;
- MR_Word *clobber_addr;
-
- /*
- ** This frame is not used in table_nondet_suspend, but it is copied
- ** to the suspend list as part of the saved nondet stack fragment,
- ** and it *will* be used when table_nondet_resume copies back the
- ** nondet stack fragment. The framevar slot is for use by
- ** table_nondet_resume.
- */
- MR_mkframe("mercury__table_builtin__table_nondet_suspend", 1,
- MR_ENTRY(MR_do_fail));
-
- table = (MR_TrieNode) MR_r1;
- subgoal = table->MR_subgoal;
- consumer = MR_table_allocate_bytes(sizeof(MR_Consumer));
- consumer->remaining_answer_list_ptr = &subgoal->answer_list;
-
- MR_save_transient_registers();
- save_state(&(consumer->saved_state),
- subgoal->generator_maxfr, subgoal->generator_sp,
- "suspension", "consumer");
- MR_restore_transient_registers();
-
- cur_gen = MR_gen_next - 1;
- cur_cut = MR_cut_next - 1;
- stop_addr = consumer->saved_state.non_stack_block_start;
- for (fr = MR_maxfr; fr > stop_addr; fr = MR_prevfr_slot(fr))
- {
- offset = MR_redoip_addr(fr) -
- consumer->saved_state.non_stack_block_start;
- clobber_addr = consumer->saved_state.non_stack_block + offset;
-#if 0
- if (MR_tablestackdebug) {
- printf("redoip addr ");
- MR_printnondstackptr(MR_redoip_addr(fr));
- printf(", offset %d from start, ", offset);
- printf("saved copy at %p\n", clobber_addr);
- }
-#endif
-
- if (fr == MR_gen_stack[cur_gen].generator_frame) {
- if (MR_gen_stack[cur_gen].generator_table->MR_subgoal
- == subgoal)
- {
- /*
- ** This is the nondet stack frame of the
- ** generator corresponding to this consumer.
- */
-
- assert(MR_prevfr_slot(fr) == (stop_addr - 1));
- *clobber_addr = (MR_Word)
- MR_ENTRY(mercury__table_builtin__table_nondet_resume_1_0);
-#ifdef MR_TABLE_DEBUG
- if (MR_tablestackdebug) {
- printf("completing redoip "
- "of frame at ");
- MR_printnondstackptr(fr);
- printf(" (in saved copy)\n");
- }
-#endif
-
- consumer->saved_state.gen_next = cur_gen + 1;
-#ifdef MR_TABLE_DEBUG
- if (MR_tabledebug) {
- printf("saved gen_next set to %d\n",
- cur_gen + 1);
- }
-#endif
- } else {
- /*
- ** This is the nondet stack frame of some
- ** other generator.
- */
-
- assert(MR_prevfr_slot(fr) != (stop_addr - 1));
-
- *clobber_addr = (MR_Word) MR_ENTRY(MR_do_fail);
-#ifdef MR_TABLE_DEBUG
- if (MR_tablestackdebug) {
- printf("clobbering redoip "
- "of frame at ");
- MR_printnondstackptr(fr);
- printf(" (in saved copy)\n");
- }
-#endif
-
- MR_save_transient_registers();
- make_subgoal_follow_leader(
- MR_gen_stack[cur_gen].
- generator_table->MR_subgoal,
- subgoal);
- MR_restore_transient_registers();
- }
-
- cur_gen--;
- } else if (cur_cut > 0 && fr == MR_cut_stack[cur_cut].frame) {
- *clobber_addr = (MR_Word) MR_ENTRY(MR_table_nondet_commit);
-#ifdef MR_TABLE_DEBUG
- if (MR_tablestackdebug) {
- printf("committing redoip of frame at ");
- MR_printnondstackptr(fr);
- printf(" (in saved copy)\n");
- }
-#endif
-
- cur_cut--;
- } else {
- *clobber_addr = (MR_Word) MR_ENTRY(MR_do_fail);
-#ifdef MR_TABLE_DEBUG
- if (MR_tablestackdebug) {
- printf("clobbering redoip of frame at ");
- MR_printnondstackptr(fr);
- printf(" (in saved copy)\n");
- }
-#endif
- }
- }
-
-#ifdef MR_TABLE_DEBUG
- if (MR_tabledebug) {
- printf("adding suspension node %p to table %p",
- consumer, subgoal);
- printf(" at slot %p\n", subgoal->consumer_list_tail);
- }
-#endif
-
- assert(*(subgoal->consumer_list_tail) == NULL);
- listnode = MR_table_allocate_bytes(sizeof(MR_ConsumerListNode));
- *(subgoal->consumer_list_tail) = listnode;
- subgoal->consumer_list_tail = &(listnode->next);
- listnode->item = consumer;
- listnode->next = NULL;
-}
- MR_fail();
-MR_END_MODULE
-
-MR_Subgoal *MR_cur_leader;
-
-/*
-** The procedure defined below restores answers to suspended consumers.
-** It works by restoring the consumer state saved by the consumer's call
-** to table_nondet_suspend. By restoring such states and then returning
-** answers, table_nondet_resume is essentially returning answers out of
-** the call to table_nondet_suspend, not out of the call to
-** table_nondet_resume.
-**
-** The code is arranged as a three level iteration to a fixpoint.
-** The three levels are: iterating over all subgoals in a connected component,
-** iterating over all consumers of each of those subgoals, and iterating
-** over all the answers to be returned to each of those consumers.
-** Note that returning an answer could lead to further answers for
-** any of the subgoals in the connected component; it can even lead
-** to the expansion of the component (i.e. the addition of more subgoals
-** to it).
-*/
-
-MR_define_extern_entry(mercury__table_builtin__table_nondet_resume_1_0);
-MR_declare_label(mercury__table_builtin__table_nondet_resume_1_0_ChangeLoop);
-MR_declare_label(mercury__table_builtin__table_nondet_resume_1_0_ReachedFixpoint);
-MR_declare_label(mercury__table_builtin__table_nondet_resume_1_0_LoopOverSuspensions);
-MR_declare_label(mercury__table_builtin__table_nondet_resume_1_0_ReturnAnswer);
-MR_declare_label(mercury__table_builtin__table_nondet_resume_1_0_RedoPoint);
-
-MR_MAKE_PROC_LAYOUT(mercury__table_builtin__table_nondet_resume_1_0,
- MR_DETISM_NON, MR_PROC_NO_SLOT_COUNT, MR_LONG_LVAL_TYPE_UNKNOWN,
- MR_PREDICATE, "table_builtin", "table_nondet_resume", 1, 0);
-MR_MAKE_INTERNAL_LAYOUT_WITH_ENTRY(
- mercury__table_builtin__table_nondet_resume_1_0_ChangeLoop,
- mercury__table_builtin__table_nondet_resume_1_0);
-MR_MAKE_INTERNAL_LAYOUT_WITH_ENTRY(
- mercury__table_builtin__table_nondet_resume_1_0_ReachedFixpoint,
- mercury__table_builtin__table_nondet_resume_1_0);
-MR_MAKE_INTERNAL_LAYOUT_WITH_ENTRY(
- mercury__table_builtin__table_nondet_resume_1_0_LoopOverSubgoals,
- mercury__table_builtin__table_nondet_resume_1_0);
-MR_MAKE_INTERNAL_LAYOUT_WITH_ENTRY(
- mercury__table_builtin__table_nondet_resume_1_0_LoopOverSuspensions,
- mercury__table_builtin__table_nondet_resume_1_0);
-MR_MAKE_INTERNAL_LAYOUT_WITH_ENTRY(
- mercury__table_builtin__table_nondet_resume_1_0_ReturnAnswer,
- mercury__table_builtin__table_nondet_resume_1_0);
-MR_MAKE_INTERNAL_LAYOUT_WITH_ENTRY(
- mercury__table_builtin__table_nondet_resume_1_0_RedoPoint,
- mercury__table_builtin__table_nondet_resume_1_0);
-MR_MAKE_INTERNAL_LAYOUT_WITH_ENTRY(
- mercury__table_builtin__table_nondet_resume_1_0_RestartPoint,
- mercury__table_builtin__table_nondet_resume_1_0);
-
-MR_BEGIN_MODULE(table_nondet_resume_module)
- MR_init_entry_sl(mercury__table_builtin__table_nondet_resume_1_0);
- MR_INIT_PROC_LAYOUT_ADDR(mercury__table_builtin__table_nondet_resume_1_0);
- MR_init_label_sl(mercury__table_builtin__table_nondet_resume_1_0_ChangeLoop);
- MR_init_label_sl(mercury__table_builtin__table_nondet_resume_1_0_ReachedFixpoint);
- MR_init_label_sl(mercury__table_builtin__table_nondet_resume_1_0_LoopOverSubgoals);
- MR_init_label_sl(mercury__table_builtin__table_nondet_resume_1_0_LoopOverSuspensions);
- MR_init_label_sl(mercury__table_builtin__table_nondet_resume_1_0_ReturnAnswer);
- MR_init_label_sl(mercury__table_builtin__table_nondet_resume_1_0_RedoPoint);
- MR_init_label_sl(mercury__table_builtin__table_nondet_resume_1_0_RestartPoint);
-MR_BEGIN_CODE
-
-MR_define_entry(mercury__table_builtin__table_nondet_resume_1_0);
- MR_cur_leader = MR_top_generator_table();
-
- if (MR_cur_leader->leader != NULL) {
- /*
- ** The predicate that called table_nondet_resume
- ** is not the leader of its component.
- ** We will leave all answers to be returned
- ** by the leader.
- */
-
-#ifdef MR_TABLE_DEBUG
- if (MR_tabledebug) {
- printf("non-leader table_nondet_resume fails\n");
- }
-#endif
-
- (void) MR_pop_generator();
- MR_redo();
- }
-
-#ifdef MR_TABLE_DEBUG
- if (MR_tabledebug) {
- printf("table_nondet_resume enter: current leader is %p\n",
- MR_cur_leader);
- }
-#endif
-
- if (MR_cur_leader->resume_info != NULL) {
-#ifdef MR_TABLE_DEBUG
- if (MR_tabledebug) {
- printf("using existing resume info %p\n",
- MR_cur_leader->resume_info);
- }
-#endif
- } else {
- MR_cur_leader->resume_info = MR_TABLE_NEW(MR_ResumeInfo);
-
- MR_save_transient_registers();
- save_state(&(MR_cur_leader->resume_info->leader_state),
- MR_cur_leader->generator_maxfr,
- MR_cur_leader->generator_sp,
- "resumption", "generator");
- MR_restore_transient_registers();
-
-#ifdef MR_TABLE_DEBUG
- if (MR_tabledebug) {
- printf("creating new resume info %p\n",
- MR_cur_leader->resume_info);
- }
-#endif
- }
-
- MR_cur_leader->resume_info->changed = MR_TRUE;
-
-MR_define_label(mercury__table_builtin__table_nondet_resume_1_0_ChangeLoop);
-
- if (MR_cur_leader->resume_info->changed) {
-#ifdef MR_TABLE_DEBUG
- if (MR_tabledebug) {
- printf("changed flag set\n");
- }
+ num_inputs = proc->MR_sle_table_info.MR_table_gen->
+ MR_table_gen_num_inputs;
+ num_outputs = proc->MR_sle_table_info.MR_table_gen->
+ MR_table_gen_num_outputs;
+
+ ptis = proc->MR_sle_table_info.MR_table_gen->MR_table_gen_ptis;
+ ptis += num_inputs;
+
+ for (i = 0; i < num_outputs; i++) {
+ if (i > 0) {
+ fprintf(fp, ", ");
+ }
+
+ pti = ptis[i];
+ if (MR_PSEUDO_TYPEINFO_IS_VARIABLE(pti)) {
+ fprintf(fp, "poly");
+ continue;
+ }
+
+ tci = MR_PSEUDO_TYPEINFO_GET_TYPE_CTOR_INFO(pti);
+ if (tci == &MR_TYPE_CTOR_INFO_NAME(builtin, int, 0)) {
+ fprintf(fp, "%ld", (long) answer_block[i]);
+ } else if (tci == &MR_TYPE_CTOR_INFO_NAME(builtin, float, 0)) {
+ fprintf(fp, "%f",
+#ifdef MR_HIGHLEVEL_CODE
+ (double) MR_unbox_float(
+ (MR_Box) answer_block[i]));
+#else
+ (double) MR_word_to_float(answer_block[i]));
#endif
+ } else if (tci == &MR_TYPE_CTOR_INFO_NAME(builtin, string, 0)) {
+ fprintf(fp, "\"%s\"", (char *) answer_block[i]);
} else {
- MR_SubgoalList table_list;
-
- for (table_list = MR_cur_leader->resume_info->subgoal_list;
- table_list != NULL; table_list = table_list->next)
- {
- if (table_list->item->num_committed_ans
- != table_list->item->num_ans)
- {
- MR_cur_leader->resume_info->changed = MR_TRUE;
-#ifdef MR_TABLE_DEBUG
- if (MR_tabledebug) {
- printf("table %p has new answers\n",
- table_list->item);
- }
-#endif
- }
- }
- }
-
- if (! MR_cur_leader->resume_info->changed) {
-#ifdef MR_TABLE_DEBUG
- if (MR_tabledebug) {
- printf("no more changes\n");
- }
-#endif
- MR_GOTO_LABEL(
- mercury__table_builtin__table_nondet_resume_1_0_ReachedFixpoint);
+ fprintf(fp, "value of unsupported type");
}
-
- MR_cur_leader->resume_info->subgoal_list = MR_cur_leader->followers;
-
- /* For each of the subgoals on our list of followers */
-MR_define_label(mercury__table_builtin__table_nondet_resume_1_0_LoopOverSubgoals);
-
- if (MR_cur_leader->resume_info->subgoal_list == NULL) {
-#ifdef MR_TABLE_DEBUG
- if (MR_tabledebug) {
- printf("no more subgoals in the followers list\n");
- }
-#endif
-
- MR_GOTO_LABEL(mercury__table_builtin__table_nondet_resume_1_0_ChangeLoop);
- }
-
- MR_cur_leader->resume_info->cur_subgoal =
- MR_cur_leader->resume_info->subgoal_list->item;
- MR_cur_leader->resume_info->subgoal_list =
- MR_cur_leader->resume_info->subgoal_list->next;
-
- MR_cur_leader->resume_info->consumer_list =
- MR_cur_leader->resume_info->cur_subgoal->consumer_list;
-
- MR_cur_leader->resume_info->changed = MR_FALSE;
- MR_cur_leader->resume_info->cur_subgoal->num_committed_ans =
- MR_cur_leader->resume_info->cur_subgoal->num_ans;
-
- /* For each of the suspended nodes for cur_subgoal */
-MR_define_label(mercury__table_builtin__table_nondet_resume_1_0_LoopOverSuspensions);
-
- if (MR_cur_leader->resume_info->consumer_list == NULL) {
-#ifdef MR_TABLE_DEBUG
- if (MR_tabledebug) {
- printf("no more suspensions for current subgoal\n");
}
-#endif
- MR_GOTO_LABEL(
- mercury__table_builtin__table_nondet_resume_1_0_LoopOverSubgoals);
- }
-
- MR_cur_leader->resume_info->cur_consumer =
- MR_cur_leader->resume_info->consumer_list->item;
- MR_cur_leader->resume_info->consumer_list =
- MR_cur_leader->resume_info->consumer_list->next;
-
- MR_cur_leader->resume_info->cur_consumer_answer_list =
- *(MR_cur_leader->resume_info->cur_consumer->
- remaining_answer_list_ptr);
-
- if (MR_cur_leader->resume_info->cur_consumer_answer_list == NULL) {
-#ifdef MR_TABLE_DEBUG
- if (MR_tabledebug) {
- printf("no first answer for this suspension\n");
- }
-#endif
- MR_GOTO_LABEL(
- mercury__table_builtin__table_nondet_resume_1_0_LoopOverSuspensions);
- }
-
-#ifdef MR_TABLE_DEBUG
- if (MR_tabledebug) {
- printf("resuming consumer %p from table %p\n",
- (void *) MR_cur_leader->resume_info->cur_consumer,
- (void *) MR_cur_leader->resume_info->cur_subgoal);
- }
-#endif
-
- MR_save_transient_registers();
- restore_state(
- &(MR_cur_leader->resume_info->cur_consumer->saved_state),
- "resumption", "consumer");
- MR_restore_transient_registers();
-
- /* check that there is room for exactly one framevar */
- assert((MR_maxfr - MR_prevfr_slot(MR_maxfr)) ==
- (MR_NONDET_FIXED_SIZE + 1));
-
- MR_gen_next = MR_cur_leader->resume_info->leader_state.gen_next;
- MR_redoip_slot(MR_maxfr) =
- MR_LABEL(mercury__table_builtin__table_nondet_resume_1_0_RedoPoint);
- MR_redofr_slot(MR_maxfr) = MR_maxfr;
- MR_based_framevar(MR_maxfr, 1) = (MR_Word) MR_cur_leader;
-
-MR_define_label(mercury__table_builtin__table_nondet_resume_1_0_ReturnAnswer);
-
- /*
- ** Return the next answer in MR_cur_leader->resume_info->
- ** cur_consumer_answer_list to the current consumer. Since we have
- ** already restored the context of the suspended consumer before
- ** we returned the first answer, we don't need to restore it again,
- ** since will not have changed in the meantime.
- */
-
- MR_r1 = (MR_Word) &MR_cur_leader->resume_info->
- cur_consumer_answer_list->answer_data;
-
- MR_cur_leader->resume_info->cur_consumer->remaining_answer_list_ptr =
- &(MR_cur_leader->resume_info->cur_consumer_answer_list->
- next_answer);
-
- MR_cur_leader->resume_info->cur_consumer_answer_list =
- MR_cur_leader->resume_info->cur_consumer_answer_list->
- next_answer;
-
- /*
- ** Return the answer. Since we just restored the state of the
- ** computation that existed when suspend was called, the code
- ** that we return to is the code following the call to suspend.
- */
- MR_succeed();
-
-MR_define_label(mercury__table_builtin__table_nondet_resume_1_0_RedoPoint);
- MR_update_prof_current_proc(MR_LABEL(mercury__table_builtin__table_nondet_resume_1_0));
-
- /*
- ** This is where the current consumer suspension will go on
- ** backtracking when it wants the next solution. If there is a solution
- ** we haven't returned to this consumer yet, we do so, otherwise we
- ** remember how many answers we have returned to this consumer so far
- ** and move on to the next suspended consumer of the current subgoal.
- */
-
- MR_cur_leader = (MR_Subgoal *) MR_based_framevar(MR_maxfr, 1);
-
-MR_define_label(mercury__table_builtin__table_nondet_resume_1_0_RestartPoint);
-#ifdef MR_TABLE_DEBUG
- if (MR_tabledebug) {
- printf("cur_consumer_answer_list: %p\n",
- MR_cur_leader->resume_info->cur_consumer_answer_list);
- printf("*cur_consumer->remaining_answer_list_ptr: %p\n",
- *(MR_cur_leader->resume_info->cur_consumer->
- remaining_answer_list_ptr));
- }
-#endif
-
- if (MR_cur_leader->resume_info->cur_consumer_answer_list != NULL) {
- MR_GOTO_LABEL(mercury__table_builtin__table_nondet_resume_1_0_ReturnAnswer);
- }
-
-#ifdef MR_TABLE_DEBUG
- if (MR_tabledebug) {
- printf("no more unreturned answers for this suspension\n");
- }
-#endif
-
- if (MR_cur_leader->resume_info->cur_subgoal->num_committed_ans
- != MR_cur_leader->resume_info->cur_subgoal->num_ans)
- {
- MR_cur_leader->resume_info->changed = MR_TRUE;
- }
-
- MR_GOTO_LABEL(mercury__table_builtin__table_nondet_resume_1_0_LoopOverSuspensions);
-
-MR_define_label(mercury__table_builtin__table_nondet_resume_1_0_ReachedFixpoint);
- {
- MR_SubgoalList table_list;
-
- for (table_list = MR_cur_leader->followers;
- table_list != NULL; table_list = table_list->next)
- {
-#ifdef MR_TABLE_DEBUG
- if (MR_tabledebug) {
- printf("marking table %p complete\n",
- table_list->item);
- }
-#endif
-
- table_list->item->status = MR_SUBGOAL_COMPLETE;
- table_list->item->num_committed_ans = -1;
- }
- }
-
- /* Restore the state we had when table_nondet_resume was called */
- MR_save_transient_registers();
- restore_state(&(MR_cur_leader->resume_info->leader_state),
- "resumption", "generator");
- MR_restore_transient_registers();
-
- /* XXX we should free this cell and its components */
- MR_cur_leader->resume_info = NULL;
-
- /* We are done with this generator */
- (void) MR_pop_generator();
-
- MR_proceed();
-MR_END_MODULE
-
-MR_define_extern_entry(MR_table_nondet_commit);
-MR_BEGIN_MODULE(table_nondet_commit_module)
- MR_init_entry_an(MR_table_nondet_commit);
-MR_BEGIN_CODE
-MR_define_entry(MR_table_nondet_commit);
- MR_commit_cut();
- MR_fail();
-MR_END_MODULE
-
-#endif /* ! MR_HIGHLEVEL_CODE */
-
-#endif /* MR_USE_MINIMAL_MODEL */
-
-#ifdef MR_HIGHLEVEL_CODE
-
-/*
-** We need to define stubs for these, even if MR_USE_MINIMAL_MODEL
-** is not enabled, since they are declared as `:- external', and
-** hence for profiling grades the generated code will take their
-** address to store in the label table.
-*/
-
-/* Declare them first, to avoid warnings from gcc -Wmissing-decls */
-void MR_CALL mercury__table_builtin__table_nondet_resume_1_p_0(
- MR_C_Pointer subgoal_table_node, MR_C_Pointer *answer_block,
- MR_Cont cont, void *cont_env_ptr);
-void MR_CALL mercury__table_builtin__table_nondet_suspend_2_p_0(
- MR_C_Pointer subgoal_table_node);
-
-void MR_CALL
-mercury__table_builtin__table_nondet_resume_1_p_0(
- MR_C_Pointer subgoal_table_node, MR_C_Pointer *answer_block,
- MR_Cont cont, void *cont_env_ptr)
-{
- MR_fatal_error("sorry, not implemented: "
- "minimal model tabling with --high-level-code");
}
-void MR_CALL
-mercury__table_builtin__table_nondet_suspend_2_p_0(
- MR_C_Pointer subgoal_table_node)
-{
- MR_fatal_error("sorry, not implemented: "
- "minimal model tabling with --high-level-code");
-}
-
-#endif /* MR_HIGHLEVEL_CODE */
-
-/* Ensure that the initialization code for the above modules gets to run. */
-/*
-INIT mercury_sys_init_table_modules
-*/
-
-#ifdef MR_USE_MINIMAL_MODEL
-MR_MODULE_STATIC_OR_EXTERN MR_ModuleFunc table_nondet_suspend_module;
-MR_MODULE_STATIC_OR_EXTERN MR_ModuleFunc table_nondet_resume_module;
-MR_MODULE_STATIC_OR_EXTERN MR_ModuleFunc table_nondet_commit_module;
-#endif
-
-/* forward declarations to suppress gcc -Wmissing-decl warnings */
-void mercury_sys_init_table_modules_init(void);
-void mercury_sys_init_table_modules_init_type_tables(void);
-#ifdef MR_DEEP_PROFILING
-void mercury_sys_init_table_modules_write_out_proc_statics(FILE *fp);
-#endif
-
-void mercury_sys_init_table_modules_init(void)
-{
-#ifdef MR_USE_MINIMAL_MODEL
- table_nondet_suspend_module();
- table_nondet_resume_module();
- table_nondet_commit_module();
-#endif
-}
-
-void mercury_sys_init_table_modules_init_type_tables(void)
-{
- /* no types to register */
-}
-
-#ifdef MR_DEEP_PROFILING
-void mercury_sys_init_table_modules_write_out_proc_statics(FILE *fp)
-{
- /* no proc_statics to write out */
-}
-#endif
+/*---------------------------------------------------------------------------*/
Index: runtime/mercury_tabling.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_tabling.h,v
retrieving revision 1.29
diff -u -b -r1.29 mercury_tabling.h
--- runtime/mercury_tabling.h 15 Nov 2002 04:50:41 -0000 1.29
+++ runtime/mercury_tabling.h 10 Mar 2003 08:24:51 -0000
@@ -1,5 +1,5 @@
/*
-** Copyright (C) 1997-2000,2002 The University of Melbourne.
+** Copyright (C) 1997-2000,2002-2003 The University of Melbourne.
** This file may only be copied under the terms of the GNU Library General
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
@@ -20,6 +20,8 @@
#include "mercury_float.h"
#include "mercury_reg_workarounds.h"
#include "mercury_dlist.h"
+#include "mercury_goto.h" /* for MR_declare_entry */
+#include "mercury_stack_layout.h" /* for MR_Proc_Layout */
#ifndef MR_CONSERVATIVE_GC
#include "mercury_deep_copy.h"
@@ -30,22 +32,6 @@
/*---------------------------------------------------------------------------*/
/*
-** Forward declarations of type names.
-*/
-
-typedef struct MR_HashTable_Struct MR_HashTable;
-typedef struct MR_Subgoal_Struct MR_Subgoal;
-typedef struct MR_SubgoalListNode_Struct MR_SubgoalListNode;
-typedef struct MR_AnswerListNode_Struct MR_AnswerListNode;
-typedef struct MR_ConsumerListNode_Struct MR_ConsumerListNode;
-
-typedef MR_SubgoalListNode *MR_SubgoalList;
-typedef MR_AnswerListNode *MR_AnswerList;
-typedef MR_ConsumerListNode *MR_ConsumerList;
-
-/*---------------------------------------------------------------------------*/
-
-/*
** Tabling builds up two kinds of tables, both conceptually tries. For call
** tables, there is one layer in the trie for each input argument; for answer
** tables, there is one layer in the trie for each output argument. However,
@@ -149,122 +135,6 @@
MR_SUBGOAL_COMPLETE
} MR_SubgoalStatus;
-struct MR_AnswerListNode_Struct {
- MR_Integer answer_num;
- MR_TableNode answer_data; /* always uses the MR_answerblock member */
- MR_AnswerList next_answer;
-};
-
-/*
-** The saved state of a generator or a consumer. While consumers get
-** suspended while they are waiting for generators to produce more solutions,
-** generators need their state saved when they restore the state of a consumer
-** to consume a new solution.
-**
-** The saved state contains copies of
-**
-** - several virtual machine registers:
-** MR_succip, MR_sp, MR_curfr and MR_maxfr
-**
-** - segments of the nondet and det stacks:
-** the parts that cannot possibly change between the times of saving
-** and restoring the saved state are not saved.
-**
-** The segments are described by three fields each. The *_block_start
-** field gives the address of the first word in the real stack
-** that is part of the saved segment, the *_block_size field
-** gives the size of the saved segment in words, and the *_block
-** field points to the area of memory containing the saved segment.
-**
-** - the entire generator stack and the entire cut stack:
-** they are usually so small, it is faster to save them all
-** than to figure out which parts need saving.
-**
-** Each stack is described by its size in words and a pointer to
-** an area of memory containing the entire saved stack.
-*/
-
-typedef struct {
- MR_Code *succ_ip;
- MR_Word *s_p;
- MR_Word *cur_fr;
- MR_Word *max_fr;
- MR_Word *non_stack_block_start;
- MR_Word non_stack_block_size;
- MR_Word *non_stack_block;
- MR_Word *det_stack_block_start;
- MR_Word det_stack_block_size;
- MR_Word *det_stack_block;
- MR_Integer gen_next;
- char *generator_stack_block;
- MR_Integer cut_next;
- char *cut_stack_block;
-} MR_SavedState;
-
-/* The state of a consumer subgoal */
-typedef struct {
- MR_SavedState saved_state;
- MR_AnswerList *remaining_answer_list_ptr;
-} MR_Consumer;
-
-struct MR_ConsumerListNode_Struct {
- MR_Consumer *item;
- MR_ConsumerList next;
-};
-
-/*
-** The following structure is used to hold the state and variables used in
-** the table_resume procedure.
-*/
-
-typedef struct {
- MR_SavedState leader_state;
- MR_SubgoalList subgoal_list;
- MR_Subgoal *cur_subgoal;
- MR_ConsumerList consumer_list; /* for the current subgoal */
- MR_Consumer *cur_consumer;
- MR_AnswerList cur_consumer_answer_list;
- MR_bool changed;
-} MR_ResumeInfo;
-
-struct MR_SubgoalListNode_Struct {
- MR_Subgoal *item;
- MR_SubgoalList next;
-};
-
-/* Used to save info about a single subgoal in the table */
-struct MR_Subgoal_Struct {
- MR_SubgoalStatus status;
- MR_Subgoal *leader;
- MR_SubgoalList followers;
- MR_SubgoalList *followers_tail;
- MR_ResumeInfo *resume_info;
- MR_Word answer_table; /* Table of answers returned */
- /* by the subgoal */
- MR_Integer num_ans; /* # of answers returned */
- /* by the subgoal */
- MR_Integer num_committed_ans;
- /* # of answers our leader */
- /* is committed to returning */
- /* to every consumer. */
- MR_AnswerList answer_list; /* List of answers returned */
- /* by the subgoal */
- MR_AnswerList *answer_list_tail;
- /* Pointer to the tail of */
- /* the answer list. This is */
- /* used to update the tail. */
- MR_ConsumerList consumer_list; /* List of suspended calls */
- /* to the subgoal */
- MR_ConsumerList *consumer_list_tail;
- /* As for answer_list_tail */
- MR_Word *generator_maxfr;
- /* MR_maxfr at the time of */
- /* the call to the generator */
- MR_Word *generator_sp;
- /* MR_sp at the time of the */
- /* call to the generator */
-};
-
/*---------------------------------------------------------------------------*/
/*
@@ -362,6 +232,14 @@
extern void MR_table_report_statistics(FILE *fp);
+/*
+** Prints the given answer_block of the given procedure to fp.
+*/
+extern void MR_print_answerblock(FILE *fp,
+ const MR_Proc_Layout *proc,
+ MR_Word *answer_block);
+
+
/*---------------------------------------------------------------------------*/
#ifndef MR_NATIVE_GC
@@ -375,17 +253,30 @@
#define MR_TABLE_RESIZE_ARRAY(ptr, type, count) \
MR_GC_RESIZE_ARRAY((ptr), type, (count))
+#if 0
#define MR_table_allocate_bytes(size) \
MR_GC_malloc((size))
#define MR_table_reallocate_bytes(pointer, size) \
MR_GC_realloc((pointer), (size))
+#endif
#define MR_table_allocate_words(size) \
- MR_GC_malloc(sizeof(MR_Word) * (size))
+ ((MR_Word *) MR_GC_malloc(sizeof(MR_Word) * (size)))
#define MR_table_reallocate_words(pointer, size) \
- MR_GC_realloc((pointer), sizeof(MR_Word) * (size))
+ (MR_CHECK_EXPR_TYPE((pointer), MR_Word *), \
+ (MR_Word *) MR_GC_realloc((pointer), sizeof(MR_Word) * (size)))
+
+ #define MR_table_allocate_struct(type) \
+ ((type *) MR_GC_malloc(sizeof(type)))
+
+ #define MR_table_allocate_structs(num, type) \
+ ((type *) MR_GC_malloc(sizeof(type) * (num)))
+
+ #define MR_table_reallocate_structs(pointer, num, type) \
+ (MR_CHECK_EXPR_TYPE((pointer), type *), \
+ (type *) MR_GC_realloc((pointer), sizeof(type) * (num)))
#define MR_table_free(pointer) \
MR_GC_free((pointer))
@@ -407,18 +298,29 @@
#define MR_TABLE_RESIZE_ARRAY(pointer, type, count) \
(MR_fatal_error(MR_TABLE_NATIVE_GC_MSG), \
(void *) NULL)
+#if 0
#define MR_table_allocate_bytes(size) \
(MR_fatal_error(MR_TABLE_NATIVE_GC_MSG), \
(void *) NULL)
#define MR_table_reallocate_bytes(pointer, size) \
(MR_fatal_error(MR_TABLE_NATIVE_GC_MSG), \
(void *) NULL)
+#endif
#define MR_table_allocate_words(size) \
(MR_fatal_error(MR_TABLE_NATIVE_GC_MSG), \
(void *) NULL)
#define MR_table_reallocate_words(pointer, size) \
(MR_fatal_error(MR_TABLE_NATIVE_GC_MSG), \
(void *) NULL)
+ #define MR_table_allocate_struct(type) \
+ (MR_fatal_error(MR_TABLE_NATIVE_GC_MSG), \
+ (void *) NULL)
+ #define MR_table_allocate_structs(num, type) \
+ (MR_fatal_error(MR_TABLE_NATIVE_GC_MSG), \
+ (void *) NULL)
+ #define MR_table_reallocate_structs(pointer, num, type) \
+ (MR_fatal_error(MR_TABLE_NATIVE_GC_MSG), \
+ (void *) NULL)
#define MR_table_free(pointer) \
MR_fatal_error(MR_TABLE_NATIVE_GC_MSG)
#define MR_table_list_cons(h, t) \
@@ -431,7 +333,16 @@
MR_memcpy((dest), (source), (size))
#define MR_table_copy_words(dest, source, size) \
- MR_memcpy((char *) (dest), (char *) (source), sizeof(MR_Word) * (size))
+ (MR_CHECK_EXPR_TYPE((dest), MR_Word *), \
+ (MR_CHECK_EXPR_TYPE((source), MR_Word *), \
+ MR_memcpy((char *) (dest), (char *) (source), \
+ sizeof(MR_Word) * (size))))
+
+#define MR_table_copy_structs(dest, source, num, type) \
+ (MR_CHECK_EXPR_TYPE((dest), type *), \
+ (MR_CHECK_EXPR_TYPE((source), type *), \
+ MR_memcpy((char *) (dest), (char *) (source), \
+ sizeof(type) * (num))))
/*---------------------------------------------------------------------------*/
Index: runtime/mercury_trace_base.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_trace_base.h,v
retrieving revision 1.31
diff -u -b -r1.31 mercury_trace_base.h
--- runtime/mercury_trace_base.h 8 Nov 2002 08:48:21 -0000 1.31
+++ runtime/mercury_trace_base.h 18 Nov 2002 04:19:47 -0000
@@ -19,6 +19,7 @@
#include "mercury_stack_layout.h"
#include "mercury_std.h"
#include "mercury_tabling.h" /* for MR_TableNode */
+#include "mercury_goto.h" /* for MR_declare_entry */
/*
** This enum should EXACTLY match the definition of the `trace_port_type'
@@ -345,5 +346,12 @@
int *histogram, int max);
#endif /* MR_TRACE_HISTOGRAM */
+
+#ifndef MR_HIGHLEVEL_CODE
+
+MR_declare_entry(MR_do_trace_redo_fail_shallow);
+MR_declare_entry(MR_do_trace_redo_fail_deep);
+
+#endif /* !MR_HIGHLEVEL_CODE */
#endif /* MERCURY_TRACE_BASE_H */
Index: runtime/mercury_types.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_types.h,v
retrieving revision 1.30
diff -u -b -r1.30 mercury_types.h
--- runtime/mercury_types.h 15 Nov 2002 04:50:41 -0000 1.30
+++ runtime/mercury_types.h 10 Mar 2003 08:28:42 -0000
@@ -135,6 +135,25 @@
typedef union MR_TableNode_Union MR_TableNode;
typedef MR_TableNode *MR_TrieNode;
+typedef struct MR_HashTable_Struct MR_HashTable;
+typedef struct MR_Subgoal_Struct MR_Subgoal;
+typedef struct MR_SubgoalListNode_Struct MR_SubgoalListNode;
+typedef struct MR_AnswerListNode_Struct MR_AnswerListNode;
+typedef struct MR_ConsumerListNode_Struct MR_ConsumerListNode;
+
+typedef MR_SubgoalListNode *MR_SubgoalList;
+typedef MR_AnswerListNode *MR_AnswerList;
+typedef MR_ConsumerListNode *MR_ConsumerList;
+
+typedef struct MR_GenStackFrameStruct MR_GenStackFrame;
+typedef struct MR_CutStackFrameStruct MR_CutStackFrame;
+typedef struct MR_PNegStackFrameStruct MR_PNegStackFrame;
+
+typedef struct MR_PNegConsumerListNodeStruct MR_PNegConsumerListNode;
+typedef MR_PNegConsumerListNode *MR_PNegConsumerList;
+
+/*---------------------------------------------------------------------------*/
+
/*
** The MR_Box type is used for representing polymorphic types.
** Currently this is only used in the MLDS C backend.
Index: runtime/mercury_wrapper.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_wrapper.c,v
retrieving revision 1.117
diff -u -b -r1.117 mercury_wrapper.c
--- runtime/mercury_wrapper.c 3 Mar 2003 16:30:44 -0000 1.117
+++ runtime/mercury_wrapper.c 7 Mar 2003 04:23:41 -0000
@@ -68,8 +68,9 @@
size_t MR_global_heap_size = 1024;
size_t MR_trail_size = 128;
size_t MR_debug_heap_size = 4096;
-size_t MR_generatorstack_size = 32;
+size_t MR_genstack_size = 32;
size_t MR_cutstack_size = 32;
+size_t MR_pnegstack_size = 32;
/* size of the redzones at the end of data areas, in kilobytes */
/* (but we later multiply by 1024 to convert to bytes) */
@@ -80,8 +81,9 @@
size_t MR_global_heap_zone_size = 16;
size_t MR_trail_zone_size = 16;
size_t MR_debug_heap_zone_size = 16;
-size_t MR_generatorstack_zone_size = 16;
+size_t MR_genstack_zone_size = 16;
size_t MR_cutstack_zone_size = 16;
+size_t MR_pnegstack_zone_size = 16;
/*
** MR_heap_margin_size is used for accurate GC with the MLDS->C back-end.
Index: runtime/mercury_wrapper.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_wrapper.h,v
retrieving revision 1.56
diff -u -b -r1.56 mercury_wrapper.h
--- runtime/mercury_wrapper.h 8 Nov 2002 00:45:49 -0000 1.56
+++ runtime/mercury_wrapper.h 7 Dec 2002 13:41:22 -0000
@@ -190,8 +190,9 @@
extern size_t MR_trail_size;
extern size_t MR_global_heap_size;
extern size_t MR_debug_heap_size;
-extern size_t MR_generatorstack_size;
+extern size_t MR_genstack_size;
extern size_t MR_cutstack_size;
+extern size_t MR_pnegstack_size;
/* sizes of the red zones */
extern size_t MR_heap_zone_size;
@@ -201,8 +202,9 @@
extern size_t MR_trail_zone_size;
extern size_t MR_global_heap_zone_size;
extern size_t MR_debug_heap_zone_size;
-extern size_t MR_generatorstack_zone_size;
+extern size_t MR_genstack_zone_size;
extern size_t MR_cutstack_zone_size;
+extern size_t MR_pnegstack_zone_size;
/* heap margin for MLDS->C accurate GC (documented in mercury_wrapper.c) */
extern size_t MR_heap_margin_size;
cvs diff: Diffing runtime/GETOPT
cvs diff: Diffing runtime/machdeps
cvs diff: Diffing samples
cvs diff: Diffing samples/c_interface
cvs diff: Diffing samples/c_interface/c_calls_mercury
cvs diff: Diffing samples/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/c_interface/mercury_calls_c
cvs diff: Diffing samples/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/diff
cvs diff: Diffing samples/muz
cvs diff: Diffing samples/rot13
cvs diff: Diffing samples/solutions
cvs diff: Diffing samples/tests
cvs diff: Diffing samples/tests/c_interface
cvs diff: Diffing samples/tests/c_interface/c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/tests/c_interface/mercury_calls_c
cvs diff: Diffing samples/tests/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/tests/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/tests/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/tests/diff
cvs diff: Diffing samples/tests/muz
cvs diff: Diffing samples/tests/rot13
cvs diff: Diffing samples/tests/solutions
cvs diff: Diffing samples/tests/toplevel
cvs diff: Diffing scripts
cvs diff: Diffing tests
cvs diff: Diffing tests/benchmarks
cvs diff: Diffing tests/debugger
Index: tests/debugger/all_solutions.exp3
===================================================================
RCS file: tests/debugger/all_solutions.exp3
diff -N tests/debugger/all_solutions.exp3
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/debugger/all_solutions.exp3 11 Mar 2003 04:13:50 -0000
@@ -0,0 +1,22 @@
+ 1: 1 1 CALL pred all_solutions.main/2-0 (det) all_solutions.m:16
+mdb> echo on
+Command echo enabled.
+mdb> context none
+Contexts will not be printed.
+mdb> register --quiet
+mdb> break hello
+ 0: + stop interface pred all_solutions.hello/1-0 (multi)
+mdb> continue
+ 2: 2 2 CALL pred all_solutions.hello/1-0 (multi)
+mdb> stack
+ 0 pred all_solutions.hello/1-0 (multi)
+reached label with no stack layout info.
+mdb> retry 1
+reached label with no stack layout info
+mdb> retry 2
+reached label with no stack layout info
+mdb> retry 3
+reached label with no stack layout info
+mdb> continue -n -S
+Hello again, world
+Hello, world
Index: tests/debugger/exception_value.exp3
===================================================================
RCS file: tests/debugger/exception_value.exp3
diff -N tests/debugger/exception_value.exp3
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/debugger/exception_value.exp3 11 Mar 2003 03:28:40 -0000
@@ -0,0 +1,42 @@
+ E1: C1 1 CALL pred exception_value.main/2-0 (cc_multi) exception_value.m:12
+mdb> echo on
+Command echo enabled.
+mdb> register --quiet
+mdb> break p
+ 0: + stop interface pred exception_value.p/1-0 (det)
+mdb> break q
+ 1: + stop interface pred exception_value.q/1-0 (det)
+mdb> continue
+ E2: C2 3 CALL pred exception_value.p/1-0 (det) exception_value.m:30
+mdb> finish
+ E3: C2 3 EXCP pred exception_value.p/1-0 (det)
+mdb> print exception
+ "p exception"
+mdb> continue
+mdb: warning: reached unknown label
+This may result in some exception events
+being omitted from the trace.
+exception(univ_cons("p exception"))
+ E4: C3 3 CALL pred exception_value.q/1-0 (det) exception_value.m:35
+mdb> finish
+ E5: C3 3 EXCP pred exception_value.q/1-0 (det)
+mdb> browse exception
+browser> set depth 9
+browser> set size 99
+browser> ls
+-
+1-"q oops"
+2-[|]
+ 1-1
+ 2-[|]
+ 1-2
+ 2-[|]
+ 1-3
+ 2-[]
+
+browser> quit
+mdb> continue
+mdb: warning: reached unknown label
+This may result in some exception events
+being omitted from the trace.
+exception(univ_cons("q oops" - [1, 2, 3]))
Index: tests/debugger/mdb_command_test.inp
===================================================================
RCS file: /home/mercury1/repository/tests/debugger/mdb_command_test.inp,v
retrieving revision 1.23
diff -u -b -r1.23 mdb_command_test.inp
--- tests/debugger/mdb_command_test.inp 11 Mar 2003 02:44:24 -0000 1.23
+++ tests/debugger/mdb_command_test.inp 11 Mar 2003 02:54:07 -0000
@@ -45,7 +45,10 @@
histogram_all xyzzy xyzzy xyzzy xyzzy xyzzy
histogram_exp xyzzy xyzzy xyzzy xyzzy xyzzy
clear_histogram xyzzy xyzzy xyzzy xyzzy xyzzy
+subgoal xyzzy xyzzy xyzzy xyzzy xyzzy
gen_stack xyzzy xyzzy xyzzy xyzzy xyzzy
+cut_stack xyzzy xyzzy xyzzy xyzzy xyzzy
+pneg_stack xyzzy xyzzy xyzzy xyzzy xyzzy
nondet_stack xyzzy xyzzy xyzzy xyzzy xyzzy
stack_regs xyzzy xyzzy xyzzy xyzzy xyzzy
all_regs xyzzy xyzzy xyzzy xyzzy xyzzy
cvs diff: Diffing tests/debugger/declarative
Index: tests/debugger/declarative/catch.exp3
===================================================================
RCS file: tests/debugger/declarative/catch.exp3
diff -N tests/debugger/declarative/catch.exp3
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/debugger/declarative/catch.exp3 10 Mar 2003 10:35:01 -0000
@@ -0,0 +1,40 @@
+ 1: 1 1 CALL pred catch.main/2-0 (cc_multi) catch.m:8
+mdb> echo on
+Command echo enabled.
+mdb> register --quiet
+mdb> break p
+ 0: + stop interface pred catch.p/2-0 (cc_multi)
+mdb> continue
+ 2: 2 2 CALL pred catch.p/2-0 (cc_multi) catch.m:18 (catch.m:9)
+mdb> finish
+mdb: warning: reached label with no stack layout info
+This may result in some exception events
+being omitted from the trace.
+ 7: 2 2 EXIT pred catch.p/2-0 (cc_multi) catch.m:18 (catch.m:9)
+mdb> dd
+mdb: warning: reached label with no stack layout info
+This may result in some exception events
+being omitted from the trace.
+p(1, exception(univ_cons("q: bad input")))
+Valid? no
+Sorry, the diagnosis cannot continue because it requires support for
+the following: code that catches exceptions.
+The debugger is a work in progress, and this is not supported in the
+current version.
+ 7: 2 2 EXIT pred catch.p/2-0 (cc_multi) catch.m:18 (catch.m:9)
+mdb> continue
+exception(univ_cons("q: bad input"))
+ 8: 4 2 CALL pred catch.p/2-0 (cc_multi) catch.m:18 (catch.m:12)
+mdb> finish
+ 13: 4 2 EXIT pred catch.p/2-0 (cc_multi) catch.m:18 (catch.m:12)
+mdb> dd
+p(2, succeeded(2))
+Valid? no
+q(2, 2)
+Valid? yes
+Found incorrect contour:
+p(2, succeeded(2))
+Is this a bug? yes
+ 13: 4 2 EXIT pred catch.p/2-0 (cc_multi) catch.m:18 (catch.m:12)
+mdb> continue
+succeeded(2)
Index: tests/debugger/declarative/ho5.exp3
===================================================================
RCS file: tests/debugger/declarative/ho5.exp3
diff -N tests/debugger/declarative/ho5.exp3
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/debugger/declarative/ho5.exp3 10 Mar 2003 10:36:02 -0000
@@ -0,0 +1,48 @@
+ 1: 1 1 CALL pred ho5.main/2-0 (cc_multi) ho5.m:8
+mdb> echo on
+Command echo enabled.
+mdb> register --quiet
+mdb> break p
+ 0: + stop interface pred ho5.p/2-0 (det)
+mdb> continue
+ 2: 2 2 CALL pred ho5.p/2-0 (det) ho5.m:18
+mdb> finish
+ 9: 2 2 EXCP pred ho5.p/2-0 (det) c2; ho5.m:18
+mdb> dd
+Call p(1, _)
+Throws zero
+Expected? no
+q(1, 0)
+Valid? yes
+Call r(0, _)
+Throws zero
+Expected? yes
+Found unhandled exception:
+p(1, _)
+zero
+Is this a bug? yes
+ 9: 2 2 EXCP pred ho5.p/2-0 (det) c2; ho5.m:18
+mdb> continue
+mdb: warning: reached label with no stack layout info
+This may result in some exception events
+being omitted from the trace.
+exception(univ_cons('<<function>>'))
+ 10: 5 2 CALL pred ho5.p/2-0 (det) ho5.m:18
+mdb> finish
+ 17: 5 2 EXCP pred ho5.p/2-0 (det) c2; ho5.m:18
+mdb> dd
+Call p(2, _)
+Throws zero
+Expected? no
+q(2, 0)
+Valid? yes
+Found unhandled exception:
+p(2, _)
+zero
+Is this a bug? yes
+ 17: 5 2 EXCP pred ho5.p/2-0 (det) c2; ho5.m:18
+mdb> continue
+mdb: warning: reached label with no stack layout info
+This may result in some exception events
+being omitted from the trace.
+exception(univ_cons('<<function>>'))
Index: tests/debugger/declarative/throw.exp3
===================================================================
RCS file: tests/debugger/declarative/throw.exp3
diff -N tests/debugger/declarative/throw.exp3
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/debugger/declarative/throw.exp3 10 Mar 2003 10:37:25 -0000
@@ -0,0 +1,53 @@
+ 1: 1 1 CALL pred throw.main/2-0 (cc_multi) throw.m:10
+mdb> echo on
+Command echo enabled.
+mdb> register --quiet
+mdb> break p
+ 0: + stop interface pred throw.p/1-0 (cc_nondet)
+mdb> break q
+ 1: + stop interface pred throw.q/1-0 (semidet)
+mdb> continue
+ 2: 2 2 CALL pred throw.p/1-0 (cc_nondet) throw.m:20
+mdb> finish
+ 31: 2 2 EXCP pred throw.p/1-0 (cc_nondet)
+mdb> dd
+Call p(_)
+Throws "Too big"
+Expected? no
+a(3)
+Valid? yes
+Call b(3, _)
+Throws "Too big"
+Expected? yes
+Found unhandled exception:
+p(_)
+"Too big"
+Is this a bug? yes
+ 31: 2 2 EXCP pred throw.p/1-0 (cc_nondet)
+mdb> continue
+mdb: warning: reached label with no stack layout info
+This may result in some exception events
+being omitted from the trace.
+exception(univ_cons("Too big"))
+ 32: 6 2 CALL pred throw.q/1-0 (semidet) throw.m:48
+mdb> finish
+ 65: 6 2 EXCP pred throw.q/1-0 (semidet)
+mdb> dd
+Call q(_)
+Throws "Too big"
+Expected? no
+a2(3)
+Valid? yes
+Call b2(3, _)
+Throws "Too big"
+Expected? yes
+Found unhandled exception:
+q(_)
+"Too big"
+Is this a bug? yes
+ 65: 6 2 EXCP pred throw.q/1-0 (semidet)
+mdb> continue
+mdb: warning: reached label with no stack layout info
+This may result in some exception events
+being omitted from the trace.
+exception(univ_cons("Too big"))
cvs diff: Diffing tests/dppd
cvs diff: Diffing tests/general
cvs diff: Diffing tests/general/accumulator
cvs diff: Diffing tests/general/string_format
cvs diff: Diffing tests/general/structure_reuse
cvs diff: Diffing tests/grade_subdirs
cvs diff: Diffing tests/hard_coded
cvs diff: Diffing tests/hard_coded/exceptions
cvs diff: Diffing tests/hard_coded/purity
cvs diff: Diffing tests/hard_coded/sub-modules
cvs diff: Diffing tests/hard_coded/typeclasses
cvs diff: Diffing tests/invalid
cvs diff: Diffing tests/invalid/purity
cvs diff: Diffing tests/misc_tests
cvs diff: Diffing tests/mmc_make
cvs diff: Diffing tests/mmc_make/lib
cvs diff: Diffing tests/recompilation
cvs diff: Diffing tests/tabling
Index: tests/tabling/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/tabling/Mmakefile,v
retrieving revision 1.18
diff -u -b -r1.18 Mmakefile
--- tests/tabling/Mmakefile 30 Oct 2002 01:42:18 -0000 1.18
+++ tests/tabling/Mmakefile 12 Mar 2003 05:14:49 -0000
@@ -24,6 +24,7 @@
coup_no_commit \
coup_non_tabled_frame \
generator_in_commit \
+ mday \
repeat \
seq \
tc_loop \
cvs diff: Diffing tests/term
cvs diff: Diffing tests/valid
cvs diff: Diffing tests/warnings
cvs diff: Diffing tools
cvs diff: Diffing trace
Index: trace/mercury_trace.c
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace.c,v
retrieving revision 1.59
diff -u -b -r1.59 mercury_trace.c
--- trace/mercury_trace.c 6 Nov 2002 02:02:37 -0000 1.59
+++ trace/mercury_trace.c 12 Mar 2003 08:18:12 -0000
@@ -440,6 +440,12 @@
/* This also saves the regs in MR_fake_regs. */
MR_copy_regs_to_saved_regs(event_info.MR_max_mr_num, saved_regs);
+#if defined(MR_USE_MINIMAL_MODEL) && defined(MR_TABLE_DEBUG)
+ if (port == MR_PORT_CALL) {
+ MR_subgoal_debug_cur_proc = layout->MR_sll_entry;
+ }
+#endif
+
#ifdef MR_USE_EXTERNAL_DEBUGGER
if (MR_trace_handler == MR_TRACE_EXTERNAL) {
if (!interactive) {
@@ -1247,8 +1253,8 @@
trienode = (MR_TrieNode) MR_based_framevar(cur_maxfr,
proc_layout->MR_sle_maybe_call_table);
subgoal = trienode->MR_subgoal;
- if (subgoal->leader != NULL) {
- leader = subgoal->leader;
+ if (subgoal->MR_sg_leader != NULL) {
+ leader = subgoal->MR_sg_leader;
} else {
leader = subgoal;
}
@@ -1261,7 +1267,7 @@
record_ptrs[record_ptr_next].found_leader_generator = MR_FALSE;
record_ptr_next++;
- if (cur_maxfr == MR_gen_stack[cur_gen].generator_frame) {
+ if (cur_maxfr == MR_gen_stack[cur_gen].MR_generator_frame) {
for (i = 0; i < record_ptr_next; i++) {
if (record_ptrs[i].record_leader == subgoal) {
record_ptrs[i].found_leader_generator = MR_TRUE;
Index: trace/mercury_trace_internal.c
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_internal.c,v
retrieving revision 1.153
diff -u -b -r1.153 mercury_trace_internal.c
--- trace/mercury_trace_internal.c 11 Mar 2003 02:56:35 -0000 1.153
+++ trace/mercury_trace_internal.c 13 Mar 2003 06:31:32 -0000
@@ -533,9 +533,24 @@
MR_Trace_Cmd_Info *cmd, MR_Event_Info *event_info,
MR_Event_Details *event_details, MR_Code **jumpaddr);
+static MR_Next MR_trace_cmd_flag(char **words, int word_count,
+ MR_Trace_Cmd_Info *cmd, MR_Event_Info *event_info,
+ MR_Event_Details *event_details, MR_Code **jumpaddr);
+static MR_Next MR_trace_cmd_subgoal(char **words, int word_count,
+ MR_Trace_Cmd_Info *cmd, MR_Event_Info *event_info,
+ MR_Event_Details *event_details, MR_Code **jumpaddr);
+static MR_Next MR_trace_cmd_consumer(char **words, int word_count,
+ MR_Trace_Cmd_Info *cmd, MR_Event_Info *event_info,
+ MR_Event_Details *event_details, MR_Code **jumpaddr);
static MR_Next MR_trace_cmd_gen_stack(char **words, int word_count,
MR_Trace_Cmd_Info *cmd, MR_Event_Info *event_info,
MR_Event_Details *event_details, MR_Code **jumpaddr);
+static MR_Next MR_trace_cmd_cut_stack(char **words, int word_count,
+ MR_Trace_Cmd_Info *cmd, MR_Event_Info *event_info,
+ MR_Event_Details *event_details, MR_Code **jumpaddr);
+static MR_Next MR_trace_cmd_pneg_stack(char **words, int word_count,
+ MR_Trace_Cmd_Info *cmd, MR_Event_Info *event_info,
+ MR_Event_Details *event_details, MR_Code **jumpaddr);
static MR_Next MR_trace_cmd_nondet_stack(char **words, int word_count,
MR_Trace_Cmd_Info *cmd, MR_Event_Info *event_info,
@@ -682,10 +697,14 @@
/* Prints the given subgoal of the given procedure to MR_mdb_out. */
static void MR_trace_print_subgoal(const MR_Proc_Layout *proc,
MR_Subgoal *subgoal);
+static void MR_trace_print_subgoal_debug(const MR_Proc_Layout *proc,
+ MR_SubgoalDebug *subgoal_debug);
-/* Prints the given answer_block of the given procedure to MR_mdb_out. */
-static void MR_print_answerblock(const MR_Proc_Layout *proc,
- MR_Word *answer_block);
+/* Prints the given consumer of the given procedure to MR_mdb_out. */
+static void MR_trace_print_consumer(const MR_Proc_Layout *proc,
+ MR_Consumer *consumer);
+static void MR_trace_print_consumer_debug(const MR_Proc_Layout *proc,
+ MR_ConsumerDebug *consumer_debug);
static void MR_trace_set_level_and_report(int ancestor_level,
MR_bool detailed, MR_bool print_optionals);
@@ -722,6 +741,8 @@
static char *MR_trace_command_completer_next(const char *word,
size_t word_len, MR_Completer_Data *data);
+static MR_bool MR_saved_tabledebug;
+
MR_Code *
MR_trace_event_internal(MR_Trace_Cmd_Info *cmd, MR_bool interactive,
MR_Event_Info *event_info)
@@ -730,7 +751,6 @@
char *line;
MR_Next res;
MR_Event_Details event_details;
- MR_bool saved_tabledebug;
if (! interactive) {
return MR_trace_event_internal_report(cmd, event_info);
@@ -748,7 +768,7 @@
*/
MR_trace_enabled = MR_FALSE;
- saved_tabledebug = MR_tabledebug;
+ MR_saved_tabledebug = MR_tabledebug;
MR_tabledebug = MR_FALSE;
MR_saved_io_tabling_enabled = MR_io_tabling_enabled;
MR_io_tabling_enabled = MR_FALSE;
@@ -792,7 +812,7 @@
MR_scroll_next = 0;
MR_trace_enabled = MR_TRUE;
- MR_tabledebug = saved_tabledebug;
+ MR_tabledebug = MR_saved_tabledebug;
MR_io_tabling_enabled = MR_saved_io_tabling_enabled;
return jumpaddr;
}
@@ -3266,6 +3286,140 @@
}
static MR_Next
+MR_trace_cmd_flag(char **words, int word_count, MR_Trace_Cmd_Info *cmd,
+ MR_Event_Info *event_info, MR_Event_Details *event_details,
+ MR_Code **jumpaddr)
+{
+ const char *name;
+ MR_bool *flagptr;
+ int i;
+ MR_bool found;
+
+ if (word_count >= 2) {
+ name = words[1];
+ } else {
+ MR_trace_usage("developer", "flag");
+ return KEEP_INTERACTING;
+ }
+
+ found = MR_FALSE;
+ for (i = 0; i < MR_MAXFLAG; i++) {
+ if (MR_streq(MR_debug_flag_info[i].MR_debug_flag_name, name)) {
+ flagptr = &MR_debugflag[
+ MR_debug_flag_info[i].MR_debug_flag_index];
+
+ if (flagptr == &MR_tabledebug) {
+ /*
+ ** The true value of MR_tabledebug is stored
+ ** in MR_saved_tabledebug inside the call tree
+ ** of MR_trace_event.
+ */
+ flagptr = &MR_saved_tabledebug;
+ }
+
+ found = MR_TRUE;
+ break;
+ }
+ }
+
+ if (!found) {
+ fprintf(MR_mdb_out, "There is no flag named %s.\n", name);
+ return KEEP_INTERACTING;
+ }
+
+ if (word_count == 2) {
+ if (*flagptr) {
+ fprintf(MR_mdb_out, "Flag %s is set.\n", name);
+ } else {
+ fprintf(MR_mdb_out, "Flag %s is clear.\n", name);
+ }
+ } else if (word_count == 3) {
+ if (MR_streq(words[2], "on")) {
+ *flagptr = MR_TRUE;
+ fprintf(MR_mdb_out, "Flag %s is now set.\n", name);
+ } else if (MR_streq(words[2], "off")) {
+ *flagptr = MR_FALSE;
+ fprintf(MR_mdb_out, "Flag %s is now clear.\n", name);
+ } else {
+ MR_trace_usage("developer", "flag");
+ }
+ } else {
+ MR_trace_usage("developer", "flag");
+ }
+
+ return KEEP_INTERACTING;
+}
+
+static MR_Next
+MR_trace_cmd_subgoal(char **words, int word_count, MR_Trace_Cmd_Info *cmd,
+ MR_Event_Info *event_info, MR_Event_Details *event_details,
+ MR_Code **jumpaddr)
+{
+#ifdef MR_USE_MINIMAL_MODEL
+
+ MR_SubgoalDebug *subgoal_debug;
+ MR_Subgoal *subgoal;
+ int n;
+
+ if (word_count == 2 && MR_trace_is_natural_number(words[1], &n)) {
+ MR_trace_init_modules();
+
+ subgoal_debug = MR_lookup_subgoal_debug_num(n);
+ if (subgoal_debug == NULL) {
+ fprintf(MR_mdb_out, "no such subgoal\n");
+ } else {
+ MR_trace_print_subgoal_debug(NULL, subgoal_debug);
+ }
+ } else {
+ MR_trace_usage("developer", "subgoal");
+ }
+
+#else /* MR_USE_MINIMAL_MODEL */
+
+ fprintf(MR_mdb_out, "mdb: the `subgoal' command is available "
+ "only in minimal model tabling grades.\n");
+
+#endif /* MR_USE_MINIMAL_MODEL */
+
+ return KEEP_INTERACTING;
+}
+
+static MR_Next
+MR_trace_cmd_consumer(char **words, int word_count, MR_Trace_Cmd_Info *cmd,
+ MR_Event_Info *event_info, MR_Event_Details *event_details,
+ MR_Code **jumpaddr)
+{
+#ifdef MR_USE_MINIMAL_MODEL
+
+ MR_ConsumerDebug *consumer_debug;
+ MR_Consumer *consumer;
+ int n;
+
+ if (word_count == 2 && MR_trace_is_natural_number(words[1], &n)) {
+ MR_trace_init_modules();
+
+ consumer_debug = MR_lookup_consumer_debug_num(n);
+ if (consumer_debug == NULL) {
+ fprintf(MR_mdb_out, "no such consumer\n");
+ } else {
+ MR_trace_print_consumer_debug(NULL, consumer_debug);
+ }
+ } else {
+ MR_trace_usage("developer", "consumer");
+ }
+
+#else /* MR_USE_MINIMAL_MODEL */
+
+ fprintf(MR_mdb_out, "mdb: the `consumer' command is available "
+ "only in minimal model tabling grades.\n");
+
+#endif /* MR_USE_MINIMAL_MODEL */
+
+ return KEEP_INTERACTING;
+}
+
+
+static MR_Next
MR_trace_cmd_gen_stack(char **words, int word_count, MR_Trace_Cmd_Info *cmd,
MR_Event_Info *event_info, MR_Event_Details *event_details,
MR_Code **jumpaddr)
@@ -3295,6 +3449,64 @@
}
static MR_Next
+MR_trace_cmd_cut_stack(char **words, int word_count, MR_Trace_Cmd_Info *cmd,
+ MR_Event_Info *event_info, MR_Event_Details *event_details,
+ MR_Code **jumpaddr)
+{
+#ifdef MR_USE_MINIMAL_MODEL
+
+ if (word_count == 1) {
+ MR_bool saved_tabledebug;
+
+ MR_trace_init_modules();
+ saved_tabledebug = MR_tabledebug;
+ MR_tabledebug = MR_TRUE;
+ MR_print_cut_stack(MR_mdb_out);
+ MR_tabledebug = saved_tabledebug;
+ } else {
+ MR_trace_usage("developer", "cut_stack");
+ }
+
+#else /* MR_USE_MINIMAL_MODEL */
+
+ fprintf(MR_mdb_out, "mdb: the `cut_stack' command is available "
+ "only in minimal model grades.\n");
+
+#endif /* MR_USE_MINIMAL_MODEL */
+
+ return KEEP_INTERACTING;
+}
+
+static MR_Next
+MR_trace_cmd_pneg_stack(char **words, int word_count, MR_Trace_Cmd_Info *cmd,
+ MR_Event_Info *event_info, MR_Event_Details *event_details,
+ MR_Code **jumpaddr)
+{
+#ifdef MR_USE_MINIMAL_MODEL
+
+ if (word_count == 1) {
+ MR_bool saved_tabledebug;
+
+ MR_trace_init_modules();
+ saved_tabledebug = MR_tabledebug;
+ MR_tabledebug = MR_TRUE;
+ MR_print_pneg_stack(MR_mdb_out);
+ MR_tabledebug = saved_tabledebug;
+ } else {
+ MR_trace_usage("developer", "pneg_stack");
+ }
+
+#else /* MR_USE_MINIMAL_MODEL */
+
+ fprintf(MR_mdb_out, "mdb: the `pneg_stack' command is available "
+ "only in minimal model grades.\n");
+
+#endif /* MR_USE_MINIMAL_MODEL */
+
+ return KEEP_INTERACTING;
+}
+
+static MR_Next
MR_trace_cmd_nondet_stack(char **words, int word_count, MR_Trace_Cmd_Info *cmd,
MR_Event_Info *event_info, MR_Event_Details *event_details,
MR_Code **jumpaddr)
@@ -4294,7 +4506,7 @@
break;
default:
fprintf(MR_mdb_out, "succeeded <");
- MR_print_answerblock(proc,
+ MR_print_answerblock(MR_mdb_out, proc,
table->MR_answerblock);
fprintf(MR_mdb_out, ">\n");
break;
@@ -4319,56 +4531,43 @@
static void
MR_trace_print_subgoal(const MR_Proc_Layout *proc, MR_Subgoal *subgoal)
{
- fprintf(MR_mdb_out, "cannot print subgoals yet\n");
+#ifdef MR_USE_MINIMAL_MODEL
+ MR_print_subgoal(MR_mdb_out, proc, subgoal);
+#else
+ fprintf(MR_mdb_out, "minimal model tabling is not enabled\n");
+#endif
}
static void
-MR_print_answerblock(const MR_Proc_Layout *proc, MR_Word *answer_block)
+MR_trace_print_subgoal_debug(const MR_Proc_Layout *proc,
+ MR_SubgoalDebug *subgoal_debug)
{
- const MR_PseudoTypeInfo *ptis;
- MR_PseudoTypeInfo pti;
- MR_TypeCtorInfo tci;
- int num_inputs;
- int num_outputs;
- int i;
-
- num_inputs = proc->MR_sle_table_info.MR_table_gen->
- MR_table_gen_num_inputs;
- num_outputs = proc->MR_sle_table_info.MR_table_gen->
- MR_table_gen_num_outputs;
-
- ptis = proc->MR_sle_table_info.MR_table_gen->MR_table_gen_ptis;
- ptis += num_inputs;
-
- for (i = 0; i < num_outputs; i++) {
- if (i > 0) {
- fprintf(MR_mdb_out, ", ");
- }
+#ifdef MR_USE_MINIMAL_MODEL
+ MR_print_subgoal_debug(MR_mdb_out, proc, subgoal_debug);
+#else
+ fprintf(MR_mdb_out, "minimal model tabling is not enabled\n");
+#endif
+}
- pti = ptis[i];
- if (MR_PSEUDO_TYPEINFO_IS_VARIABLE(pti)) {
- fprintf(MR_mdb_out, "poly");
- continue;
- }
+static void
+MR_trace_print_consumer(const MR_Proc_Layout *proc, MR_Consumer *consumer)
+{
+#ifdef MR_USE_MINIMAL_MODEL
+ MR_print_consumer(MR_mdb_out, proc, consumer);
+#else
+ fprintf(MR_mdb_out, "minimal model tabling is not enabled\n");
+#endif
+}
- tci = MR_PSEUDO_TYPEINFO_GET_TYPE_CTOR_INFO(pti);
- if (tci == &MR_TYPE_CTOR_INFO_NAME(builtin, int, 0)) {
- fprintf(MR_mdb_out, "%ld", (long) answer_block[i]);
- } else if (tci == &MR_TYPE_CTOR_INFO_NAME(builtin, float, 0)) {
- fprintf(MR_mdb_out, "%f",
-#ifdef MR_HIGHLEVEL_CODE
- (double) MR_unbox_float(
- (MR_Box) answer_block[i]));
+static void
+MR_trace_print_consumer_debug(const MR_Proc_Layout *proc,
+ MR_ConsumerDebug *consumer_debug)
+{
+#ifdef MR_USE_MINIMAL_MODEL
+ MR_print_consumer_debug(MR_mdb_out, proc, consumer_debug);
#else
- (double) MR_word_to_float(answer_block[i]));
+ fprintf(MR_mdb_out, "minimal model tabling is not enabled\n");
#endif
- } else if (tci == &MR_TYPE_CTOR_INFO_NAME(builtin, string, 0)) {
- fprintf(MR_mdb_out, "\"%s\"",
- (char *) answer_block[i]);
- } else {
- fprintf(MR_mdb_out, "value of unsupported type");
- }
- }
}
static MR_Next
@@ -6218,7 +6417,17 @@
{ "exp", "clear_histogram", MR_trace_cmd_clear_histogram,
NULL, MR_trace_null_completer },
+ { "developer", "flag", MR_trace_cmd_flag,
+ NULL, MR_trace_null_completer },
+ { "developer", "subgoal", MR_trace_cmd_subgoal,
+ NULL, MR_trace_null_completer },
+ { "developer", "consumer", MR_trace_cmd_consumer,
+ NULL, MR_trace_null_completer },
{ "developer", "gen_stack", MR_trace_cmd_gen_stack,
+ NULL, MR_trace_null_completer },
+ { "developer", "cut_stack", MR_trace_cmd_cut_stack,
+ NULL, MR_trace_null_completer },
+ { "developer", "pneg_stack", MR_trace_cmd_pneg_stack,
NULL, MR_trace_null_completer },
{ "developer", "nondet_stack", MR_trace_cmd_nondet_stack,
MR_trace_stack_cmd_args, MR_trace_null_completer },
cvs diff: Diffing util
cvs diff: Diffing vim
cvs diff: Diffing vim/after
cvs diff: Diffing vim/ftplugin
cvs diff: Diffing vim/syntax
--------------------------------------------------------------------------
mercury-reviews mailing list
post: mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------
More information about the reviews
mailing list