[PATCH] Fix PR c/3711

Jakub Jelinek jakub@redhat.com
Thu Mar 7 13:25:00 GMT 2002


Hi!

This is a regression from 2.95.x. Up to 3.0.x the compiler wouldn't
actually ICE on it, but it wouldn't adjust valist properly.
The problem is that va_arg can be passed variable size type, in which case
computation in HOST_WIDE_INTs is not appropriate.

Also, there is a second issue (which goes away with the following patch on
this testcase but I fear might pop up somewhere else).
instantiate_virtual_regs instantiates regs one by one, so when it works on
(insn 39 37 41 (parallel[
            (set (mem/f:SI (plus:SI (reg/f:SI 54 virtual-stack-vars)
                        (const_int -4 [0xfffffffc])) [0 ap+0 S4 A32])
                (plus:SI (mem/f:SI (plus:SI (reg/f:SI 54 virtual-stack-vars)
                            (const_int -4 [0xfffffffc])) [0 ap+0 S4 A32])
                    (const_int 0 [0x0])))
            (clobber (reg:CC 17 flags))
        ] ) -1 (nil)
    (nil))
it will abort, because replacing just one mem with a different mem means
ix86_binary_operator_ok will forbid matching (the 2 mems are no longer
equal).
I see 2 ways how to fix this:
either ix86_binary_operator_ok will just return 1 instead of comparing
mems for equality if (! virtuals_instantiated), or patch
instantiate_virtual_regs_1, so that if the first validate_change fails,
it looks in the whole object searching for other equal PLUS rtxs and if it
finds any, tries to validate them all at once.

Ok to commit following if testing succeeds?

2002-03-07  Jakub Jelinek  <jakub@redhat.com>

	PR c/3711
	* builtins.c (std_expand_builtin_va_arg): Do all computations on
	trees.

	* gcc.c-torture/execute/20020307-2.c: New test.

--- gcc/testsuite/gcc.c-torture/execute/20020307-2.c.jj	Thu Mar  7 20:16:52 2002
+++ gcc/testsuite/gcc.c-torture/execute/20020307-2.c	Thu Mar  7 22:23:03 2002
@@ -0,0 +1,55 @@
+/* PR c/3711
+   This testcase ICEd on IA-32 at -O0 and was miscompiled otherwise,
+   because std_expand_builtin_va_arg didn't handle variable size types.  */
+
+#include <stdarg.h>
+
+extern void abort (void);
+extern void exit (int);
+
+void bar (int c)
+{
+  static int d = '0';
+
+  if (c != d++)
+    abort ();
+  if (c < '0' || c > '9')
+    abort ();
+}
+
+void foo (int size, ...)
+{
+  struct
+  {
+    char x[size];
+  } d;
+  va_list ap;
+  int i;
+
+  va_start (ap, size);
+  d = va_arg (ap, typeof (d));
+  for (i = 0; i < size; i++)
+    bar (d.x[i]);
+  d = va_arg (ap, typeof (d));
+  for (i = 0; i < size; i++)
+    bar (d.x[i]);
+  va_end (ap);
+}
+
+int main (void)
+{
+  struct { char a[5]; } x, y;
+          
+  x.a[0] = '0';
+  x.a[1] = '1';
+  x.a[2] = '2';
+  x.a[3] = '3';
+  x.a[4] = '4';
+  y.a[0] = '5';
+  y.a[1] = '6';
+  y.a[2] = '7';
+  y.a[3] = '8';
+  y.a[4] = '9';
+  foo (5, x, y);
+  exit (0);
+}
--- gcc/builtins.c.jj	Thu Mar  7 15:51:25 2002
+++ gcc/builtins.c	Thu Mar  7 22:14:08 2002
@@ -2986,37 +2986,52 @@ rtx
 std_expand_builtin_va_arg (valist, type)
      tree valist, type;
 {
-  tree addr_tree, t;
-  HOST_WIDE_INT align;
-  HOST_WIDE_INT rounded_size;
+  tree addr_tree, t, type_size = NULL;
+  tree align, alignm1;
+  tree rounded_size;
   rtx addr;
 
   /* Compute the rounded size of the type.  */
-  align = PARM_BOUNDARY / BITS_PER_UNIT;
-  rounded_size = (((int_size_in_bytes (type) + align - 1) / align) * align);
+  align = size_int (PARM_BOUNDARY / BITS_PER_UNIT);
+  alignm1 = size_int (PARM_BOUNDARY / BITS_PER_UNIT + 1);
+  if (type == error_mark_node
+      || (type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type))) == NULL
+      || TREE_OVERFLOW (type_size))
+    rounded_size = size_zero_node;
+  else
+    rounded_size = fold (build (MULT_EXPR, sizetype,
+				build (TRUNC_DIV_EXPR, sizetype,
+				       build (PLUS_EXPR, sizetype,
+					      type_size, alignm1),
+				       align),
+				align));
 
   /* Get AP.  */
   addr_tree = valist;
-  if (PAD_VARARGS_DOWN)
+  if (PAD_VARARGS_DOWN && ! integer_zerop (rounded_size))
     {
       /* Small args are padded downward.  */
-
-      HOST_WIDE_INT adj
-	= rounded_size > align ? rounded_size : int_size_in_bytes (type);
-
       addr_tree = build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
-			 build_int_2 (rounded_size - adj, 0));
+			 build (COND_EXPR, sizetype,
+				build (GT_EXPR, sizetype,
+				       rounded_size, align),
+				size_zero_node,
+				build (MINUS_EXPR, sizetype,
+				       rounded_size, type_size)));
     }
 
-  addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
+  addr = expand_expr (fold (addr_tree), NULL_RTX, Pmode, EXPAND_NORMAL);
   addr = copy_to_reg (addr);
 
   /* Compute new value for AP.  */
-  t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
-	     build (PLUS_EXPR, TREE_TYPE (valist), valist,
-		    build_int_2 (rounded_size, 0)));
-  TREE_SIDE_EFFECTS (t) = 1;
-  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+  if (! integer_zerop (rounded_size))
+    {
+      t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
+		 build (PLUS_EXPR, TREE_TYPE (valist), valist,
+			rounded_size));
+      TREE_SIDE_EFFECTS (t) = 1;
+      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+    }
 
   return addr;
 }

	Jakub



More information about the Gcc-patches mailing list