[m-dev.] for review: MLDS->C back-end: efficiency improvements

Fergus Henderson fjh at cs.mu.OZ.AU
Wed Jan 17 23:35:22 AEDT 2001


Estimated hours taken: 5

Some efficiency improvements to the MLDS->C back-end.
In particular, use GCC's __builtin_setjmp/__builtin_longjmp(),
and generate better code for switches whose default case is
unreachable.

These changes also help to ensure that the MLDS->C back-end should
generate exactly the same assembler code as the MLDS->GCC back-end,
which makes it easier to debug the latter (by using `diff' on the
generated `.s' files).

compiler/mlds_to_c.m:
	For unreachable default cases, use `MR_assert(0)' rather than
	`assert(0)'.  This improves efficiency, since `MR_assert' is
	disabled unless you compile with -DMR_LOWLEVEL_DEBUG.
	These checks were useful in debugging the MLDS back-end, but
	it's probably not worth keeping them enabled by default now.

	Put the default case first, so that if it is empty (as it will
	be if the default is unreachable and MR_assert() is not enabled),
	it gets merged with.

	Replace an obsolete comment about a problem with setjmp() and
	volatile with a comment explaining how that problem was fixed.

	Generate calls to MR_builtin_setjmp() and MR_builtin_longjmp()
	rather than to setjmp() and longjmp().

runtime/mercury.h:
	Define MR_builtin_setjmp() and MR_builtin_longjmp().
	These expand to __builtin_setjmp()/__builtin_longjmp() for GNU C
	and to the standard setjmp()/longjmp() otherwise.

compiler/ml_code_gen.m:
	Add some comments about __builtin_setjmp() and __builtin_longjmp().

Workspace: /home/hg/fjh/gcc-cvs/gcc/mercury
Index: compiler/ml_code_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/ml_code_gen.m,v
retrieving revision 1.72
diff -u -d -r1.72 ml_code_gen.m
--- compiler/ml_code_gen.m	2000/12/14 08:02:18	1.72
+++ compiler/ml_code_gen.m	2001/01/17 12:25:52
@@ -150,6 +150,7 @@
 % There's several different ways of handling commits:
 %	- using catch/throw
 %	- using setjmp/longjmp
+%	- using GCC's __builtin_setjmp/__builtin_longjmp
 %	- exiting nested functions via gotos to
 %	  their containing functions
 %
@@ -158,6 +159,17 @@
 % The comments below show the MLDS try_commit/do_commit version first,
 % but for clarity I've also included sample code using each of the three
 % different techniques.
+%
+% Note that if we're using GCC's __builtin_longjmp(),
+% then it is important that the call to __builtin_longjmp() be
+% put in its own function, to ensure that it is not in the same
+% function as the __builtin_setjmp().
+% The code generation schema below does that automatically.
+% We will need to be careful with MLDS optimizations to
+% ensure that we preserve that invariant, though.
+% (Alternatively, we could just call a function that
+% calls __builtin_longjmp() rather than calling it directly.
+% But that would be a little less efficient.)
 %
 % If those methods turn out to be too inefficient,
 % another alternative would be to change the generated
Index: compiler/mlds_to_c.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mlds_to_c.m,v
retrieving revision 1.76
diff -u -d -r1.76 mlds_to_c.m
--- compiler/mlds_to_c.m	2001/01/11 13:37:57	1.76
+++ compiler/mlds_to_c.m	2001/01/17 12:06:21
@@ -1952,9 +1952,11 @@
 	io__write_string("switch ("),
 	mlds_output_rval(Val),
 	io__write_string(") {\n"),
+	% we put the default case first, so that if it is unreachable,
+	% it will get merged in with the first case.
+	mlds_output_switch_default(Indent + 1, FuncInfo, Context, Default),
 	list__foldl(mlds_output_switch_case(Indent + 1, FuncInfo, Context),
 		Cases),
-	mlds_output_switch_default(Indent + 1, FuncInfo, Context, Default),
 	mlds_indent(Context, Indent),
 	io__write_string("}\n").
 
@@ -2086,8 +2088,12 @@
 		io__write_string("goto "),
 		mlds_output_rval(Ref)
 	;
-		% output "longjmp(<Ref>, 1)"
-		io__write_string("longjmp("),
+		% output "MR_builtin_longjmp(<Ref>, 1)".
+		% This is a macro that expands to either the standard longjmp()
+		% or the GNU C's __builtin_longjmp().
+		% Note that the second argument to GNU C's
+		% __builtin_longjmp() *must* be `1'.
+		io__write_string("MR_builtin_longjmp("),
 		mlds_output_rval(Ref),
 		io__write_string(", 1)")
 	),
@@ -2132,14 +2138,26 @@
 
 		% Output the following:
 		%
-		%	if (setjmp(<Ref>) == 0)
+		%	if (MR_builtin_setjmp(<Ref>) == 0)
 		%               <Stmt>
 		%       else
 		%               <Handler>
-
 		%
-		% XXX we need to declare the local variables as volatile,
-		% because of the setjmp()!
+		% MR_builtin_setjmp() expands to either the
+		% standard setjmp() or GNU C's __builtin_setjmp().
+		%
+		% Note that ISO C says that any non-volatile variables
+		% that are local to the function containing the setjmp()
+		% and which are modified between the setjmp() and the
+		% longjmp() become indeterminate after the longjmp(). 
+		% The MLDS code generator handles that by generating
+		% each commit in its own nested function, with the
+		% local variables remaining in the containing function.
+		% This ensures that none of the variables which get
+		% modified between the setjmp() and the longjmp() and
+		% which get referenced after the longjmp() are local
+		% variables in the function containing the setjmp(),
+		% so we don't need to mark them as volatile.
 		%
 
 		%
@@ -2155,7 +2173,7 @@
 		},
 
 		mlds_indent(Indent),
-		io__write_string("if (setjmp("),
+		io__write_string("if (MR_builtin_setjmp("),
 		mlds_output_lval(Ref),
 		io__write_string(") == 0)\n"),
 
@@ -2208,12 +2226,14 @@
 
 mlds_output_switch_default(Indent, _FuncInfo, Context, default_is_unreachable) -->
 	mlds_indent(Context, Indent),
-	io__write_string("default: /*NOTREACHED*/ assert(0);\n").
+	io__write_string("default: /*NOTREACHED*/ MR_assert(0);\n").
 mlds_output_switch_default(_Indent, _FuncInfo, _Context, default_do_nothing) --> [].
 mlds_output_switch_default(Indent, FuncInfo, Context, default_case(Statement)) -->
 	mlds_indent(Context, Indent),
 	io__write_string("default:\n"),
-	mlds_output_statement(Indent + 1, FuncInfo, Statement).
+	mlds_output_statement(Indent + 1, FuncInfo, Statement),
+	mlds_indent(Context, Indent + 1),
+	io__write_string("break;\n").
 
 %-----------------------------------------------------------------------------%
 
Index: runtime/mercury.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury.h,v
retrieving revision 1.32
diff -u -d -r1.32 mercury.h
--- runtime/mercury.h	2001/01/14 03:10:53	1.32
+++ runtime/mercury.h	2001/01/17 12:13:13
@@ -70,6 +70,22 @@
 typedef void MR_CALL (*MR_Cont) (void *); /* for --no-gcc-nested-functions */
 
 /*
+** The jmp_buf type used by MR_builtin_setjmp()
+** to save the stack context when implementing commits.
+*/
+#ifdef __GNUC__
+  /*
+  ** For GCC, we use `__builtin_setjmp' and `__builtin_longjmp'.
+  ** These are documented (in gcc/builtins.c in the GCC source code)
+  ** as taking as their parameter a pointer to an array of five words. 
+  */
+  typedef void *MR_builtin_jmp_buf[5];
+#else
+  /* Otherwise we use the standard jmp_buf type */
+  typedef jmp_buf MR_builtin_jmp_buf;
+#endif
+
+/*
 ** The types uses to represent the Mercury builtin types,
 ** MR_Char, MR_Float, MR_Integer, MR_String, and MR_ConstString,
 ** are defined in mercury_types.h and mercury_float.h.
@@ -277,6 +293,24 @@
 /*
 ** Macro / inline function definitions
 */
+
+/*
+** These macros expand to the either the standard setjmp()/longjmp()
+** or to the GNU __builtin_setjmp() and __builtin_longjmp().
+** The GNU versions are the same as the standard versions,
+** except that they are more efficient, and that they have two
+** restrictions:
+**	1.  The second argument to __builtin_longjmp() must always be `1'.
+**	2.  The call to __builtin_longjmp() must not be in the same
+**	    function as the call to __builtin_setjmp().
+*/
+#ifdef __GNUC__
+  #define MR_builtin_setjmp(buf)	__builtin_setjmp((buf))
+  #define MR_builtin_longjmp(buf, val)	__builtin_longjmp((buf), (val))
+#else
+  #define MR_builtin_setjmp(buf)	setjmp((buf))
+  #define MR_builtin_longjmp(buf, val)	longjmp((buf), (val))
+#endif
 
 /*
 ** MR_new_object():

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
                                    |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list