This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] RHS INDIRECT_REF optimizations (PR tree-optimization/26069)
- From: Jakub Jelinek <jakub at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Fri, 11 Jan 2008 14:33:39 -0500
- Subject: [PATCH] RHS INDIRECT_REF optimizations (PR tree-optimization/26069)
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
Hi!
unsigned short x;
...
y = *(short *) &x;
can be optimized as
y = (short) x;
Similarly
unsigned long x;
...
y = *(char *) &x;
can be optimized as
y = (char) x; on little endian and
y = (char) (x >> N); on big endian.
It is especially helpful if the var is no longer addressable
because of these transformations, but they work only on RHS,
so they can't be done in fold_indirect_ref_1.
With older GCCs this was usually optimized using ADDRESSOF,
so this is actually a regression from 3.4.
Bootstrapped/regtested on x86_64-linux, ok for trunk?
2008-01-11 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/26069
* gimplify.c (fold_indirect_ref_rhs): Renamed to ...
(gimple_fold_indirect_ref): ... this.
(gimple_fold_indirect_ref_rhs): New function.
(gimplify_modify_expr_rhs): Call gimple_fold_indirect_ref_rhs
instead of fold_indirect_ref_rhs.
(gimplify_expr) <case INDIRECT_REF>: If fold_indirect_ref
didn't optimize anything, try gimple_fold_indirect_ref_rhs
or gimple_fold_indirect_ref depending on fallback value.
* gcc.dg/tree-ssa/pr26069.c: New test.
--- gcc/gimplify.c.jj 2008-01-11 16:31:21.000000000 +0100
+++ gcc/gimplify.c 2008-01-11 17:39:27.000000000 +0100
@@ -1,6 +1,6 @@
/* Tree lowering pass. This pass converts the GENERIC functions-as-trees
tree representation into the GIMPLE form.
- Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007
+ Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
Major work done by Sebastian Pop <s.pop@laposte.net>,
Diego Novillo <dnovillo@redhat.com> and Jason Merrill <jason@redhat.com>.
@@ -3449,13 +3449,12 @@ gimplify_init_constructor (tree *expr_p,
/* Given a pointer value OP0, return a simplified version of an
indirection through OP0, or NULL_TREE if no simplification is
- possible. This may only be applied to a rhs of an expression.
- Note that the resulting type may be different from the type pointed
- to in the sense that it is still compatible from the langhooks
- point of view. */
+ possible. Note that the resulting type may be different from
+ the type pointed to in the sense that it is still compatible
+ from the langhooks point of view. */
static tree
-fold_indirect_ref_rhs (tree t)
+gimple_fold_indirect_ref (tree t)
{
tree type = TREE_TYPE (TREE_TYPE (t));
tree sub = t;
@@ -3473,9 +3472,10 @@ fold_indirect_ref_rhs (tree t)
/* *&p => p */
if (useless_type_conversion_p (type, optype))
return op;
+
/* *(foo *)&fooarray => fooarray[0] */
- else if (TREE_CODE (optype) == ARRAY_TYPE
- && useless_type_conversion_p (type, TREE_TYPE (optype)))
+ if (TREE_CODE (optype) == ARRAY_TYPE
+ && useless_type_conversion_p (type, TREE_TYPE (optype)))
{
tree type_domain = TYPE_DOMAIN (optype);
tree min_val = size_zero_node;
@@ -3492,7 +3492,7 @@ fold_indirect_ref_rhs (tree t)
tree type_domain;
tree min_val = size_zero_node;
tree osub = sub;
- sub = fold_indirect_ref_rhs (sub);
+ sub = gimple_fold_indirect_ref (sub);
if (! sub)
sub = build1 (INDIRECT_REF, TREE_TYPE (subtype), osub);
type_domain = TYPE_DOMAIN (TREE_TYPE (sub));
@@ -3504,6 +3504,82 @@ fold_indirect_ref_rhs (tree t)
return NULL_TREE;
}
+/* Given a pointer value OP0, return a simplified version of an
+ indirection through OP0, or NULL_TREE if no simplification is
+ possible. This may only be applied to a rhs of an expression.
+ Note that the resulting type may be different from the type pointed
+ to in the sense that it is still compatible from the langhooks
+ point of view. */
+static tree
+gimple_fold_indirect_ref_rhs (tree t)
+{
+ tree type;
+ tree sub;
+ tree subtype;
+
+ sub = gimple_fold_indirect_ref (t);
+ if (sub)
+ return sub;
+
+ type = TREE_TYPE (TREE_TYPE (t));
+ sub = t;
+ STRIP_NOPS (sub);
+ subtype = TREE_TYPE (sub);
+ if (!POINTER_TYPE_P (subtype))
+ return NULL_TREE;
+
+ if (TREE_CODE (sub) == ADDR_EXPR)
+ {
+ tree op = TREE_OPERAND (sub, 0);
+ tree optype = TREE_TYPE (op);
+
+ if ((INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
+ && (INTEGRAL_TYPE_P (optype) || POINTER_TYPE_P (optype))
+ && TYPE_PRECISION (type) == GET_MODE_BITSIZE (TYPE_MODE (type))
+ && !TREE_THIS_VOLATILE (op)
+ && !TYPE_VOLATILE (optype) && !TYPE_VOLATILE (type))
+ {
+ /* Handle e.g. unsigned short int x; *(short int *) &x; */
+ if (TYPE_MODE (type) == TYPE_MODE (optype)
+ && TYPE_PRECISION (type) == TYPE_PRECISION (optype))
+ return fold_convert (type, op);
+
+ /* Handle e.g. unsigned long int x; *(char *) &x; */
+ if (TYPE_PRECISION (type) == BITS_PER_UNIT
+ && TYPE_PRECISION (optype) > TYPE_PRECISION (type)
+ && (TYPE_PRECISION (optype)
+ == GET_MODE_BITSIZE (TYPE_MODE (optype))))
+ {
+ int shift = 0;
+ tree itype;
+
+ if (TYPE_PRECISION (optype) > BITS_PER_WORD)
+ {
+ if (WORDS_BIG_ENDIAN)
+ shift = (TYPE_PRECISION (optype) / BITS_PER_WORD - 1)
+ * BITS_PER_WORD;
+ if (BYTES_BIG_ENDIAN)
+ shift += BITS_PER_WORD - BITS_PER_UNIT;
+ }
+ else if (BYTES_BIG_ENDIAN)
+ shift = TYPE_PRECISION (optype) - BITS_PER_UNIT;
+
+ if (shift == 0)
+ return fold_convert (type, op);
+
+ itype = lang_hooks.types.type_for_size (TYPE_PRECISION (optype),
+ TYPE_UNSIGNED (type));
+ return fold_convert (type,
+ fold_build2 (RSHIFT_EXPR, itype,
+ fold_convert (itype, op),
+ build_int_cst (NULL, shift)));
+ }
+ }
+ }
+
+ return NULL_TREE;
+}
+
/* Subroutine of gimplify_modify_expr to do simplifications of
MODIFY_EXPRs based on the code of the RHS. We loop for as long as
something changes. */
@@ -3557,7 +3633,7 @@ gimplify_modify_expr_rhs (tree *expr_p,
This kind of code arises in C++ when an object is bound
to a const reference, and if "x" is a TARGET_EXPR we want
to take advantage of the optimization below. */
- tree t = fold_indirect_ref_rhs (TREE_OPERAND (*from_p, 0));
+ tree t = gimple_fold_indirect_ref_rhs (TREE_OPERAND (*from_p, 0));
if (t)
{
*from_p = t;
@@ -5750,6 +5826,16 @@ gimplify_expr (tree *expr_p, tree *pre_p
*expr_p = fold_indirect_ref (*expr_p);
if (*expr_p != save_expr)
break;
+ if (fallback == fb_rvalue)
+ tmp = gimple_fold_indirect_ref_rhs (TREE_OPERAND (*expr_p, 0));
+ else
+ tmp = gimple_fold_indirect_ref (TREE_OPERAND (*expr_p, 0));
+ if (tmp != NULL_TREE)
+ {
+ *expr_p = tmp;
+ break;
+ }
+
/* else fall through. */
case ALIGN_INDIRECT_REF:
case MISALIGNED_INDIRECT_REF:
--- gcc/testsuite/gcc.dg/tree-ssa/pr26069.c.jj 2008-01-11 17:50:10.000000000 +0100
+++ gcc/testsuite/gcc.dg/tree-ssa/pr26069.c 2008-01-11 17:53:45.000000000 +0100
@@ -0,0 +1,39 @@
+/* PR tree-optimization/26069 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-gimple" } */
+
+extern void f5 (int *);
+
+int
+f1 ()
+{
+ unsigned x = 1;
+ return *(char *) &x;
+}
+
+int
+f2 (short a)
+{
+ unsigned short b = *(unsigned short *) &a;
+ return b;
+}
+
+struct S { int i; } s;
+
+int
+f3 (void)
+{
+ return *(char *) &s.i;
+}
+
+int
+f4 (int x)
+{
+ int ret = *(char *) &x;
+ f5 (&x);
+ return ret;
+}
+
+/* All ADDR_EXPRs but the one in f5 (&x) should be optimized out. */
+/* { dg-final { scan-tree-dump-times "&" 1 "gimple"} } */
+/* { dg-final { cleanup-tree-dump "gimple" } } */
Jakub