diff: new method of failure handling
Zoltan Somogyi
zs at cs.mu.OZ.AU
Mon Jul 20 16:21:35 AEST 1998
I have made the changes Fergus asked for, including his proposed changeover
mechanism, and Tom says the change is OK. I will commit the change when
it finishes bootchecking to prove that it works together with the other
changes made to the system in the last few weeks.
Once this change is reflected in the installed compiler, which may happen
at different times on different machines, you will need to (a) do a CVS
update of the runtime directory, and (b) recompile everything. You
won't need to specify specific flags in Mmake.params, nor will you need
to invoke boothcheck with -r.
The diff is in three parts. (1) the diff of the log message, (2) an absolute
diff of the runtime directory, and (3) a diff of the compiler directory that
is relative to my previous message. (The Log item starting "Emit MR_stackvar
and MR_framevar" is missing from this diff, since I made that change before
making the comparison-baseline copy, but that change is trivial.)
Zoltan.
--- Log.was Mon Jul 20 18:00:07 1998
+++ Log Mon Jul 20 18:16:27 1998
@@ -1,5 +1,5 @@
-Estimated hours taken: 240
+Estimated hours taken: 260
Implement new methods of handling failures and the end points of branched
control structures.
@@ -34,6 +34,10 @@
Reorder the declarations and definitions of access predicates
to conform to the new order of fields.
+ Reorder the declarations and definitions of the failure handling
+ submodule to better reflect the separation of higher-level and
+ lower-level predicates.
+
compiler/code_gen.m:
Replace code_gen__generate_{det,semi,non}_goal_2 with a single
predicate, since for most HLDS constructs the code here is the same
@@ -85,6 +89,12 @@
tell the runtime we are using the new failure handling scheme.
This effectively changes the grade of the compiled module.
+ Emit MR_stackvar and MR_framevar instead of detstackvar and framevar.
+ This is a step towards cleaning up the name-space, and a step towards
+ making both start numbering at 0. For the time being, the compiler
+ internally still starts counting framevars at 0; the code in llds_out.m
+ adds a +1 offset.
+
compiler/trace.m:
Change the way trace info is initialized to fit in with the new
requirements of code_info.m.
@@ -115,10 +125,16 @@
Turn off allow_hijacks if the gc method is accurate.
runtime/mercury_stacks.h:
- Provide alternative definitions for the nondet stack handling
- macros when we are using the nondet stack handling discipline.
+ Change the definitions for the nondet stack handling macros
+ to accommodate the new nondet stack handling discipline.
Define a new macro for creating temp nondet frames.
+ Define MR_based_stackvar and MR_based_framevar (both of which start
+ numbering slots at 1), and express other references, including
+ MR_stackvar and MR_framevar and backward compatible definitions of
+ detstackvar and framevar for hand-written C code, in terms of those
+ two.
+
runtime/mercury_stack_trace.[ch]:
Add a new function to print a dump of the fixed elements nondet stack,
for debugging my changes. (The dump does not include variable values.)
@@ -161,16 +177,6 @@
This change should be undone once all our workspaces have switched
over to the new failure handling method.
-
-tools/bootcheck:
- Always copy the runtime directory, since this is required when the
- stage1 and stage2 compilers have different grades, and differences
- in failure handling methods lead to differences in grades.
-
- This change should be undone once all our workspaces have switched
- over to the new nondet stack method. (Until then, any bootcheck
- in a directory that has not done a cvs update of this change will fail
- if it does not copy the runtime and define MR_DISABLE_REDOFR.)
tests/hard_coded/cut_test.{m,exp}:
A new test case to tickle the various ways of handling cuts in the
cvs diff: Diffing .
Index: mercury_engine.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_engine.c,v
retrieving revision 1.9
diff -u -u -r1.9 mercury_engine.c
--- mercury_engine.c 1998/06/18 04:30:42 1.9
+++ mercury_engine.c 1998/06/30 08:17:57
@@ -8,6 +8,7 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
+#define MR_STACK_TRACE_THIS_MODULE
#include "mercury_imp.h"
#include <stdio.h>
Index: mercury_grade.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_grade.h,v
retrieving revision 1.9
diff -u -u -r1.9 mercury_grade.h
--- mercury_grade.h 1998/06/09 02:07:58 1.9
+++ mercury_grade.h 1998/07/07 06:28:24
@@ -31,11 +31,11 @@
#define MR_PASTE2(p1,p2) MR_PASTE2_2(p1,p2)
#define MR_PASTE2_2(p1,p2) p1##p2
-/* paste 12 macros together */
-#define MR_PASTE12(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12) \
- MR_PASTE12_2(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12)
-#define MR_PASTE12_2(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12) \
- p1##p2##p3##p4##p5##p6##p7##p8##p9##p10##p11##p12
+/* paste 13 macros together */
+#define MR_PASTE13(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12) \
+ MR_PASTE13_2(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12)
+#define MR_PASTE13_2(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12) \
+ p0##p1##p2##p3##p4##p5##p6##p7##p8##p9##p10##p11##p12
/*
** Here we build up the MR_GRADE macro part at a time,
@@ -45,6 +45,12 @@
** changes to compiler/handle_options.m and scripts/mgnuc.in.
*/
+#ifdef MR_USE_REDOFR
+ #define MR_GRADE_PART_0 redofr_
+#else
+ #define MR_GRADE_PART_0
+#endif
+
#ifdef USE_ASM_LABELS
#define MR_GRADE_PART_1 asm_
#else
@@ -177,7 +183,8 @@
#endif
#endif
-#define MR_GRADE MR_PASTE12( \
+#define MR_GRADE MR_PASTE13( \
+ MR_GRADE_PART_0, \
MR_GRADE_PART_1, \
MR_GRADE_PART_2, \
MR_GRADE_PART_3, \
Index: mercury_imp.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_imp.h,v
retrieving revision 1.7
diff -u -u -r1.7 mercury_imp.h
--- mercury_imp.h 1998/06/09 02:08:02 1.7
+++ mercury_imp.h 1998/07/07 07:09:02
@@ -19,10 +19,13 @@
#ifndef MERCURY_IMP_H
#define MERCURY_IMP_H
+#define MR_USE_REDOFR
+
/*
** The #include of "mercury_conf.h" must come before the `#ifdef USE_DLLS',
** because mercury_conf.h defines the USE_DLLS macro.
*/
+
#include "mercury_conf.h"
/*
@@ -30,6 +33,7 @@
** global variables. This is necessary to support DLLs on Windows.
** Note: `libmer_dll.h' is automatically generated by `Makefile.DLLs'.
*/
+
#ifdef USE_DLLS
#include "libmer_dll.h"
#endif
Index: mercury_stack_trace.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_stack_trace.c,v
retrieving revision 1.12
diff -u -u -r1.12 mercury_stack_trace.c
--- mercury_stack_trace.c 1998/07/04 06:04:21 1.12
+++ mercury_stack_trace.c 1998/07/07 06:55:57
@@ -145,7 +145,6 @@
return label_layout;
}
-
static MR_Stack_Walk_Step_Result
MR_stack_walk_step(const MR_Stack_Layout_Entry *entry_layout,
const MR_Stack_Layout_Label **return_label_layout,
@@ -207,6 +206,40 @@
*return_label_layout = label->i_layout;
return STEP_OK;
+}
+
+void
+MR_dump_nondet_stack_from_layout(FILE *fp, Word *base_maxfr)
+{
+ /*
+ ** Change the >= below to > if you don't want the trace to include
+ ** the bottom frame created by mercury_wrapper.c (whose redoip/redofr
+ ** field can be hijacked by other code).
+ */
+
+ while (base_maxfr >= MR_nondet_stack_trace_bottom) {
+#ifdef MR_USE_REDOFR
+ if ((base_maxfr - bt_prevfr(base_maxfr)) < NONDET_FIXED_SIZE) {
+ fprintf(fp, "%p: temp\n", base_maxfr);
+ fprintf(fp, " redoip: ");
+ printlabel(bt_redoip(base_maxfr));
+ fprintf(fp, " redofr: %p\n", bt_redofr(base_maxfr));
+ } else
+#endif
+ {
+ fprintf(fp, "%p: ordinary\n", base_maxfr);
+ fprintf(fp, " redoip: ");
+ printlabel(bt_redoip(base_maxfr));
+#ifdef MR_USE_REDOFR
+ fprintf(fp, " redofr: %p\n", bt_redofr(base_maxfr));
+#endif
+ fprintf(fp, " succip: ");
+ printlabel(bt_succip(base_maxfr));
+ fprintf(fp, " succfr: %p\n", bt_succfr(base_maxfr));
+ }
+
+ base_maxfr = bt_prevfr(base_maxfr);
+ }
}
static const MR_Stack_Layout_Entry *prev_entry_layout;
Index: mercury_stack_trace.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_stack_trace.h,v
retrieving revision 1.7
diff -u -u -r1.7 mercury_stack_trace.h
--- mercury_stack_trace.h 1998/07/03 02:35:25 1.7
+++ mercury_stack_trace.h 1998/07/03 07:20:46
@@ -55,6 +55,31 @@
const MR_Stack_Layout_Entry *entry_layout,
Word *det_stack_pointer, Word *current_frame);
+/*
+** MR_dump_nondet_stack_from_layout:
+** This function dumps the control control slots of the nondet stack.
+** The output format is not meant to be intelligible to non-implementors.
+** The value of maxfr should be in *base_maxfr.
+*/
+
+extern void MR_dump_nondet_stack_from_layout(FILE *fp,
+ Word *base_maxfr);
+
+/*
+** MR_find_nth_ancestor:
+** Return the layout structure of the return label of the call
+** ancestor_level levels above the current call. Label_layout
+** tells us how to decipher the stack of the current call, while
+** *stack_trace_sp and *stack_trace_curfr tell us where it is.
+** On return, *stack_trace_sp and *stack_trace_curfr will be
+** set up to match the specified ancestor.
+**
+** If the required stack walk is not possible (e.g. because some
+** stack frames have no layout information, or because the stack
+** does not have the required depth), the return value will be NULL,
+** and problem will point to an error message.
+*/
+
extern const MR_Stack_Layout_Label *MR_find_nth_ancestor(
const MR_Stack_Layout_Label *label_layout,
int ancestor_level, Word **stack_trace_sp,
@@ -67,5 +92,14 @@
*/
Code *MR_stack_trace_bottom;
+
+/*
+** MR_nondet_stack_trace_bottom should be set to the address of the buffer
+** nondet stack frame created before calling main. Nondet stack dumps terminate
+** when they reach a stack frame whose redoip contains this address. Note that
+** the redoip and redofr slots of this frame may be hijacked.
+*/
+
+Word *MR_nondet_stack_trace_bottom;
#endif /* MERCURY_STACK_TRACE_H */
Index: mercury_stacks.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_stacks.h,v
retrieving revision 1.6
diff -u -u -r1.6 mercury_stacks.h
--- mercury_stacks.h 1998/06/18 06:08:09 1.6
+++ mercury_stacks.h 1998/07/10 07:28:26
@@ -4,7 +4,7 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
-/* mercury_stacks.h - definitions for manipulation the det and nondet stacks */
+/* mercury_stacks.h - definitions for manipulating the det and nondet stacks */
#ifndef MERCURY_STACKS_H
#define MERCURY_STACKS_H
@@ -17,9 +17,13 @@
/* DEFINITIONS FOR MANIPULATING THE DET STACK */
-#define detstackvar(n) (MR_sp[-n])
-#define based_detstackvar(base_sp, n) ((base_sp)[-n])
-#define saved_detstackvar(save_area, n) (MR_saved_sp(save_area)[-n])
+#define MR_based_stackvar(base_sp, n) ((base_sp)[-n])
+#define MR_stackvar(n) MR_based_stackvar(MR_sp, n)
+
+#define detstackvar(n) MR_based_stackvar(MR_sp, n)
+#define based_detstackvar(base_sp, n) MR_based_stackvar(base_sp, n)
+#define saved_detstackvar(save_area, n) \
+ MR_based_stackvar(MR_saved_sp(save_area), n)
#define incr_sp_push_msg(n, msg) \
( \
@@ -55,7 +59,7 @@
#define push(w) ( \
*MR_sp = (Word) (w), \
- debugpush(*sp, MR_sp), \
+ debugpush(*MR_sp, MR_sp), \
MR_sp = MR_sp + 1, \
detstack_overflow_check(), \
(void)0 \
@@ -70,47 +74,61 @@
/* DEFINITIONS FOR NONDET STACK FRAMES */
-#define REDOIP (-0) /* in this proc, set up at clause entry */
-#define PREVFR (-1) /* prev frame on stack, set up at call */
-#define SUCCIP (-2) /* in caller proc, set up at call */
-#define SUCCFR (-3) /* frame of caller proc, set up at call */
+#define PREVFR (-0) /* prev frame on stack, set up at call */
+#define REDOIP (-1) /* in this proc, set up at clause entry */
+#define REDOFR (-2) /* value for curfr on backtracking */
+#define SUCCIP (-3) /* in caller proc, set up at call */
+#define SUCCFR (-4) /* frame of caller proc, set up at call */
#ifdef MR_DEBUG_NONDET_STACK
- #define PREDNM (-4) /* for debugging, set up at call */
- #define bt_prednm(fr) LVALUE_CAST(const char *, ((Word *) fr)[PREDNM])
- #define NONDET_FIXED_SIZE_0 5 /* units: words */
+ #define PREDNM (-5) /* for debugging, set up at call */
+ #define MR_prednm(fr) LVALUE_CAST(const char *, ((Word *) fr)[PREDNM])
+ #define NONDET_FIXED_SIZE 6 /* units: words */
#else
- #define bt_prednm(fr) "unknown"
- #define NONDET_FIXED_SIZE_0 4 /* units: words */
+ #define MR_prednm(fr) "unknown"
+ #define NONDET_FIXED_SIZE 5 /* units: words */
#endif
-#define NONDET_FIXED_SIZE NONDET_FIXED_SIZE_0
-
-#define SAVEVAL (-NONDET_FIXED_SIZE)
- /* saved values start at this offset */
+#define NONDET_TEMP_SIZE 3 /* prevfr, redoip, redofr */
-#define bt_redoip(fr) LVALUE_CAST(Code *, ((Word *) (fr))[REDOIP])
-#define bt_prevfr(fr) LVALUE_CAST(Word *, ((Word *) (fr))[PREVFR])
-#define bt_succip(fr) LVALUE_CAST(Code *, ((Word *) (fr))[SUCCIP])
-#define bt_succfr(fr) LVALUE_CAST(Word *, ((Word *) (fr))[SUCCFR])
-#define bt_var(fr,n) (((Word *) (fr))[SAVEVAL-(n)])
-
-#define curprednm bt_prednm(MR_curfr)
-#define curredoip bt_redoip(MR_curfr)
-#define curprevfr bt_prevfr(MR_curfr)
-#define cursuccip bt_succip(MR_curfr)
-#define cursuccfr bt_succfr(MR_curfr)
-#define framevar(n) bt_var(MR_curfr,n)
+#define SAVEVAL (-NONDET_FIXED_SIZE)
+ /* saved values start at this offset */
-#define based_framevar(base_curfr, n) bt_var(base_curfr, n)
-#define saved_framevar(save_area, n) bt_var(MR_saved_curfr(save_area), n)
+#define MR_prevfr_slot(fr) LVALUE_CAST(Word *, ((Word *) (fr))[PREVFR])
+#define MR_redoip_slot(fr) LVALUE_CAST(Code *, ((Word *) (fr))[REDOIP])
+#define MR_redofr_slot(fr) LVALUE_CAST(Word *, ((Word *) (fr))[REDOFR])
+#define MR_succip_slot(fr) LVALUE_CAST(Code *, ((Word *) (fr))[SUCCIP])
+#define MR_succfr_slot(fr) LVALUE_CAST(Word *, ((Word *) (fr))[SUCCFR])
+#define MR_based_framevar(fr,n) (((Word *) (fr))[SAVEVAL+1-(n)])
+
+#define bt_prevfr(fr) MR_prevfr_slot(fr)
+#define bt_redoip(fr) MR_redoip_slot(fr)
+#define bt_redofr(fr) MR_redofr_slot(fr)
+#define bt_succip(fr) MR_succip_slot(fr)
+#define bt_succfr(fr) MR_succfr_slot(fr)
+#define bt_prednm(fr) MR_prednm_slot(fr)
+#define bt_var(fr,n) MR_based_framevar(fr,n+1)
+
+#define curprevfr bt_prevfr(MR_curfr)
+#define curredoip bt_redoip(MR_curfr)
+#define curredofr bt_redofr(MR_curfr)
+#define cursuccip bt_succip(MR_curfr)
+#define cursuccfr bt_succfr(MR_curfr)
+#define curprednm bt_prednm(MR_curfr)
+
+#define MR_framevar(n) MR_based_framevar(MR_curfr,n)
+#define framevar(n) MR_framevar(n+1)
+#define based_framevar(base_curfr, n) \
+ MR_based_framevar(base_curfr, n+1)
+#define saved_framevar(save_area, n) \
+ MR_based_framevar(MR_saved_curfr(save_area), n+1)
/* DEFINITIONS FOR MANIPULATING THE NONDET STACK */
-#ifdef MR_DEBUG_NONDET_STACK
-#define mkframe_save_prednm(prednm) (curprednm = prednm)
+#ifdef MR_DEBUG_NONDET_STACK
+ #define mkframe_save_prednm(prednm) (curprednm = prednm)
#else
-#define mkframe_save_prednm(prednm) /* nothing */
+ #define mkframe_save_prednm(prednm) /* nothing */
#endif
#define mkframe(prednm, numslots, redoip) \
@@ -126,6 +144,7 @@
curprevfr = prevfr; \
cursuccip = MR_succip; \
cursuccfr = succfr; \
+ curredofr = MR_curfr; \
mkframe_save_prednm(prednm); \
debugmkframe(); \
nondstack_overflow_check(); \
@@ -147,11 +166,26 @@
curprevfr = prevfr; \
cursuccip = MR_succip; \
cursuccfr = succfr; \
+ curredofr = MR_curfr; \
mkframe_save_prednm(prednm); \
debugmkframe(); \
nondstack_overflow_check(); \
} while (0)
+#define mktempframe(redoip) \
+ do { \
+ reg Word *prevfr; \
+ reg Word *succfr; \
+ \
+ prevfr = MR_maxfr; \
+ succfr = MR_curfr; \
+ MR_maxfr += NONDET_TEMP_SIZE; \
+ bt_prevfr(MR_maxfr) = prevfr; \
+ bt_redoip(MR_maxfr) = redoip; \
+ bt_redofr(MR_maxfr) = MR_curfr; \
+ nondstack_overflow_check(); \
+ } while (0)
+
#define modframe(redoip) \
do { \
curredoip = redoip; \
@@ -178,18 +212,20 @@
GOTO(bt_succip(childfr)); \
} while (0)
+
#define fail() do { \
debugfail(); \
- MR_maxfr = curprevfr; \
- MR_curfr = MR_maxfr; \
+ MR_maxfr = bt_prevfr(MR_maxfr); \
nondstack_underflow_check(); \
- GOTO(curredoip); \
+ MR_curfr = bt_redofr(MR_maxfr); \
+ GOTO(bt_redoip(MR_maxfr)); \
} while (0)
+
#define redo() do { \
debugredo(); \
- MR_curfr = MR_maxfr; \
- GOTO(curredoip); \
+ MR_curfr = bt_redofr(MR_maxfr); \
+ GOTO(bt_redoip(MR_maxfr)); \
} while (0)
#endif /* not MERCURY_STACKS_H */
Index: mercury_trace_internal.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_trace_internal.c,v
retrieving revision 1.7
diff -u -u -r1.7 mercury_trace_internal.c
--- mercury_trace_internal.c 1998/06/18 06:08:12 1.7
+++ mercury_trace_internal.c 1998/07/03 07:04:15
@@ -40,6 +40,8 @@
static MR_spy_point MR_spy_points[MR_MAX_SPY_POINTS];
static int MR_next_spy_point = 0;
+static bool MR_echo_commands = FALSE;
+
static MR_next MR_trace_debug_cmd(MR_trace_cmd_info *cmd,
const MR_Stack_Layout_Label *layout,
MR_trace_port port, int seqno, int depth,
@@ -126,6 +128,10 @@
(void) strcpy(line, "a\n");
}
+ if (MR_echo_commands) {
+ fputs(line, stdout);
+ }
+
/*
** Handle a possible number prefix on the first word on the line,
** separating it out into a word on its own.
@@ -312,11 +318,21 @@
} else {
printf("This command expects no argument.\n");
}
+ } else if (streq(words[0], "D")) {
+ if (word_count == 1) {
+ do_init_modules();
+ MR_dump_nondet_stack_from_layout(stdout,
+ MR_saved_maxfr(MR_saved_regs));
+ } else {
+ printf("This command expects no argument.\n");
+ }
} else if (streq(words[0], "X")) {
printf("sp = %p, curfr = %p, maxfr = %p\n",
MR_saved_sp(MR_saved_regs),
MR_saved_curfr(MR_saved_regs),
MR_saved_maxfr(MR_saved_regs));
+ } else if (streq(words[0], "toggle_echo")) {
+ MR_echo_commands = !MR_echo_commands;
} else if (streq(words[0], "b")) {
if (word_count != 3) {
printf("This command expects two arguments,\n");
Index: mercury_wrapper.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_wrapper.c,v
retrieving revision 1.16
diff -u -u -r1.16 mercury_wrapper.c
--- mercury_wrapper.c 1998/07/07 08:04:15 1.16
+++ mercury_wrapper.c 1998/07/08 05:36:36
@@ -27,6 +27,7 @@
** various cleanups that are needed to terminate cleanly.
*/
+#define MR_STACK_TRACE_THIS_MODULE
#include "mercury_imp.h"
#include <stdio.h>
@@ -857,11 +858,12 @@
push(MR_maxfr);
mkframe("interpreter", 1, LABEL(global_fail));
+ MR_nondet_stack_trace_bottom = MR_maxfr;
+ MR_stack_trace_bottom = LABEL(global_success);
+
if (program_entry_point == NULL) {
fatal_error("no program entry point supplied");
}
-
- MR_stack_trace_bottom = LABEL(global_success);
#ifdef PROFILE_TIME
if (MR_profiling) MR_prof_turn_on_time_profiling();
cvs diff: Diffing machdeps
diff -u JUL14/code_gen.m ./code_gen.m
--- JUL14/code_gen.m Tue Jul 14 11:38:23 1998
+++ ./code_gen.m Tue Jul 14 12:36:30 1998
@@ -156,17 +156,16 @@
% generated when generating prologs and is used in generating epilogs
% and when massaging the code generated for the procedure.
-:- type frame_info ---> frame(
- int, % Number of slots in frame.
+:- type frame_info
+ ---> frame(
+ int, % Number of slots in frame.
- maybe(int), % Slot number of succip
- % if succip is present
- % in a general slot.
+ maybe(int), % Slot number of succip if succip is
+ % present in a general slot.
- bool % Is this the frame of a
- % model_non proc defined
- % via pragma C code?
- ).
+ bool % Is this the frame of a model_non
+ % proc defined via pragma C code?
+ ).
%---------------------------------------------------------------------------%
diff -u JUL14/code_info.m ./code_info.m
--- JUL14/code_info.m Tue Jul 14 11:38:27 1998
+++ ./code_info.m Fri Jul 17 17:43:25 1998
@@ -115,6 +115,9 @@
:- pred code_info__set_instmap(instmap, code_info, code_info).
:- mode code_info__set_instmap(in, in, out) is det.
+ % The current value of the counter we use to give
+ % each "create" rval its unique cell number, for use
+ % in case the cell can be allocated statically.
:- pred code_info__get_cell_count(int, code_info, code_info).
:- mode code_info__get_cell_count(out, in, out) is det.
@@ -552,6 +555,7 @@
:- pred code_info__get_proc_model(code_model, code_info, code_info).
:- mode code_info__get_proc_model(out, in, out) is det.
+ % Get the list of the head variables of the current procedure.
:- pred code_info__get_headvars(list(var), code_info, code_info).
:- mode code_info__get_headvars(out, in, out) is det.
@@ -567,9 +571,6 @@
:- pred code_info__variable_to_string(var, string, code_info, code_info).
:- mode code_info__variable_to_string(in, out, in, out) is det.
-:- pred code_info__apply_instmap_delta(instmap_delta, code_info, code_info).
-:- mode code_info__apply_instmap_delta(in, in, out) is det.
-
% Create a code address which holds the address of the specified
% procedure.
% The fourth argument should be `no' if the the caller wants the
@@ -579,7 +580,15 @@
% --procs-per-c-function option and the current procedure id.
% Using an address that is only valid from within the current
% procedure may make jumps more efficient.
- % XXX
+ %
+ % If the procs_per_c_function option tells us to put more than one
+ % procedure into each C function, but not all procedures in the module
+ % are in one function, then we would like to be able to use the
+ % fast form of reference to a procedure for references not only from
+ % within the same procedure but also from other procedures within
+ % the same C function. However, at the time of code generation,
+ % we do not yet know which procedures will be put into the same
+ % C functions, and so we cannot do this.
:- pred code_info__make_entry_label(module_info, pred_id, proc_id, bool,
code_addr, code_info, code_info).
:- mode code_info__make_entry_label(in, in, in, in, out, in, out) is det.
@@ -592,6 +601,8 @@
:- pred code_info__get_next_cell_number(int, code_info, code_info).
:- mode code_info__get_next_cell_number(out, in, out) is det.
+ % Note that the succip slot is used, and thus cannot be
+ % optimized away.
:- pred code_info__succip_is_used(code_info, code_info).
:- mode code_info__succip_is_used(in, out) is det.
@@ -664,7 +675,9 @@
code_info__add_forward_live_vars(PostBirths),
code_info__make_vars_forward_live(PostBirths),
{ goal_info_get_instmap_delta(GoalInfo, InstMapDelta) },
- code_info__apply_instmap_delta(InstMapDelta).
+ code_info__get_instmap(InstMap0),
+ { instmap__apply_instmap_delta(InstMap0, InstMapDelta, InstMap) },
+ code_info__set_instmap(InstMap).
%---------------------------------------------------------------------------%
@@ -722,10 +735,7 @@
code_info__get_module_info(ModuleInfo),
code_info__get_pred_id(PredId),
code_info__get_proc_id(ProcId),
- { module_info_preds(ModuleInfo, Preds) },
- { map__lookup(Preds, PredId, PredInfo) },
- { pred_info_procedures(PredInfo, Procs) },
- { map__lookup(Procs, ProcId, ProcInfo) },
+ { module_info_pred_proc_info(ModuleInfo, PredId, ProcId, _, ProcInfo) },
{ proc_info_headvars(ProcInfo, HeadVars) }.
code_info__get_arginfo(ArgInfo) -->
@@ -757,11 +767,6 @@
code_info__get_varset(Varset),
{ varset__lookup_name(Varset, Var, Name) }.
-code_info__apply_instmap_delta(Delta) -->
- code_info__get_instmap(InstMap0),
- { instmap__apply_instmap_delta(InstMap0, Delta, InstMap) },
- code_info__set_instmap(InstMap).
-
%---------------------------------------------------------------------------%
code_info__make_entry_label(ModuleInfo, PredId, ProcId, Immed0, PredAddress) -->
@@ -945,17 +950,28 @@
% Submodule for the handling of failure continuations.
+ % The principles underlying this submodule of code_info.m are
+ % documented in the file compiler/notes/failure.html, which also
+ % defines terms such as "quarter hijack"). Some parts of the submodule
+ % also require knowledge of compiler/notes/allocation.html.
+
:- interface.
:- type resume_map.
:- type resume_point_info.
-:- type disj_hijack_info.
+ % `prepare_for_disj_hijack' should be called before entering
+ % a disjunction. It saves the values of any nondet stack slots
+ % the disjunction may hijack, and if necessary, sets the redofr
+ % slot of the top frame to point to this frame. The code at the
+ % start of the individual disjuncts will override the redoip slot.
+ %
+ % `undo_disj_hijack' should be called before entering the last
+ % disjunct of a disjunction. It undoes the effects of
+ % `prepare_for_disj_hijack'.
- % Save the values of any stack slots we may hijack,
- % and if necessary, set the redofr slot of the top frame
- % to point to this frame.
+:- type disj_hijack_info.
:- pred code_info__prepare_for_disj_hijack(code_model::in,
disj_hijack_info::out, code_tree::out,
@@ -964,6 +980,27 @@
:- pred code_info__undo_disj_hijack(disj_hijack_info::in,
code_tree::out, code_info::in, code_info::out) is det.
+ % `prepare_for_ite_hijack' should be called before entering
+ % an if-then-else. It saves the values of any nondet stack slots
+ % the if-then-else may hijack, and if necessary, sets the redofr
+ % slot of the top frame to point to this frame. Our caller
+ % will then override the redoip slot to point to the start of
+ % the else part before generating the code of the condition.
+ %
+ % However, some conditions will themselves hijack this redoip slot.
+ % If this is the case, `maybe_push_temp_frame' will protect against
+ % this by pushing a temporary nondet frame solely for the purpose
+ % of having its redoip and redofr slots hijacked by the condition.
+ % In any case it returns the lval that `ite_enter_then' should use to
+ % refer to the stack frame containing the redoip slot that was
+ % overridden for the if-then-else.
+ %
+ % `ite_enter_then', which should be called generating code for
+ % the condition, sets up the failure state of the code generator
+ % for generating the then-part, and returns the code sequences
+ % to be used at the starts of the then-part and the else-part
+ % to undo the effects of any hijacking.
+
:- type ite_hijack_info.
:- pred code_info__prepare_for_ite_hijack(code_model::in,
@@ -977,6 +1014,15 @@
:- pred code_info__ite_enter_then(ite_hijack_info::in, lval::in,
code_tree::out, code_tree::out, code_info::in, code_info::out) is det.
+ % `enter_simple_neg' and `leave_simple_neg' should be called before
+ % and after generating the code for a negated unification, in
+ % situations where failure is a direct branch. We handle this case
+ % specially, because it occurs frequently and should not require
+ % a flushing of the expression cache, whereas the general way of
+ % handling negations does require a flush. These two predicates
+ % handle all aspects of the negation except for the unification
+ % itself.
+
:- type simple_neg_info.
:- pred code_info__enter_simple_neg(set(var)::in, hlds_goal_info::in,
@@ -985,39 +1031,84 @@
:- pred code_info__leave_simple_neg(hlds_goal_info::in, simple_neg_info::in,
code_info::in, code_info::out) is det.
+ % `prepare_for_det_commit' and `generate_det_commit' should be
+ % called before and after generating the code for the multi goal
+ % being cut across. If the goal succeeds, the commit will cut
+ % any choice points generated in the goal.
+
+:- type det_commit_info.
+
+:- pred code_info__prepare_for_det_commit(det_commit_info::out,
+ code_tree::out, code_info::in, code_info::out) is det.
+
+:- pred code_info__generate_det_commit(det_commit_info::in,
+ code_tree::out, code_info::in, code_info::out) is det.
+
+ % `prepare_for_semi_commit' and `generate_semi_commit' should be
+ % called before and after generating the code for the nondet goal
+ % being cut across. If the goal succeeds, the commit will cut
+ % any choice points generated in the goal.
+
+:- type semi_commit_info.
+
+:- pred code_info__prepare_for_semi_commit(semi_commit_info::out,
+ code_tree::out, code_info::in, code_info::out) is det.
+
+:- pred code_info__generate_semi_commit(semi_commit_info::in,
+ code_tree::out, code_info::in, code_info::out) is det.
+
% Put the given resume point into effect, by pushing it on to
- % the resume point stack, and if necessary overriding the redoip
- % of the top frame.
+ % the resume point stack, and if necessary generating code to
+ % override the redoip of the top nondet stack frame.
:- pred code_info__effect_resume_point(resume_point_info::in, code_model::in,
code_tree::out, code_info::in, code_info::out) is det.
+ % Return the details of the resume point currently on top of the
+ % failure continuation stack.
+
:- pred code_info__top_resume_point(resume_point_info::out,
code_info::in, code_info::out) is det.
- % We have just left a disjunction; we don't know what address
- % the following code will need to backtrack to.
+ % Call this predicate to say "we have just left a disjunction;
+ % we don't know what address the following code will need to
+ % backtrack to".
:- pred code_info__set_resume_point_to_unknown(code_info::in, code_info::out)
is det.
- % We have just returned a model_non call; we don't know what address
- % the following code will need to backtrack to, and there may now
- % be nondet frames on top of ours that do not have their redofr slots
- % pointing to our frame.
+ % Call this predicate to say "we have just returned a model_non call;
+ % we don't know what address the following code will need to
+ % backtrack to, and there may now be nondet frames on top of ours
+ % that do not have their redofr slots pointing to our frame".
:- pred code_info__set_resume_point_and_frame_to_unknown(code_info::in,
code_info::out) is det.
+ % Generate code for executing a failure that is appropriate for the
+ % current failure environment.
+
:- pred code_info__generate_failure(code_tree::out,
code_info::in, code_info::out) is det.
+ % Generate code that checks if the given rval is false, and if yes,
+ % executes a failure that is appropriate for the current failure
+ % environment.
+
:- pred code_info__fail_if_rval_is_false(rval::in, code_tree::out,
code_info::in, code_info::out) is det.
+ % Checks whether the appropriate code for failure in the current
+ % failure environment is a direct branch.
+
:- pred code_info__failure_is_direct_branch(code_addr::out,
code_info::in, code_info::out) is semidet.
+ % Checks whether the current failure environment would allow
+ % a model_non call at this point to be turned into a tail call,
+ % provided of course that the return from the call is followed
+ % immediately by succeed().
+
:- pred code_info__may_use_nondet_tailcall(bool::out,
code_info::in, code_info::out) is det.
@@ -1043,45 +1134,56 @@
:- pred code_info__generate_resume_point(resume_point_info::in,
code_tree::out, code_info::in, code_info::out) is det.
+ % List the variables that need to be preserved for the given
+ % resume point.
+
:- pred code_info__resume_point_vars(resume_point_info::in, list(var)::out)
is det.
+ % See whether the given resume point includes a code address
+ % that presumes all the resume point variables to be in their
+ % stack slots. If yes, return that code address; otherwise,
+ % abort the compiler.
+
:- pred code_info__resume_point_stack_addr(resume_point_info::in,
code_addr::out) is det.
- % `generate_det_pre_commit' and `generate_det_commit' should be
- % called before and after generating the code for the multi goal
- % being cut across. If the goal succeeds, the `commit' will cut
- % any choice points generated in the goal.
-
-:- type det_commit_info.
-
-:- pred code_info__generate_det_pre_commit(det_commit_info::out,
- code_tree::out, code_info::in, code_info::out) is det.
-
-:- pred code_info__generate_det_commit(det_commit_info::in,
- code_tree::out, code_info::in, code_info::out) is det.
+%---------------------------------------------------------------------------%
- % `generate_semi_pre_commit' and `generate_semi_commit' should be
- % called before and after generating the code for the nondet goal
- % being cut across. If the goal succeeds, the `commit' will cut
- % any choice points generated in the goal.
+:- implementation.
-:- type semi_commit_info.
+ % The part of the code generator state that says how to handle
+ % failures; also called the failure continuation stack.
-:- pred code_info__generate_semi_pre_commit(semi_commit_info::out,
- code_tree::out, code_info::in, code_info::out) is det.
+:- type fail_info
+ ---> fail_info(
+ stack(resume_point_info),
+ resume_point_known,
+ curfr_vs_maxfr
+ ).
-:- pred code_info__generate_semi_commit(semi_commit_info::in,
- code_tree::out, code_info::in, code_info::out) is det.
+ % A resumption point has one or two labels associated with it.
+ % Backtracking can arrive at either label. The code following
+ % each label will assume that the variables needed at the resumption
+ % point are in the locations given by the resume_map associated with
+ % the given label and nowhere else. Any code that can cause
+ % backtracking to a label must make sure that those variables are
+ % in the positions expected by the label.
+ %
+ % The only time when a code_addr in a resume_point info is not a label
+ % is when the code_addr is do_fail, which indicates that the resumption
+ % point is not in (this invocation of) this procedure.
-%---------------------------------------------------------------------------%
+:- type resume_point_info
+ ---> orig_only(resume_map, code_addr)
+ ; stack_only(resume_map, code_addr)
+ ; orig_and_stack(resume_map, code_addr, resume_map, code_addr)
+ ; stack_and_orig(resume_map, code_addr, resume_map, code_addr).
-:- implementation.
+ % A resume map maps the variables that will be needed at a resumption
+ % point to the locations in which they will be.
-% The principles underlying this submodule of code_info.m are documented
-% in the file compiler/notes/failure.html. That file also defines terms
-% such as "quarter hijack".
+:- type resume_map == map(var, set(rval)).
:- type resume_point_known ---> resume_point_known
; resume_point_unknown.
@@ -1089,59 +1191,22 @@
:- type curfr_vs_maxfr ---> must_be_equal
; may_be_different.
-:- type resume_map == map(var, set(rval)).
-
-:- type resume_point_info
- ---> orig_only(resume_map, code_addr)
- ; stack_only(resume_map, code_addr)
- ; orig_and_stack(resume_map, code_addr, resume_map, code_addr)
- ; stack_and_orig(resume_map, code_addr, resume_map, code_addr).
-
-:- type fail_info
- ---> fail_info(
- stack(resume_point_info),
- resume_point_known,
- curfr_vs_maxfr
- ).
+%---------------------------------------------------------------------------%
:- type disj_hijack_info
---> disj_no_hijack
; disj_quarter_hijack
; disj_half_hijack(
- lval % the stack slot in which we saved
- % the value of the hijacked redoip
+ lval % The stack slot in which we saved
+ % the value of the hijacked redoip.
)
; disj_full_hijack(
- lval, % the stack slot in which we saved
- % the value of the hijacked redoip
- lval % the stack slot in which we saved
- % the value of the hijacked redofr
+ lval, % The stack slot in which we saved
+ % the value of the hijacked redoip.
+ lval % The stack slot in which we saved
+ % the value of the hijacked redofr.
).
-:- type ite_hijack_info
- ---> ite_no_hijack(
- resume_point_known
- )
- ; ite_quarter_hijack(
- resume_point_known
- )
- ; ite_half_hijack(
- resume_point_known,
- lval % the stack slot in which we saved
- % the value of the hijacked redoip
- )
- ; ite_full_hijack(
- resume_point_known,
- lval, % the stack slot in which we saved
- % the value of the hijacked redoip
- lval, % the stack slot in which we saved
- % the value of the hijacked redofr
- lval % the stack slot in which we saved
- % the value of maxfr
- ).
-
-:- type simple_neg_info == fail_info.
-
code_info__prepare_for_disj_hijack(CodeModel, HijackInfo, Code) -->
( { CodeModel = model_non } ->
code_info__get_fail_info(FailInfo),
@@ -1203,7 +1268,7 @@
{ require(unify(ResumeKnown, resume_point_unknown),
"resume point known in disj_half_hijack") },
{ require(unify(CurfrMaxfr, must_be_equal),
- "maxfr may be different from curfr in disj_half_hijack") },
+ "maxfr may differ from curfr in disj_half_hijack") },
{ Code = node([
assign(redoip(lval(curfr)), lval(RedoipSlot))
- "restore redoip for half disj hijack"
@@ -1213,7 +1278,7 @@
{ require(unify(ResumeKnown, resume_point_known),
"resume point not known in disj_quarter_hijack") },
{ require(unify(CurfrMaxfr, must_be_equal),
- "maxfr may be different from curfr in disj_quarter_hijack") },
+ "maxfr may differ from curfr in disj_quarter_hijack") },
{ stack__top_det(ResumePoints, ResumePoint) },
{ code_info__pick_stack_resume_point(ResumePoint,
_, StackLabel) },
@@ -1227,6 +1292,30 @@
{ Code = empty }
).
+%---------------------------------------------------------------------------%
+
+:- type ite_hijack_info
+ ---> ite_no_hijack(
+ resume_point_known
+ )
+ ; ite_quarter_hijack(
+ resume_point_known
+ )
+ ; ite_half_hijack(
+ resume_point_known,
+ lval % The stack slot in which we saved
+ % the value of the hijacked redoip.
+ )
+ ; ite_full_hijack(
+ resume_point_known,
+ lval, % The stack slot in which we saved
+ % the value of the hijacked redoip.
+ lval, % The stack slot in which we saved
+ % the value of the hijacked redofr.
+ lval % The stack slot in which we saved
+ % the value of maxfr.
+ ).
+
code_info__prepare_for_ite_hijack(EffCodeModel, HijackInfo, Code) -->
code_info__get_fail_info(FailInfo0),
{ FailInfo0 = fail_info(_ResumePoints, ResumeKnown, CurfrMaxfr) },
@@ -1363,6 +1452,10 @@
{ FailInfo = fail_info(ResumePoints, ResumeKnown, CurfrMaxfr) },
code_info__set_fail_info(FailInfo).
+%---------------------------------------------------------------------------%
+
+:- type simple_neg_info == fail_info.
+
code_info__enter_simple_neg(ResumeVars, GoalInfo, FailInfo0) -->
code_info__get_fail_info(FailInfo0),
% The only reason why we push a resume point at all
@@ -1399,6 +1492,226 @@
%---------------------------------------------------------------------------%
+:- type det_commit_info
+ ---> det_commit_info(
+ maybe(lval), % Location of saved maxfr.
+ maybe(pair(lval)) % Location of saved ticket
+ % counter and trail pointer.
+ ).
+
+code_info__prepare_for_det_commit(DetCommitInfo, Code) -->
+ code_info__get_fail_info(FailInfo0),
+ { FailInfo0 = fail_info(_, _, CurfrMaxfr) },
+ (
+ { CurfrMaxfr = may_be_different },
+ code_info__acquire_temp_slot(lval(maxfr), MaxfrSlot),
+ { SaveMaxfrCode = node([
+ assign(MaxfrSlot, lval(maxfr))
+ - "save the value of maxfr"
+ ]) },
+ { MaybeMaxfrSlot = yes(MaxfrSlot) }
+ ;
+ { CurfrMaxfr = must_be_equal },
+ { SaveMaxfrCode = empty },
+ { MaybeMaxfrSlot = no }
+ ),
+ code_info__maybe_save_trail_info(MaybeTrailSlots, SaveTrailCode),
+ { DetCommitInfo = det_commit_info(MaybeMaxfrSlot, MaybeTrailSlots) },
+ { Code = tree(SaveMaxfrCode, SaveTrailCode) }.
+
+code_info__generate_det_commit(DetCommitInfo, Code) -->
+ { DetCommitInfo = det_commit_info(MaybeMaxfrSlot, MaybeTrailSlots) },
+ (
+ { MaybeMaxfrSlot = yes(MaxfrSlot) },
+ { RestoreMaxfrCode = node([
+ assign(maxfr, lval(MaxfrSlot))
+ - "restore the value of maxfr - perform commit"
+ ]) },
+ code_info__release_temp_slot(MaxfrSlot)
+ ;
+ { MaybeMaxfrSlot = no },
+ { RestoreMaxfrCode = node([
+ assign(maxfr, lval(curfr))
+ - "restore the value of maxfr - perform commit"
+ ]) }
+ ),
+ code_info__maybe_restore_trail_info(MaybeTrailSlots,
+ CommitTrailCode, _),
+ { Code = tree(RestoreMaxfrCode, CommitTrailCode) }.
+
+%---------------------------------------------------------------------------%
+
+:- type semi_commit_info
+ ---> semi_commit_info(
+ fail_info, % Fail_info on entry.
+ resume_point_info,
+ commit_hijack_info,
+ maybe(pair(lval)) % Location of saved ticket
+ % counter and trail pointer.
+ ).
+
+:- type commit_hijack_info
+ ---> commit_quarter_hijack
+ ; commit_half_hijack(
+ lval % The stack slot in which we saved
+ % the value of the hijacked redoip.
+ )
+ ; commit_full_hijack(
+ lval, % The stack slot in which we saved
+ % the value of the hijacked redoip.
+ lval, % The stack slot in which we saved
+ % the value of the hijacked redofr.
+ lval % The stack slot in which we saved
+ % the value of maxfr.
+ ).
+
+code_info__prepare_for_semi_commit(SemiCommitInfo, Code) -->
+ code_info__get_fail_info(FailInfo0),
+ { FailInfo0 = fail_info(ResumePoints0, ResumeKnown, CurfrMaxfr) },
+ { stack__top_det(ResumePoints0, TopResumePoint) },
+ code_info__clone_resume_point(TopResumePoint, NewResumePoint),
+ { stack__push(ResumePoints0, NewResumePoint, ResumePoints) },
+ { FailInfo = fail_info(ResumePoints, ResumeKnown, CurfrMaxfr) },
+ code_info__set_fail_info(FailInfo),
+
+ { code_info__pick_stack_resume_point(NewResumePoint, _, StackLabel) },
+ { StackLabelConst = const(code_addr_const(StackLabel)) },
+ (
+ { CurfrMaxfr = may_be_different },
+ code_info__acquire_temp_slot(lval(redoip(lval(maxfr))),
+ RedoipSlot),
+ code_info__acquire_temp_slot(lval(redofr(lval(maxfr))),
+ RedofrSlot),
+ code_info__acquire_temp_slot(lval(maxfr),
+ MaxfrSlot),
+ { HijackInfo = commit_full_hijack(RedoipSlot, RedofrSlot,
+ MaxfrSlot) },
+ { HijackCode = node([
+ assign(RedoipSlot, lval(redoip(lval(maxfr))))
+ - "prepare for full commit hijack",
+ assign(RedofrSlot, lval(redofr(lval(maxfr))))
+ - "prepare for full commit hijack",
+ assign(MaxfrSlot, lval(maxfr))
+ - "prepare for full commit hijack",
+ assign(redofr(lval(maxfr)), lval(curfr))
+ - "hijack the redofr slot",
+ assign(redoip(lval(maxfr)), StackLabelConst)
+ - "hijack the redoip slot"
+ ]) }
+ ;
+ { CurfrMaxfr = must_be_equal },
+ (
+ { ResumeKnown = resume_point_unknown },
+ code_info__acquire_temp_slot(lval(redoip(lval(curfr))),
+ RedoipSlot),
+ { HijackInfo = commit_half_hijack(RedoipSlot) },
+ { HijackCode = node([
+ assign(RedoipSlot, lval(redoip(lval(curfr))))
+ - "prepare for half commit hijack",
+ assign(redoip(lval(curfr)), StackLabelConst)
+ - "hijack the redofr slot"
+ ]) }
+ ;
+ { ResumeKnown = resume_point_known },
+ { HijackInfo = commit_quarter_hijack },
+ { HijackCode = node([
+ assign(redoip(lval(curfr)), StackLabelConst)
+ - "hijack the redofr slot"
+ ]) }
+ )
+ ),
+ code_info__maybe_save_trail_info(MaybeTrailSlots, SaveTrailCode),
+ { SemiCommitInfo = semi_commit_info(FailInfo0, NewResumePoint,
+ HijackInfo, MaybeTrailSlots) },
+ { Code = tree(HijackCode, SaveTrailCode) }.
+
+code_info__generate_semi_commit(SemiCommitInfo, Code) -->
+ { SemiCommitInfo = semi_commit_info(FailInfo, ResumePoint,
+ HijackInfo, MaybeTrailSlots) },
+
+ code_info__set_fail_info(FailInfo),
+ (
+ { HijackInfo = commit_full_hijack(RedoipSlot, RedofrSlot,
+ MaxfrSlot) },
+ { SuccessUndoCode = node([
+ assign(maxfr, lval(MaxfrSlot))
+ - "restore maxfr for full commit hijack",
+ assign(redoip(lval(maxfr)), lval(RedoipSlot))
+ - "restore redoip for full commit hijack",
+ assign(redofr(lval(maxfr)), lval(RedofrSlot))
+ - "restore redofr for full commit hijack"
+ ]) },
+ { FailureUndoCode = node([
+ assign(redoip(lval(maxfr)), lval(RedoipSlot))
+ - "restore redoip for full commit hijack",
+ assign(redofr(lval(maxfr)), lval(RedofrSlot))
+ - "restore redofr for full commit hijack"
+ ]) }
+ ;
+ { HijackInfo = commit_half_hijack(RedoipSlot) },
+ { SuccessUndoCode = node([
+ assign(maxfr, lval(curfr))
+ - "restore maxfr for half commit hijack",
+ assign(redoip(lval(maxfr)), lval(RedoipSlot))
+ - "restore redoip for half commit hijack"
+ ]) },
+ { FailureUndoCode = node([
+ assign(redoip(lval(maxfr)), lval(RedoipSlot))
+ - "restore redoip for half commit hijack"
+ ]) }
+ ;
+ { HijackInfo = commit_quarter_hijack },
+ { FailInfo = fail_info(ResumePoints, _, _) },
+ { stack__top_det(ResumePoints, TopResumePoint) },
+ { code_info__pick_stack_resume_point(TopResumePoint,
+ _, StackLabel) },
+ { StackLabelConst = const(code_addr_const(StackLabel)) },
+ { SuccessUndoCode = node([
+ assign(maxfr, lval(curfr))
+ - "restore maxfr for quarter commit hijack",
+ assign(redoip(lval(maxfr)), StackLabelConst)
+ - "restore redoip for quarter commit hijack"
+ ]) },
+ { FailureUndoCode = node([
+ assign(redoip(lval(maxfr)), StackLabelConst)
+ - "restore redoip for quarter commit hijack"
+ ]) }
+ ),
+
+ code_info__remember_position(AfterCommit),
+ code_info__generate_resume_point(ResumePoint, ResumePointCode),
+ code_info__generate_failure(FailCode),
+ code_info__reset_to_position(AfterCommit),
+
+ code_info__maybe_restore_trail_info(MaybeTrailSlots,
+ CommitTrailCode, RestoreTrailCode),
+
+ code_info__get_next_label(SuccLabel),
+ { GotoSuccLabel = node([
+ goto(label(SuccLabel)) - "Jump to success continuation"
+ ]) },
+ { SuccLabelCode = node([
+ label(SuccLabel) - "Success continuation"
+ ]) },
+ { SuccessCode =
+ tree(SuccessUndoCode,
+ CommitTrailCode)
+ },
+ { FailureCode =
+ tree(ResumePointCode,
+ tree(FailureUndoCode,
+ tree(RestoreTrailCode,
+ FailCode)))
+ },
+ { Code =
+ tree(SuccessCode,
+ tree(GotoSuccLabel,
+ tree(FailureCode,
+ SuccLabelCode)))
+ }.
+
+%---------------------------------------------------------------------------%
+
code_info__effect_resume_point(ResumePoint, CodeModel, Code) -->
code_info__get_fail_info(FailInfo0),
{ FailInfo0 = fail_info(ResumePoints0, _ResumeKnown, CurfrMaxfr) },
@@ -1607,9 +1920,8 @@
map__select(Locations0, Keys, Locations),
map__to_assoc_list(Locations, List),
\+ (
- list__member(Thingy, List),
+ list__member(Var - Actual, List),
\+ (
- Thingy = Var - Actual,
map__search(Map, Var, Rvals),
set__subset(Rvals, Actual)
)
@@ -1858,7 +2170,7 @@
( CodeAddr = label(Label0) ->
Label = Label0
;
- error("code_info__generate_resume_setup: non-label!")
+ error("extract_label_from_code_addr: non-label!")
).
:- pred code_info__place_resume_vars(assoc_list(var, set(rval))::in,
@@ -1924,226 +2236,6 @@
%---------------------------------------------------------------------------%
-:- type det_commit_info
- ---> det_commit_info(
- maybe(lval), % location of saved maxfr
- maybe(pair(lval)) % location of saved ticket
- % counter and trail pointer
- ).
-
-code_info__generate_det_pre_commit(DetCommitInfo, Code) -->
- code_info__get_fail_info(FailInfo0),
- { FailInfo0 = fail_info(_, _, CurfrMaxfr) },
- (
- { CurfrMaxfr = may_be_different },
- code_info__acquire_temp_slot(lval(maxfr), MaxfrSlot),
- { SaveMaxfrCode = node([
- assign(MaxfrSlot, lval(maxfr))
- - "save the value of maxfr"
- ]) },
- { MaybeMaxfrSlot = yes(MaxfrSlot) }
- ;
- { CurfrMaxfr = must_be_equal },
- { SaveMaxfrCode = empty },
- { MaybeMaxfrSlot = no }
- ),
- code_info__maybe_save_trail_info(MaybeTrailSlots, SaveTrailCode),
- { DetCommitInfo = det_commit_info(MaybeMaxfrSlot, MaybeTrailSlots) },
- { Code = tree(SaveMaxfrCode, SaveTrailCode) }.
-
-code_info__generate_det_commit(DetCommitInfo, Code) -->
- { DetCommitInfo = det_commit_info(MaybeMaxfrSlot, MaybeTrailSlots) },
- (
- { MaybeMaxfrSlot = yes(MaxfrSlot) },
- { RestoreMaxfrCode = node([
- assign(maxfr, lval(MaxfrSlot))
- - "restore the value of maxfr - perform commit"
- ]) },
- code_info__release_temp_slot(MaxfrSlot)
- ;
- { MaybeMaxfrSlot = no },
- { RestoreMaxfrCode = node([
- assign(maxfr, lval(curfr))
- - "restore the value of maxfr - perform commit"
- ]) }
- ),
- code_info__maybe_restore_trail_info(MaybeTrailSlots,
- CommitTrailCode, _),
- { Code = tree(RestoreMaxfrCode, CommitTrailCode) }.
-
-%---------------------------------------------------------------------------%
-
-:- type semi_commit_info
- ---> semi_commit_info(
- fail_info, % fail_info on entry
- resume_point_info,
- commit_hijack_info,
- maybe(pair(lval)) % location of saved ticket
- % counter and trail pointer
- ).
-
-:- type commit_hijack_info
- ---> commit_quarter_hijack
- ; commit_half_hijack(
- lval % the stack slot in which we saved
- % the value of the hijacked redoip
- )
- ; commit_full_hijack(
- lval, % the stack slot in which we saved
- % the value of the hijacked redoip
- lval, % the stack slot in which we saved
- % the value of the hijacked redofr
- lval % the stack slot in which we saved
- % the value of maxfr
- ).
-
-code_info__generate_semi_pre_commit(SemiCommitInfo, Code) -->
- code_info__get_fail_info(FailInfo0),
- { FailInfo0 = fail_info(ResumePoints0, ResumeKnown, CurfrMaxfr) },
- { stack__top_det(ResumePoints0, TopResumePoint) },
- code_info__clone_resume_point(TopResumePoint, NewResumePoint),
- { stack__push(ResumePoints0, NewResumePoint, ResumePoints) },
- { FailInfo = fail_info(ResumePoints, ResumeKnown, CurfrMaxfr) },
- code_info__set_fail_info(FailInfo),
-
- { code_info__pick_stack_resume_point(NewResumePoint, _, StackLabel) },
- { StackLabelConst = const(code_addr_const(StackLabel)) },
- (
- { CurfrMaxfr = may_be_different },
- code_info__acquire_temp_slot(lval(redoip(lval(maxfr))),
- RedoipSlot),
- code_info__acquire_temp_slot(lval(redofr(lval(maxfr))),
- RedofrSlot),
- code_info__acquire_temp_slot(lval(maxfr),
- MaxfrSlot),
- { HijackInfo = commit_full_hijack(RedoipSlot, RedofrSlot,
- MaxfrSlot) },
- { HijackCode = node([
- assign(RedoipSlot, lval(redoip(lval(maxfr))))
- - "prepare for full commit hijack",
- assign(RedofrSlot, lval(redofr(lval(maxfr))))
- - "prepare for full commit hijack",
- assign(MaxfrSlot, lval(maxfr))
- - "prepare for full commit hijack",
- assign(redofr(lval(maxfr)), lval(curfr))
- - "hijack the redofr slot",
- assign(redoip(lval(maxfr)), StackLabelConst)
- - "hijack the redoip slot"
- ]) }
- ;
- { CurfrMaxfr = must_be_equal },
- (
- { ResumeKnown = resume_point_unknown },
- code_info__acquire_temp_slot(lval(redoip(lval(curfr))),
- RedoipSlot),
- { HijackInfo = commit_half_hijack(RedoipSlot) },
- { HijackCode = node([
- assign(RedoipSlot, lval(redoip(lval(curfr))))
- - "prepare for half commit hijack",
- assign(redoip(lval(curfr)), StackLabelConst)
- - "hijack the redofr slot"
- ]) }
- ;
- { ResumeKnown = resume_point_known },
- { HijackInfo = commit_quarter_hijack },
- { HijackCode = node([
- assign(redoip(lval(curfr)), StackLabelConst)
- - "hijack the redofr slot"
- ]) }
- )
- ),
- code_info__maybe_save_trail_info(MaybeTrailSlots, SaveTrailCode),
- { SemiCommitInfo = semi_commit_info(FailInfo0, NewResumePoint,
- HijackInfo, MaybeTrailSlots) },
- { Code = tree(HijackCode, SaveTrailCode) }.
-
-code_info__generate_semi_commit(SemiCommitInfo, Code) -->
- { SemiCommitInfo = semi_commit_info(FailInfo, ResumePoint,
- HijackInfo, MaybeTrailSlots) },
-
- code_info__set_fail_info(FailInfo),
- (
- { HijackInfo = commit_full_hijack(RedoipSlot, RedofrSlot,
- MaxfrSlot) },
- { SuccessUndoCode = node([
- assign(maxfr, lval(MaxfrSlot))
- - "restore maxfr for full commit hijack",
- assign(redoip(lval(maxfr)), lval(RedoipSlot))
- - "restore redoip for full commit hijack",
- assign(redofr(lval(maxfr)), lval(RedofrSlot))
- - "restore redofr for full commit hijack"
- ]) },
- { FailureUndoCode = node([
- assign(redoip(lval(maxfr)), lval(RedoipSlot))
- - "restore redoip for full commit hijack",
- assign(redofr(lval(maxfr)), lval(RedofrSlot))
- - "restore redofr for full commit hijack"
- ]) }
- ;
- { HijackInfo = commit_half_hijack(RedoipSlot) },
- { SuccessUndoCode = node([
- assign(maxfr, lval(curfr))
- - "restore maxfr for half commit hijack",
- assign(redoip(lval(maxfr)), lval(RedoipSlot))
- - "restore redoip for half commit hijack"
- ]) },
- { FailureUndoCode = node([
- assign(redoip(lval(maxfr)), lval(RedoipSlot))
- - "restore redoip for half commit hijack"
- ]) }
- ;
- { HijackInfo = commit_quarter_hijack },
- { FailInfo = fail_info(ResumePoints, _, _) },
- { stack__top_det(ResumePoints, TopResumePoint) },
- { code_info__pick_stack_resume_point(TopResumePoint,
- _, StackLabel) },
- { StackLabelConst = const(code_addr_const(StackLabel)) },
- { SuccessUndoCode = node([
- assign(maxfr, lval(curfr))
- - "restore maxfr for quarter commit hijack",
- assign(redoip(lval(maxfr)), StackLabelConst)
- - "restore redoip for quarter commit hijack"
- ]) },
- { FailureUndoCode = node([
- assign(redoip(lval(maxfr)), StackLabelConst)
- - "restore redoip for quarter commit hijack"
- ]) }
- ),
-
- code_info__remember_position(AfterCommit),
- code_info__generate_resume_point(ResumePoint, ResumePointCode),
- code_info__generate_failure(FailCode),
- code_info__reset_to_position(AfterCommit),
-
- code_info__maybe_restore_trail_info(MaybeTrailSlots,
- CommitTrailCode, RestoreTrailCode),
-
- code_info__get_next_label(SuccLabel),
- { GotoSuccLabel = node([
- goto(label(SuccLabel)) - "Jump to success continuation"
- ]) },
- { SuccLabelCode = node([
- label(SuccLabel) - "Success continuation"
- ]) },
- { SuccessCode =
- tree(SuccessUndoCode,
- CommitTrailCode)
- },
- { FailureCode =
- tree(ResumePointCode,
- tree(FailureUndoCode,
- tree(RestoreTrailCode,
- FailCode)))
- },
- { Code =
- tree(SuccessCode,
- tree(GotoSuccLabel,
- tree(FailureCode,
- SuccLabelCode)))
- }.
-
-%---------------------------------------------------------------------------%
-
:- pred code_info__maybe_save_trail_info(maybe(pair(lval))::out,
code_tree::out, code_info::in, code_info::out) is det.
@@ -2229,6 +2321,9 @@
% Submodule to deal with liveness issues.
+ % The principles underlying this submodule of code_info.m are
+ % documented in the file compiler/notes/allocation.html.
+
:- interface.
:- pred code_info__get_known_variables(list(var), code_info, code_info).
@@ -2785,7 +2880,8 @@
code_info__setup_call(Rest, Direction, Code)
).
- % XXX We could use the sanity checking mechanism...
+ % As a sanity check, we could test whether any known variable
+ % has its only value in a reguster, but we don't.
code_info__clear_all_registers -->
code_info__get_exprn_info(Exprn0),
{ code_exprn__clobber_regs([], Exprn0, Exprn) },
@@ -2962,33 +3058,32 @@
% Submodule for managing stack slots.
- % The det stack frame is organized as follows.
+ % Det stack frames are organized as follows.
%
% ... unused ...
% sp ---> <first unused slot>
% <space for local var 1>
% ... local vars ...
% <space for local var n>
- % <space for temporary reg save 1>
- % ... temporary reg saves ...
- % <space for temporary reg save n>
- % <space for succip>
+ % <space for temporary 1>
+ % ... temporaries ...
+ % <space for temporary n>
+ % <space for saved succip, if needed>
%
% The stack pointer points to the first free location at the
% top of the stack.
%
- % `code_info__num_stackslots' counts the number of slots reserved
- % for saving local variables. XXX
- %
- % `code_info__max_push_count' counts the number of slots reserved
- % for saving and restoring registers (hp, redoip, etc.)
- %
- % `code_info__succip_used' determines whether we need a slot to
+ % `code_info__succip_is_used' determines whether we need a slot to
% hold the succip.
%
- % The variable part of the nondet stack is organized in the same way
- % as the det stack (but the nondet stack also contains several other
- % fixed fields.)
+ % Nondet stack frames also have the local variables above the
+ % temporaries, but contain several fixed frames on top, and the
+ % saved succip is stored in one of these.
+ %
+ % For both kinds of stack frames, the slots holding variables
+ % are allocated during the live_vars pass, while the slots holding
+ % temporaries are acquired (and if possible, released) on demand
+ % during code generation.
:- interface.
@@ -3002,20 +3097,24 @@
; lval(lval).
% Returns the total stackslot count, but not including space for
- % succip.
+ % succip. This total can change in the future if this call is
+ % followed by further allocations of temp slots.
:- pred code_info__get_total_stackslot_count(int, code_info, code_info).
:- mode code_info__get_total_stackslot_count(out, in, out) is det.
-:- pred code_info__get_trace_slot(lval, code_info, code_info).
-:- mode code_info__get_trace_slot(out, in, out) is det.
-
+ % Acquire a stack slot for storing a temporary. The slot_contents
+ % description is for accurate gc.
:- pred code_info__acquire_temp_slot(slot_contents, lval,
code_info, code_info).
:- mode code_info__acquire_temp_slot(in, out, in, out) is det.
+ % Release a stack slot acquired earlier for a temporary value.
:- pred code_info__release_temp_slot(lval, code_info, code_info).
:- mode code_info__release_temp_slot(in, in, out) is det.
+ % Return the lval of the stack slot in which the given variable
+ % is stored. Aborts if the variable does not have a stack slot
+ % an assigned to it.
:- pred code_info__get_variable_slot(var, lval, code_info, code_info).
:- mode code_info__get_variable_slot(in, out, in, out) is det.
@@ -3024,18 +3123,6 @@
:- implementation.
-:- pred code_info__stack_variable(int, lval, code_info, code_info).
-:- mode code_info__stack_variable(in, out, in, out) is det.
-
-:- pred code_info__stack_variable_reference(int, rval, code_info, code_info).
-:- mode code_info__stack_variable_reference(in, out, in, out) is det.
-
-:- pred code_info__max_var_slot(stack_slots, int).
-:- mode code_info__max_var_slot(in, out) is det.
-
-code_info__get_trace_slot(StackVar) -->
- code_info__acquire_temp_slot(trace_data, StackVar).
-
code_info__acquire_temp_slot(Item, StackVar) -->
code_info__get_avail_temp_slots(AvailSlots0),
( { set__remove_least(AvailSlots0, StackVarPrime, AvailSlots) } ->
@@ -3077,6 +3164,14 @@
{ error(Str) }
).
+code_info__get_total_stackslot_count(NumSlots) -->
+ code_info__get_var_slot_count(SlotsForVars),
+ code_info__get_max_temp_slot_count(SlotsForTemps),
+ { NumSlots is SlotsForVars + SlotsForTemps }.
+
+:- pred code_info__max_var_slot(stack_slots, int).
+:- mode code_info__max_var_slot(in, out) is det.
+
code_info__max_var_slot(StackSlots, SlotCount) :-
map__values(StackSlots, StackSlotList),
code_info__max_var_slot_2(StackSlotList, 0, SlotCount).
@@ -3095,10 +3190,8 @@
),
code_info__max_var_slot_2(Ls, Max1, Max).
-code_info__get_total_stackslot_count(NumSlots) -->
- code_info__get_var_slot_count(SlotsForVars),
- code_info__get_max_temp_slot_count(SlotsForTemps),
- { NumSlots is SlotsForVars + SlotsForTemps }.
+:- pred code_info__stack_variable(int, lval, code_info, code_info).
+:- mode code_info__stack_variable(in, out, in, out) is det.
code_info__stack_variable(Num, Lval) -->
code_info__get_proc_model(CodeModel),
@@ -3108,6 +3201,9 @@
;
{ Lval = stackvar(Num) } % stackvars start at one
).
+
+:- pred code_info__stack_variable_reference(int, rval, code_info, code_info).
+:- mode code_info__stack_variable_reference(in, out, in, out) is det.
code_info__stack_variable_reference(Num, mem_addr(Ref)) -->
code_info__get_proc_model(CodeModel),
diff -u JUL14/commit_gen.m ./commit_gen.m
--- JUL14/commit_gen.m Tue Jul 14 11:38:28 1998
+++ ./commit_gen.m Fri Jul 17 17:51:20 1998
@@ -39,7 +39,7 @@
{ error("semidet model in det context") }
;
{ InnerCodeModel = model_non },
- code_info__generate_det_pre_commit(CommitInfo,
+ code_info__prepare_for_det_commit(CommitInfo,
PreCommit),
code_gen__generate_goal(InnerCodeModel, Goal, GoalCode),
code_info__generate_det_commit(CommitInfo, Commit),
@@ -55,7 +55,7 @@
code_gen__generate_goal(InnerCodeModel, Goal, Code)
;
{ InnerCodeModel = model_non },
- code_info__generate_semi_pre_commit(CommitInfo,
+ code_info__prepare_for_semi_commit(CommitInfo,
PreCommit),
code_gen__generate_goal(InnerCodeModel, Goal, GoalCode),
code_info__generate_semi_commit(CommitInfo, Commit),
diff -u JUL14/options.m ./options.m
--- JUL14/options.m Tue Jul 14 11:39:36 1998
+++ ./options.m Tue Jul 14 12:09:04 1998
@@ -159,7 +159,7 @@
% procedure identification.
; procid_stack_layout
% Stack layout information required to do
- % tracing.
+ % execution tracing.
; trace_stack_layout
% Use an alternate calculation of liveness
% where typeinfos are live for any live data
diff -u JUL14/trace.m ./trace.m
--- JUL14/trace.m Tue Jul 14 11:40:01 1998
+++ ./trace.m Tue Jul 14 16:11:35 1998
@@ -165,12 +165,12 @@
).
trace__setup(TraceLevel, TraceInfo) -->
- code_info__get_trace_slot(CallNumSlot),
- code_info__get_trace_slot(CallDepthSlot),
+ code_info__acquire_temp_slot(trace_data, CallNumSlot),
+ code_info__acquire_temp_slot(trace_data, CallDepthSlot),
( { trace_level_trace_ports(TraceLevel, yes) } ->
{ TraceType = full_trace }
;
- code_info__get_trace_slot(CallFromFullSlot),
+ code_info__acquire_temp_slot(trace_data, CallFromFullSlot),
{ TraceType = interface_trace(CallFromFullSlot) }
),
{ TraceInfo = trace_info(CallNumSlot, CallDepthSlot, TraceType) }.
More information about the developers
mailing list