This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: builtin_constant_p
- To: Jim Wilson <wilson at cygnus dot com>, Richard Henderson <rth at cygnus dot com>
- Subject: Re: builtin_constant_p
- From: Richard Henderson <rth at cygnus dot com>
- Date: Tue, 23 Jun 1998 20:57:04 -0700
- Cc: law at cygnus dot com, egcs-patches at cygnus dot com
- References: <19980615223134.29242@twiddle.rth.home> <199806182224.PAA21955@rtl.cygnus.com>
- Reply-To: Richard Henderson <rth at cygnus dot com>
On Thu, Jun 18, 1998 at 03:24:30PM -0700, Jim Wilson wrote:
> The reference is 1997-Dec/0485.html. I'll try applying it to the
> current tree and see what happens.
>
> The patch looks reasonable to me.
The biggest flaw I saw in the patch is that it doesn't care for
side effects of expressions. So __builtin_constant_p(i++) would
return false, but i would still be incremented.
The following updated patch tries to address this deficiency.
I have not addressed the concerns quoted below for the list's benefit.
> I think we will lose some optimization possibilities if we don't handle
> CONSTANT_P_RTX like other constants. E.g. it should be accepted by the
> CONSTANT_P macro, and probably many other places that accept constants.
> This might imply modifying some backends to accept CONSTANT_P_RTX in various
> places. This is probably too much work though. It depends on what operations
> we want to define as valid for CONSTANT_P_RTX. If the only thing it is valid
> for is loading into a pseudo, then we don't need to worry about it. But if
> we want to allow it to be used in addresses, then we need more support for it.
It doesn't seem likely that __builtin_constant_p will be used in addresses.
I see it most often used in
__builtin_constant_p(x) ? compile_time_expr(x) : run_time_expr(x)
> We might also need to worry about whether various predicates accept
> CONSTANT_P_RTX. This probably works fine on the x86 because it accepts
> practically any kind of operand anywhere you want it. This is not true
> of RISC targets though.
>
> Am I correct is assuming that this is similar to ADDRESSOF in that
> we effectively want to delay emitting const0_rtx if the expression
> is not initially a constant so that optimizers get a chance to
> propagate constants, potentially through inline function calls?
>
> yes.
>
> Seems to me that we could have CSE do the same thing -- ie leave it
> alone if its argument is still not a constant, but perform the
> replacement if the expression is constant. Then we have pass that
> runs after gcse (or maybe even cse2) which performs the substitution
> on any remaining CONSTANT_P_RTX expressions.
>
> There is a tradeoff on what optimizations can be performed. It we don't
> reduce CONSTANT_P_RTX to a one/zero until after cse/gcse, then it will be
> impossible for cse/gcse to perform any contant propagation on these values.
> This may result in worse code, if we aren't careful, because stuff that
> should have been optimized away may not be. For instance, consider branches
> on CONSTANT_P_RTX, which can't be optimized away if we don't know whether
> this is a one or a zero. Hence we need to do this at least before the last
> run of the jump optimization pass.
>
> Of course, if we treat CONSTANT_P_RTX exactly as if it is a constant value
> which isn't known yet, then we can still perform constant propagation.
> This implies that CONSTANT_P_RTX will end up in more places that it would
> otherwise, which means we need to look at all RTL when we are getting rid
> of the CONSTANT_P_RTX operations. This also will probably work only if all
> ports are modified to recognize CONSTANT_P_RTX as constants.
>
> It looks like we really should do this during cse or during gcse, so that
> we can get constant propagation, and so that the following jump optimize
> pass can eliminate now unnecessary branches.
So given the above expectation, do we still need to modify ports? Or
is updating CONSTANT_P sufficient?
r~
? m3cg
Index: cse.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cse.c,v
retrieving revision 1.35
diff -u -p -r1.35 cse.c
--- cse.c 1998/06/17 20:20:21 1.35
+++ cse.c 1998/06/23 22:05:00
@@ -5715,6 +5715,12 @@ fold_rtx (x, insn)
const_arg1 ? const_arg1 : folded_arg1,
const_arg2 ? const_arg2 : XEXP (x, 2));
break;
+
+ case 'x':
+ /* Always eliminate CONSTANT_P_RTX at this stage. */
+ if (code == CONSTANT_P_RTX)
+ return (const_arg0 ? const1_rtx : const0_rtx);
+ break;
}
return new ? new : x;
Index: expr.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/expr.c,v
retrieving revision 1.73
diff -u -p -r1.73 expr.c
--- expr.c 1998/06/19 22:06:11 1.73
+++ expr.c 1998/06/23 22:05:24
@@ -8442,10 +8442,18 @@ expand_builtin (exp, target, subtarget,
tree arg = TREE_VALUE (arglist);
STRIP_NOPS (arg);
- return (TREE_CODE_CLASS (TREE_CODE (arg)) == 'c'
- || (TREE_CODE (arg) == ADDR_EXPR
- && TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST)
- ? const1_rtx : const0_rtx);
+ if (really_constant_p (arg)
+ || (TREE_CODE (arg) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST))
+ return const1_rtx;
+
+ /* Only emit CONSTANT_P_RTX if CSE will be run. Moreover, we
+ can't expand trees that have side effects. */
+ if (optimize > 0 && no_side_effects_p (arg))
+ return gen_rtx_CONSTANT_P_RTX (TYPE_MODE (integer_type_node),
+ expand_expr (TREE_VALUE (arglist),
+ NULL_RTX, VOIDmode, 0));
+ return const0_rtx;
}
case BUILT_IN_FRAME_ADDRESS:
Index: rtl.def
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/rtl.def,v
retrieving revision 1.9
diff -u -p -r1.9 rtl.def
--- rtl.def 1998/06/17 16:13:53 1.9
+++ rtl.def 1998/06/23 22:05:27
@@ -834,6 +834,11 @@ DEF_RTL_EXPR(RANGE_VAR, "range_var", "et
0 is the live bitmap. Operand 1 is the original block number. */
DEF_RTL_EXPR(RANGE_LIVE, "range_live", "bi", 'x')
+/* A unary `__builtin_constant_p' expression. These are only emitted
+ during RTL generation, and then only if optimize > 0. They are
+ eliminated by the first CSE pass. */
+DEF_RTL_EXPR(CONSTANT_P_RTX, "constant_p", "e", 'x')
+
/*
Local variables:
mode:c
Index: tree.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/tree.c,v
retrieving revision 1.33
diff -u -p -r1.33 tree.c
--- tree.c 1998/06/20 00:35:42 1.33
+++ tree.c 1998/06/23 22:05:38
@@ -1802,6 +1802,57 @@ really_constant_p (exp)
exp = TREE_OPERAND (exp, 0);
return TREE_CONSTANT (exp);
}
+
+/* Nonzero if EXP has no side effects. */
+
+int
+no_side_effects_p (exp)
+ tree exp;
+{
+ switch (TREE_CODE (exp))
+ {
+ /* 'e' */
+ case COND_EXPR:
+ if (!no_side_effects_p (TREE_OPERAND (exp, 2)))
+ return 0;
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_ORIF_EXPR:
+ case TRUTH_AND_EXPR:
+ case TRUTH_OR_EXPR:
+ if (!no_side_effects_p (TREE_OPERAND (exp, 1)))
+ return 0;
+ case TRUTH_XOR_EXPR:
+ case TRUTH_NOT_EXPR:
+ case ADDR_EXPR:
+ case REFERENCE_EXPR:
+ return no_side_effects_p (TREE_OPERAND (exp, 0));
+
+ case SAVE_EXPR:
+ /* ??? A difference based on when we examine something? */
+ if (SAVE_EXPR_RTL (exp) != 0)
+ return 1;
+ return no_side_effects_p (TREE_OPERAND (exp, 0));
+ }
+
+ switch (TREE_CODE_CLASS (TREE_CODE (exp)))
+ {
+ case 'd': case 'c':
+ return 1;
+
+ case '<': case '2':
+ if (!no_side_effects_p (TREE_OPERAND (exp, 1)))
+ return 0;
+ case '1':
+ return no_side_effects_p (TREE_OPERAND (exp, 0));
+
+ case 's':
+ case 'r': case 'e':
+ return 0;
+
+ default:
+ abort();
+ }
+}
/* Return first list element whose TREE_VALUE is ELEM.
Return 0 if ELEM is not in LIST. */
Index: tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/tree.h,v
retrieving revision 1.41
diff -u -p -r1.41 tree.h
--- tree.h 1998/06/17 16:13:58 1.41
+++ tree.h 1998/06/23 22:05:43
@@ -2028,6 +2028,7 @@ extern void pop_obstacks PROTO((void));
/* In tree.c */
extern int really_constant_p PROTO ((tree));
+extern int no_side_effects_p PROTO ((tree));
extern void push_obstacks PROTO ((struct obstack *,
struct obstack *));
extern void pop_momentary_nofree PROTO ((void));