Subject: bin/7735: Compiler generates wrong code
To: None <gnats-bugs@gnats.netbsd.org>
From: Juergen Hannken-Illjes <hannken@eis.cs.tu-bs.de>
List: netbsd-bugs
Date: 06/08/1999 02:51:12
>Number: 7735
>Category: bin
>Synopsis: Compiler generates wrong code
>Confidential: no
>Severity: critical
>Priority: high
>Responsible: bin-bug-people (Utility Bug People)
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Tue Jun 8 02:50:01 1999
>Last-Modified:
>Originator: Juergen Hannken-Illjes
>Organization:
>Release: <NetBSD-current source date>-current as of Fri Jun 4
>Environment:
System: NetBSD toaster 1.4C NetBSD 1.4C (CUSTOM) #20: Fri Jun 4 11:39:25 MEST 1999 hannken@toaster:/usr/obj/kern.sparc/CUSTOM sparc
>Description:
Complex post increment / mem copy gets wrong order. See next section.
>How-To-Repeat:
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);
}
>Fix:
Backing out the following change from egcs-1.1.1 -> egcs-1.1.2 cures the problem:
--- 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,
>Audit-Trail:
>Unformatted: