problem with alias-safe code

Richard Henderson rth@cygnus.com
Sat Jun 27 23:52:00 GMT 1998


In article <r2ogveu5ch.fsf.cygnus.egcs.bugs@happy.cygnus.com>,
Ulrich Drepper <drepper@cygnus.com> wrote:
>  (((union { double D; int I[2]; }) {D: x}).I[1]) = i & 0x7fffffff;

This bit doesn't do what you think.  It modifies x in the same
way `Constructor(x).I[1] = blah' doesn't in c++.

There was another extension I'd hoped would work -- casting
to a union -- given that gcc has a cast-is-still-an-lvalue
extension as well.  But it turned out to do a copy as well.

I would up spending the day implementing this extension to the
union cast feature.  I also made certain forms not an lvalue,
since I couldn't see how to make them work as expected.

So now you can implement fabs as

double fabs (double x)
{
  ((union { double d; int i[2]; })x).i[1] &= 0x7fffffff;
  return x;
}

If this seems a sane kind of thing implementation-wise, I'll
update the documentation as well.  Mark, I'm a little fuzzy
on where your alias stuff wants to hook in -- is this safe
wrt that, bypassing conversions as I am?


r~


	* c-typeck.c (build_c_cast): Allow union casts whose source spans
	the entire structure to be an lvalue, and deny others.
	* expmed.c (store_bit_field): Transmute fp sources to an integral mode.
	(extract_bit_field): Likewise.
	* expr.c (expand_expr): When casting to a union, use the original
	source when possible.

Index: c-typeck.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/c-typeck.c,v
retrieving revision 1.18
diff -u -p -r1.18 c-typeck.c
--- c-typeck.c	1998/06/19 22:27:35	1.18
+++ c-typeck.c	1998/06/28 04:58:06
@@ -3726,24 +3726,31 @@ build_c_cast (type, expr)
 
       if (field)
 	{
-	  char *name;
 	  tree t;
 
 	  if (pedantic)
 	    pedwarn ("ANSI C forbids casts to union type");
-	  if (TYPE_NAME (type) != 0)
+
+	  /* If the original type spans the entire union, just swap types
+	     so that this can be used as an lvalue, as with the other gcc
+	     extension below.  */
+	  if (simple_cst_equal (TYPE_SIZE (type),
+				TYPE_SIZE (TREE_TYPE (value))))
 	    {
-	      if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
-		name = IDENTIFIER_POINTER (TYPE_NAME (type));
-	      else
-		name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
+	      t = build1 (NOP_EXPR, type, value);
+	      TREE_CONSTANT (t) = TREE_CONSTANT (value);
 	    }
 	  else
-	    name = "";
-	  t = digest_init (type, build (CONSTRUCTOR, type, NULL_TREE,
-					build_tree_list (field, value)),
-			   0, 0);
-	  TREE_CONSTANT (t) = TREE_CONSTANT (value);
+	    {
+	      /* Otherwise, build construct a temporary.  Mark it as a
+		 non-lvalue so that we don't think we can modify it
+		 usefully.  */
+	      t = digest_init (type, build (CONSTRUCTOR, type, NULL_TREE,
+					    build_tree_list (field, value)),
+			       0, 0);
+	      TREE_CONSTANT (t) = TREE_CONSTANT (value);
+	      t = non_lvalue (t);
+	    }
 	  return t;
 	}
       error ("cast to union type from type not present in union");
Index: expmed.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/expmed.c,v
retrieving revision 1.16
diff -u -p -r1.16 expmed.c
--- expmed.c	1998/06/24 13:32:56	1.16
+++ expmed.c	1998/06/28 05:28:23
@@ -260,7 +260,14 @@ store_bit_field (str_rtx, bitsize, bitnu
       && unit > GET_MODE_BITSIZE (GET_MODE (op0)))
     bitpos += unit - GET_MODE_BITSIZE (GET_MODE (op0));
 
-  value = protect_from_queue (value, 0);
+  /* If we are insertting to a non-integral type, convert it.  Fail to
+     attempt nonsense for BLKmode et al.  */
+  if (! INTEGRAL_MODE_P (GET_MODE (op0))
+      && GET_MODE_CLASS (GET_MODE (op0)) != MODE_RANDOM)
+    {
+      op0 = gen_lowpart (mode_for_size (GET_MODE_BITSIZE (GET_MODE (op0)),
+					MODE_INT, 0), op0);
+    }
 
   if (flag_force_mem)
     value = force_not_mem (value);
@@ -922,6 +929,15 @@ extract_bit_field (str_rtx, bitsize, bit
 	}
 
       op0 = SUBREG_REG (op0);
+    }
+
+  /* If we are insertting to a non-integral type, convert it.  Fail to
+     attempt nonsense for BLKmode et al.  */
+  if (! INTEGRAL_MODE_P (GET_MODE (op0))
+      && GET_MODE_CLASS (GET_MODE (op0)) != MODE_RANDOM)
+    {
+      op0 = gen_lowpart (mode_for_size (GET_MODE_BITSIZE (GET_MODE (op0)),
+					MODE_INT, 0), op0);
     }
 
   /* ??? We currently assume TARGET is at least as big as BITSIZE.
Index: expr.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/expr.c,v
retrieving revision 1.77
diff -u -p -r1.77 expr.c
--- expr.c	1998/06/25 15:14:26	1.77
+++ expr.c	1998/06/28 05:28:55
@@ -6287,6 +6300,23 @@ expand_expr (exp, target, tmode, modifie
       if (TREE_CODE (type) == UNION_TYPE)
 	{
 	  tree valtype = TREE_TYPE (TREE_OPERAND (exp, 0));
+
+	  /* If the value being cast is the same size as the union, don't
+	     copy the data, as we'd like to be able to use it as an lvalue.  */
+	  if (simple_cst_equal (TYPE_SIZE (type), TYPE_SIZE (valtype)))
+	    {
+	      rtx v = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode,
+				   code == NOP_EXPR ? modifier : ro_modifier);
+
+	      if (mode != BLKmode)
+	        v = gen_lowpart (tmode != VOIDmode ? tmode : mode, v);
+	      if (!target)
+		return v;
+
+	      emit_move_insn (target, v);
+	      return target;
+	    }
+
 	  if (target == 0)
 	    {
 	      if (mode != BLKmode)



More information about the Gcc-patches mailing list