This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: problem with alias-safe code
- To: drepper at cygnus dot com, egcs-patches at cygnus dot com
- Subject: Re: problem with alias-safe code
- From: Richard Henderson <rth at cygnus dot com>
- Date: Sat, 27 Jun 1998 22:49:36 -0700
- Newsgroups: cygnus.egcs.bugs
- References: <r2ogveu5ch.fsf.cygnus.egcs.bugs@happy.cygnus.com>
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)