This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Generalize builtin_mathfn_code
- From: Roger Sayle <roger at eyesopen dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: "Kaveh R. Ghazi" <ghazi at caip dot rutgers dot edu>
- Date: Thu, 11 Sep 2003 22:12:19 -0600 (MDT)
- Subject: [PATCH] Generalize builtin_mathfn_code
The following patch generalizes the middle-end's builtin_mathfn_code
function to most (all?) of GCC's builtin functions. As pointed out
by Kaveh, the current scheme suffers from the dual drawbacks that it
duplicates/hard-codes the builtin function's type (as already encoded
in builtins.def), and it isn't easily extensible to the large number
of mathematical builtins recently added to GCC.
The builtin_mathfn_code function is used within the middle-end to
determine that a given CALL_EXPR tree is actually a call to a standard
GCC builtin, with the correct number arguments with appropriate types.
Indeed historically the original name of this function was
builtin_mathfn_p, but it was decided under review to change it to
builtin_mathfn_code reflecting that upon success the program would return
BUILT_IN_SQRT, BUILT_IN_SIN or BUILT_IN_COS if the call was a valid
invocation to the resulting mathematical function. Indeed, this saved
the need for a series of predicates such as builtin_sqrt_call_p (), etc...
by factoring them into a single function and checking the return value.
An important role of this function was checking that the call's argument
list was a tree list containing a single expression of REAL_TYPE_P.
In C, it's possible to do some very wierd stuff that needs to be
defended against such as the following (see PR optimization/12085):
double pow(double, double);
double foo(double x, double y, int z)
{
return pow(x,y) * ((double(*)(double))pow)(x);
}
Most of the code to expand builtins as RTL defends against this abuse
by calling the function validate_arglist and generating a call to the
library function if arguments don't match their expected type classes.
In fold-const.c and elsewhere, the task of checking arguments is
handed off to builtin_mathfn_code. This dramatically simplifies this
code as once the constant folder as the "enum built_in_function"
result, it may index and dereference the call's argument list without
fear or NULL pointers or error_mark_nodes.
The problem is that the utility of this function has become its own
downfall. Where originally it handled just the common math builtins
that took a single floating point type and returned a floating point
type, it has since been extended to handle pow, powf, powl, atan2,
atan2f and atan2l which take two reals and return a real. And with
Kaveh's recent excellent work to support the remaining C90, C99 and
BSD mathematical builtins, there is now a need to support many more
function "shapes".
In hindsight the solution is so obvious as to be painful. Rather
than re-encode the types of each builtin via explicit checks in a
switch statement, the entire process may be generalized by simply
comparing the call's argument list against the builtin fndecl's
tree type, using the approximate middle-end notion of type matching,
i.e. that checks for compatible type classes, as is already used
in validate_arglist. This is exactly what the patch below does.
By calling this function at the beginning of expand_builtin and
fold_builtin, it should be possible to eliminate almost all of
the calls to validate_arglist in builtins.c. This also has the
added benefit of catching any remaining builtin function expanders
or folders that don't currently validate their argument lists (such
as expand_builtin_trap for example :).
The following patch has been tested on i686-pc-linux-gnu with a full
"make bootstrap", all languages except treelang, and regression tested
with a top-level "make -k check" with no new failures. Many thanks to
Kaveh for motivating this patch and his patience whilst I was developing
and testing it.
Ok for mainline?
2003-09-11 Roger Sayle <roger@eyesopen.com>
* builtins.c (builtin_mathfn_code): Generalize to check whether
the call is to any built-in function by comparing the call's
argument list against the builtin decl's function type.
Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.251
diff -c -3 -p -r1.251 builtins.c
*** builtins.c 9 Sep 2003 22:10:29 -0000 1.251
--- builtins.c 12 Sep 2003 00:48:34 -0000
*************** expand_builtin (tree exp, rtx target, rt
*** 5391,5405 ****
}
/* Determine whether a tree node represents a call to a built-in
! math function. If the tree T is a call to a built-in function
! taking a single real argument, then the return value is the
! DECL_FUNCTION_CODE of the call, e.g. BUILT_IN_SQRT. Otherwise
! the return value is END_BUILTINS. */
enum built_in_function
builtin_mathfn_code (tree t)
{
! tree fndecl, arglist;
if (TREE_CODE (t) != CALL_EXPR
|| TREE_CODE (TREE_OPERAND (t, 0)) != ADDR_EXPR)
--- 5391,5406 ----
}
/* Determine whether a tree node represents a call to a built-in
! function. If the tree T is a call to a built-in function with
! the right number of arguments of the appropriate types, return
! the DECL_FUNCTION_CODE of the call, e.g. BUILT_IN_SQRT.
! Otherwise the return value is END_BUILTINS. */
enum built_in_function
builtin_mathfn_code (tree t)
{
! tree fndecl, arglist, parmlist;
! tree argtype, parmtype;
if (TREE_CODE (t) != CALL_EXPR
|| TREE_CODE (TREE_OPERAND (t, 0)) != ADDR_EXPR)
*************** builtin_mathfn_code (tree t)
*** 5407,5442 ****
fndecl = get_callee_fndecl (t);
if (fndecl == NULL_TREE
|| ! DECL_BUILT_IN (fndecl)
|| DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
return END_BUILTINS;
arglist = TREE_OPERAND (t, 1);
! if (! arglist
! || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != REAL_TYPE)
! return END_BUILTINS;
!
! arglist = TREE_CHAIN (arglist);
! switch (DECL_FUNCTION_CODE (fndecl))
{
! case BUILT_IN_POW:
! case BUILT_IN_POWF:
! case BUILT_IN_POWL:
! case BUILT_IN_ATAN2:
! case BUILT_IN_ATAN2F:
! case BUILT_IN_ATAN2L:
! if (! arglist
! || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != REAL_TYPE
! || TREE_CHAIN (arglist))
return END_BUILTINS;
- break;
! default:
! if (arglist)
return END_BUILTINS;
! break;
}
return DECL_FUNCTION_CODE (fndecl);
}
--- 5408,5464 ----
fndecl = get_callee_fndecl (t);
if (fndecl == NULL_TREE
+ || TREE_CODE (fndecl) != FUNCTION_DECL
|| ! DECL_BUILT_IN (fndecl)
|| DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
return END_BUILTINS;
arglist = TREE_OPERAND (t, 1);
! parmlist = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
! for (; parmlist; parmlist = TREE_CHAIN (parmlist))
{
! /* If a function doesn't take a variable number of arguments,
! the last element in the list will have type `void'. */
! parmtype = TREE_VALUE (parmlist);
! if (VOID_TYPE_P (parmtype))
! {
! if (arglist)
! return END_BUILTINS;
! return DECL_FUNCTION_CODE (fndecl);
! }
!
! if (! arglist)
return END_BUILTINS;
! argtype = TREE_TYPE (TREE_VALUE (arglist));
!
! if (SCALAR_FLOAT_TYPE_P (parmtype))
! {
! if (! SCALAR_FLOAT_TYPE_P (argtype))
! return END_BUILTINS;
! }
! else if (COMPLEX_FLOAT_TYPE_P (parmtype))
! {
! if (! COMPLEX_FLOAT_TYPE_P (argtype))
! return END_BUILTINS;
! }
! else if (POINTER_TYPE_P (parmtype))
! {
! if (! POINTER_TYPE_P (argtype))
! return END_BUILTINS;
! }
! else if (INTEGRAL_TYPE_P (parmtype))
! {
! if (! INTEGRAL_TYPE_P (argtype))
! return END_BUILTINS;
! }
! else
return END_BUILTINS;
!
! arglist = TREE_CHAIN (arglist);
}
+ /* Variable-length argument list. */
return DECL_FUNCTION_CODE (fndecl);
}
Roger
--
Roger Sayle, E-mail: roger@eyesopen.com
OpenEye Scientific Software, WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road, Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507. Fax: (+1) 505-473-0833