Constant folding for builtins

From-SVN: r37191
This commit is contained in:
Bernd Schmidt 2000-11-01 17:02:45 +00:00 committed by Bernd Schmidt
parent f92351d76e
commit b0b3afb2f3
7 changed files with 116 additions and 40 deletions

View File

@ -1,3 +1,14 @@
2000-11-01 Bernd Schmidt <bernds@redhat.co.uk>
* builtins.c (fold_builtin_constant_p, fold_builtin): New functions.
(expand_builtin_constant_p): Move parts of the code into
fold_builtin_constant_p.
(expand_builtin_strlen): Move parts of the code into fold_builtin.
* expr.h (fold_builtin): Declare.
* fold-const.c (fold): Handle builtin calls.
* c-typeck.c (build_function_call): Call fold on the CALL_EXPR.
2000-11-01 Richard Henderson <rth@redhat.com>
* stmt.c (expand_start_null_loop): New.

View File

@ -116,6 +116,7 @@ static rtx expand_builtin_frame_address PARAMS ((tree));
static rtx expand_builtin_fputs PARAMS ((tree, int));
static tree stabilize_va_list PARAMS ((tree, int));
static rtx expand_builtin_expect PARAMS ((tree, rtx));
static tree fold_builtin_constant_p PARAMS ((tree));
/* Return the alignment in bits of EXP, a pointer valued expression.
But don't return more than MAX_ALIGN no matter what.
@ -1161,44 +1162,19 @@ expand_builtin_constant_p (exp)
{
tree arglist = TREE_OPERAND (exp, 1);
enum machine_mode value_mode = TYPE_MODE (TREE_TYPE (exp));
rtx tmp;
if (arglist == 0)
return const0_rtx;
else
{
tree arg = TREE_VALUE (arglist);
rtx tmp;
arglist = TREE_VALUE (arglist);
/* We return 1 for a numeric type that's known to be a constant
value at compile-time or for an aggregate type that's a
literal constant. */
STRIP_NOPS (arg);
/* We have taken care of the easy cases during constant folding. This
case is not obvious, so emit (constant_p_rtx (ARGLIST)) and let CSE get a
chance to see if it can deduce whether ARGLIST is constant. */
/* If we know this is a constant, emit the constant of one. */
if (TREE_CODE_CLASS (TREE_CODE (arg)) == 'c'
|| (TREE_CODE (arg) == CONSTRUCTOR
&& TREE_CONSTANT (arg))
|| (TREE_CODE (arg) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST))
return const1_rtx;
/* If we aren't going to be running CSE or this expression
has side effects, show we don't know it to be a constant.
Likewise if it's a pointer or aggregate type since in those
case we only want literals, since those are only optimized
when generating RTL, not later. */
if (TREE_SIDE_EFFECTS (arg) || cse_not_expected
|| AGGREGATE_TYPE_P (TREE_TYPE (arg))
|| POINTER_TYPE_P (TREE_TYPE (arg)))
return const0_rtx;
/* Otherwise, emit (constant_p_rtx (ARG)) and let CSE get a
chance to see if it can deduce whether ARG is constant. */
tmp = expand_expr (arg, NULL_RTX, VOIDmode, 0);
tmp = gen_rtx_CONSTANT_P_RTX (value_mode, tmp);
return tmp;
}
tmp = expand_expr (arglist, NULL_RTX, VOIDmode, 0);
tmp = gen_rtx_CONSTANT_P_RTX (value_mode, tmp);
return tmp;
}
/* Expand a call to one of the builtin math functions (sin, cos, or sqrt).
@ -1342,7 +1318,6 @@ expand_builtin_strlen (exp, target, mode)
{
rtx pat;
tree src = TREE_VALUE (arglist);
tree len = c_strlen (src);
int align
= get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
@ -1351,10 +1326,6 @@ expand_builtin_strlen (exp, target, mode)
enum machine_mode insn_mode = value_mode, char_mode;
enum insn_code icode = CODE_FOR_nothing;
/* If the length is known, just return it. */
if (len != 0)
return expand_expr (len, target, mode, EXPAND_MEMORY_USE_BAD);
/* If SRC is not a pointer type, don't do this operation inline. */
if (align == 0)
return 0;
@ -2814,3 +2785,78 @@ expand_builtin (exp, target, subtarget, mode, ignore)
to be called normally. */
return expand_call (exp, target, ignore);
}
/* Fold a call to __builtin_constant_p, if we know it will evaluate to a
constant. ARGLIST is the argument list of the call. */
static tree
fold_builtin_constant_p (arglist)
tree arglist;
{
if (arglist == 0)
return 0;
arglist = TREE_VALUE (arglist);
/* We return 1 for a numeric type that's known to be a constant
value at compile-time or for an aggregate type that's a
literal constant. */
STRIP_NOPS (arglist);
/* If we know this is a constant, emit the constant of one. */
if (TREE_CODE_CLASS (TREE_CODE (arglist)) == 'c'
|| (TREE_CODE (arglist) == CONSTRUCTOR
&& TREE_CONSTANT (arglist))
|| (TREE_CODE (arglist) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (arglist, 0)) == STRING_CST))
return integer_one_node;
/* If we aren't going to be running CSE or this expression
has side effects, show we don't know it to be a constant.
Likewise if it's a pointer or aggregate type since in those
case we only want literals, since those are only optimized
when generating RTL, not later. */
if (TREE_SIDE_EFFECTS (arglist) || cse_not_expected
|| AGGREGATE_TYPE_P (TREE_TYPE (arglist))
|| POINTER_TYPE_P (TREE_TYPE (arglist)))
return integer_zero_node;
return 0;
}
/* Used by constant folding to eliminate some builtin calls early. EXP is
the CALL_EXPR of a call to a builtin function. */
tree
fold_builtin (exp)
tree exp;
{
tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
tree arglist = TREE_OPERAND (exp, 1);
enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
return 0;
switch (fcode)
{
case BUILT_IN_CONSTANT_P:
return fold_builtin_constant_p (arglist);
case BUILT_IN_STRLEN:
if (arglist != 0
/* Arg could be non-pointer if user redeclared this fcn wrong. */
&& TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) == POINTER_TYPE)
{
tree len = c_strlen (TREE_VALUE (arglist));
if (len != 0)
return len;
}
break;
default:
break;
}
return 0;
}

View File

@ -1567,8 +1567,9 @@ build_function_call (function, params)
result = build (CALL_EXPR, TREE_TYPE (fntype),
function, coerced_params, NULL_TREE);
TREE_SIDE_EFFECTS (result) = 1;
result = fold (result);
if (VOID_TYPE_P (TREE_TYPE (result)))
return result;
return require_complete_type (result);

View File

@ -1,3 +1,7 @@
2000-11-01 Bernd Schmidt <bernds@redhat.co.uk>
* call.c (build_over_call): Call fold on the CALL_EXPR.
2000-11-01 Gabriel Dos Reis <gdr@codesourcery.com>
* error.c (dump_template_decl): Separate template hearders with

View File

@ -4188,7 +4188,7 @@ build_over_call (cand, args, flags)
return exp;
}
fn = build_call (fn, converted_args);
fn = fold (build_call (fn, converted_args));
if (TREE_CODE (TREE_TYPE (fn)) == VOID_TYPE)
return fn;
fn = require_complete_type (fn);

View File

@ -918,6 +918,7 @@ extern rtx gen_cond_trap PARAMS ((enum rtx_code, rtx, rtx, rtx));
/* Functions from builtins.c: */
#ifdef TREE_CODE
extern rtx expand_builtin PARAMS ((tree, rtx, rtx, enum machine_mode, int));
extern tree fold_builtin PARAMS ((tree));
extern tree expand_tree_builtin PARAMS ((tree, tree, tree));
extern void std_expand_builtin_va_start PARAMS ((int, tree, rtx));
extern rtx std_expand_builtin_va_arg PARAMS ((tree, tree));

View File

@ -7168,6 +7168,19 @@ fold (expr)
return t;
}
case CALL_EXPR:
/* Check for a built-in function. */
if (TREE_CODE (TREE_OPERAND (expr, 0)) == ADDR_EXPR
&& (TREE_CODE (TREE_OPERAND (TREE_OPERAND (expr, 0), 0))
== FUNCTION_DECL)
&& DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (expr, 0), 0)))
{
tree tmp = fold_builtin (expr);
if (tmp)
return tmp;
}
return t;
default:
return t;
} /* switch (code) */