sparc generating wrong code, regression from 1.1.1

Marc Espie Marc.Espie@liafa.jussieu.fr
Wed Jun 9 08:01:00 GMT 1999


I found this little gem in the netbsd mailing lists...

after browsing the egcs mailing-lists, it does look like the NetBSD guys
did not bother to send it yet to egcs-bugs.


I really wouldn't care if sparc-unknown-openbsd were not showing the exact
same problem, with egcs-19990517...


>Arrival-Date:   Tue Jun  8 02:50:01 1999
>Originator:     Juergen Hannken-Illjes
	
Compile the following program on a sparc and get the output:

................................................................
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

See that nextblock is incremented before the assignment.
This is very dangerous, this program is a stripped down example of
/sbin/dump. This error ruins all dumps created on this machine.

#define TP_BSIZE 64

char	buf[2*TP_BSIZE];
char	(*nextblock)[TP_BSIZE] = (char (*)[TP_BSIZE]) buf;

union u_test {
	char dummy[TP_BSIZE];
	struct s_test {
		int a;
		int b;
		int c;
	} s_test;
};

main(int argc, char **argv)
{
	int i;
	char dp[TP_BSIZE];

	for (i = 0; i < 2*TP_BSIZE; i++)
		buf[i] = '.';
	for (i = 0; i < TP_BSIZE; i++)
		dp[i] = 'a';

	*(union u_test *)(*(nextblock)++) = *(union u_test *)dp;

	for (i = 0; i < 2*TP_BSIZE; i++)
		printf("%c%s", buf[i], (i % 64) == 63 ? "\n" : "");
	exit(0);
}

-----------------

and they traced it to the following change from 1.1.1 to 1.1.2:

-----------------
--- expr.c	1998/11/14 04:27:16	1.3
+++ expr.c	1999/04/06 16:04:02	1.4
@@ -1619,4 +1619,8 @@
 {
   rtx retval = 0;
+#ifdef TARGET_MEM_FUNCTIONS
+  static tree fn;
+  tree call_expr, arg_list;
+#endif
 
   if (GET_MODE (x) != BLKmode)
@@ -1692,11 +1696,58 @@
 
 #ifdef TARGET_MEM_FUNCTIONS
- -      retval
- -	= emit_library_call_value (memcpy_libfunc, NULL_RTX, 0,
- -				   ptr_mode, 3, XEXP (x, 0), Pmode,
- -				   XEXP (y, 0), Pmode,
- -				   convert_to_mode (TYPE_MODE (sizetype), size,
- -						    TREE_UNSIGNED (sizetype)),
- -				   TYPE_MODE (sizetype));
+      /* It is incorrect to use the libcall calling conventions to call
+	 memcpy in this context.
+
+	 This could be a user call to memcpy and the user may wish to
+	 examine the return value from memcpy.
+
+	 For targets where libcalls and normal calls have different conventions
+	 for returning pointers, we could end up generating incorrect code. 
+
+	 So instead of using a libcall sequence we build up a suitable
+	 CALL_EXPR and expand the call in the normal fashion.  */
+      if (fn == NULL_TREE)
+	{
+	  tree fntype;
+
+	  /* This was copied from except.c, I don't know if all this is
+	     necessary in this context or not.  */
+	  fn = get_identifier ("memcpy");
+	  push_obstacks_nochange ();
+	  end_temporary_allocation ();
+	  fntype = build_pointer_type (void_type_node);
+	  fntype = build_function_type (fntype, NULL_TREE);
+	  fn = build_decl (FUNCTION_DECL, fn, fntype);
+	  DECL_EXTERNAL (fn) = 1;
+	  TREE_PUBLIC (fn) = 1;
+	  DECL_ARTIFICIAL (fn) = 1;
+	  make_decl_rtl (fn, NULL_PTR, 1);
+	  assemble_external (fn);
+	  pop_obstacks ();
+	}
+
+      /* We need to make an argument list for the function call. 
+
+	 memcpy has three arguments, the first two are void * addresses and
+	 the last is a size_t byte count for the copy.  */
+      arg_list
+	= build_tree_list (NULL_TREE,
+			    make_tree (build_pointer_type (void_type_node),
+				       XEXP (x, 0)));
+      TREE_CHAIN (arg_list)
+	= build_tree_list (NULL_TREE,
+			   make_tree (build_pointer_type (void_type_node),
+				      XEXP (y, 0)));
+      TREE_CHAIN (TREE_CHAIN (arg_list))
+	 = build_tree_list (NULL_TREE, make_tree (sizetype, size));
+      TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arg_list))) = NULL_TREE;
+
+      /* Now we have to build up the CALL_EXPR itself.  */
+      call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
+      call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+			 call_expr, arg_list, NULL_TREE);
+      TREE_SIDE_EFFECTS (call_expr) = 1;
+
+      retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
 #else
       emit_library_call (bcopy_libfunc, 0,
-- 
	Marc Espie		
|anime, sf, juggling, unicycle, acrobatics, comics...
|AmigaOS, OpenBSD, C++, perl, Icon, PostScript...
| `real programmers don't die, they just get out of beta'


More information about the Gcc-bugs mailing list