This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

builtins: choose_expr and types_compatible_p


i've neglected to finish the builtins we discussed way back in this
thread:
	
	http://gcc.gnu.org/ml/gcc/2001-10/msg00302.html

these builtins are needed in 3.1 for altivec support (overloaded C
functions).

ideally, glibc should be changed to use these functions (particularly in
gmath.h?), but my main goal is to have the working builtins first, get
the rest of my misc changes before 3.1, and then start worrying about
cleaning and prettying up glibc.

without further ado.  here is the completed patch, with comprehensive
docs as well as corresponding testcases.  and yes, make info works. :)

happinness everyone?

-- 
Aldy Hernandez			E-mail: aldyh@redhat.com
Professional Gypsy
Red Hat, Inc.

2001-10-07  Aldy Hernandez  <aldyh@redhat.com>

        * testsuite/gcc.c-torture/execute/builtin-types-compatible-p.c: New.

        * testsuite/gcc.c-torture/gcc.dg/builtin-choose-expr.c: New.

        * c-common.h (rid): Add RID_CHOOSE_EXPR and
        RID_TYPES_COMPATIBLE_P.

        * c-parse.in (reswords): Add __builtin_choose_expr.
        Add __builtin_types_compatible_p.
        Add CHOOSE_EXPR token.
        Add TYPES_COMPATIBLE_P token.
        Add production for CHOOSE_EXPR.
        Add production for TYPES_COMPATIBLE_P.

        * doc/extend.texi (__builtin_choose_expr): Add documentation.
        (__builtin_types_compatible_p): Likewise.


Index: c-common.h
===================================================================
RCS file: /cvs/uberbaum/gcc/c-common.h,v
retrieving revision 1.104
diff -c -p -r1.104 c-common.h
*** c-common.h	2001/12/05 23:19:55	1.104
--- c-common.h	2001/12/08 06:02:07
*************** enum rid
*** 74,80 ****
    /* C extensions */
    RID_ASM,       RID_TYPEOF,   RID_ALIGNOF,  RID_ATTRIBUTE,  RID_VA_ARG,
    RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,      RID_PTRBASE,
!   RID_PTREXTENT, RID_PTRVALUE,
  
    /* Too many ways of getting the name of a function as a string */
    RID_FUNCTION_NAME, RID_PRETTY_FUNCTION_NAME, RID_C99_FUNCTION_NAME,
--- 74,80 ----
    /* C extensions */
    RID_ASM,       RID_TYPEOF,   RID_ALIGNOF,  RID_ATTRIBUTE,  RID_VA_ARG,
    RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,      RID_PTRBASE,
!   RID_PTREXTENT, RID_PTRVALUE, RID_CHOOSE_EXPR, RID_TYPES_COMPATIBLE_P,
  
    /* Too many ways of getting the name of a function as a string */
    RID_FUNCTION_NAME, RID_PRETTY_FUNCTION_NAME, RID_C99_FUNCTION_NAME,
Index: c-parse.in
===================================================================
RCS file: /cvs/uberbaum/gcc/c-parse.in,v
retrieving revision 1.117
diff -c -p -r1.117 c-parse.in
*** c-parse.in	2001/12/04 22:55:37	1.117
--- c-parse.in	2001/12/08 06:02:08
*************** end ifobjc
*** 111,117 ****
  %token SIZEOF ENUM STRUCT UNION IF ELSE WHILE DO FOR SWITCH CASE DEFAULT
  %token BREAK CONTINUE RETURN GOTO ASM_KEYWORD TYPEOF ALIGNOF
  %token ATTRIBUTE EXTENSION LABEL
! %token REALPART IMAGPART VA_ARG
  %token PTR_VALUE PTR_BASE PTR_EXTENT
  
  /* function name can be a string const or a var decl. */
--- 111,117 ----
  %token SIZEOF ENUM STRUCT UNION IF ELSE WHILE DO FOR SWITCH CASE DEFAULT
  %token BREAK CONTINUE RETURN GOTO ASM_KEYWORD TYPEOF ALIGNOF
  %token ATTRIBUTE EXTENSION LABEL
! %token REALPART IMAGPART VA_ARG CHOOSE_EXPR TYPES_COMPATIBLE_P
  %token PTR_VALUE PTR_BASE PTR_EXTENT
  
  /* function name can be a string const or a var decl. */
*************** primary:
*** 669,674 ****
--- 669,693 ----
  		{ $$ = build_function_call ($1, $3); }
  	| VA_ARG '(' expr_no_commas ',' typename ')'
  		{ $$ = build_va_arg ($3, groktypename ($5)); }
+       | CHOOSE_EXPR '(' expr_no_commas ',' expr_no_commas ',' expr_no_commas ')'
+ 		{
+                   tree c;
+ 
+                   c = fold ($3);
+                   STRIP_NOPS (c);
+                   if (TREE_CODE (c) != INTEGER_CST)
+                     error ("first argument to __builtin_choose_expr not a constant");
+                   $$ = integer_zerop (c) ? $7 : $5;
+ 		}
+       | TYPES_COMPATIBLE_P '(' typename ',' typename ')'
+ 		{
+ 		  tree e1, e2;
+ 
+ 		  e1 = TYPE_MAIN_VARIANT (groktypename ($3));
+ 		  e2 = TYPE_MAIN_VARIANT (groktypename ($5));
+ 
+ 		  $$ = e1 == e2 ? build_int_2 (1, 0) : build_int_2 (0, 0);
+ 		}
  	| primary '[' expr ']'   %prec '.'
  		{ $$ = build_array_ref ($1, $3); }
  	| primary '.' identifier
*************** static const struct resword reswords[] =
*** 3249,3254 ****
--- 3268,3275 ----
    { "__attribute__",	RID_ATTRIBUTE,	0 },
    { "__bounded",	RID_BOUNDED,	0 },
    { "__bounded__",	RID_BOUNDED,	0 },
+   { "__builtin_choose_expr", RID_CHOOSE_EXPR, 0 },
+   { "__builtin_types_compatible_p", RID_TYPES_COMPATIBLE_P, 0 },
    { "__builtin_va_arg",	RID_VA_ARG,	0 },
    { "__complex",	RID_COMPLEX,	0 },
    { "__complex__",	RID_COMPLEX,	0 },
*************** static const short rid_to_yy[RID_MAX] =
*** 3420,3425 ****
--- 3441,3449 ----
    /* RID_PTRBASE */	PTR_BASE,
    /* RID_PTREXTENT */	PTR_EXTENT,
    /* RID_PTRVALUE */	PTR_VALUE,
+ 
+   /* RID_CHOOSE_EXPR */			CHOOSE_EXPR,
+   /* RID_TYPES_COMPATIBLE_P */		TYPES_COMPATIBLE_P,
  
    /* RID_FUNCTION_NAME */		STRING_FUNC_NAME,
    /* RID_PRETTY_FUNCTION_NAME */	STRING_FUNC_NAME,
Index: doc/extend.texi
===================================================================
RCS file: /cvs/uberbaum/gcc/doc/extend.texi,v
retrieving revision 1.43
diff -c -p -r1.43 extend.texi
*** extend.texi	2001/12/07 23:00:16	1.43
--- extend.texi	2001/12/08 06:02:09
*************** the same names as the standard macros ( 
*** 4388,4393 ****
--- 4388,4477 ----
  prefixed.  We intend for a library implementor to be able to simply
  @code{#define} each standard macro to its built-in equivalent.
  
+ @deftypefn {Built-in Function} int __builtin_types_compatible_p (@var{type1}, @var{type2})
+ 
+ You can use the builtin function @code{__builtin_types_compatible_p} to
+ determine whether two types are the same.
+ 
+ This builtin returns 1 if the unqualified versions of the types
+ @var{type1} and @var{type2} (which are types, not expressions) are
+ compatible, 0 otherwise.  The result of this builtin can be used in
+ integer constant expressions.
+ 
+ This builtin ignores top level qualifiers (e.g., const, static).  For
+ example, @code{int} is equivalent to @code{const int}.
+ 
+ The type @code{int[]} and @code{int[5]} are compatible.  On the other
+ hand, @code{int} and @code{char *} are not compatible, even if the size
+ of their types, on the particular architecture are the same.  Also, the
+ amount of pointer indirection is taken into account when determining
+ similarity.  Consequently, @code{short *} is not similar to
+ @code{short **}.  Furthermore, two types that are typedefed are
+ considered compatible if their underlying types are compatible.
+ 
+ An @code{enum} type is not considered to be compatible with another
+ @code{enum} type.  For example, @code{enum @{foo, bar@}} is not similar
+ to @code{enum @{hot, dog@}}.  However, the type of an @code{enum}
+ element is considered to be of the same type as the type of any another
+ @code{enum} element.  In the above example, @code{hot} has the same type
+ as @code{bar}.  Lastly, @code{enum} elements are considered to have the
+ same type as an @code{int}.  In the above example, @code{foo} has the
+ same type as @code{int}.
+ 
+ You would typically use this function in code whose execution varies
+ depending on the arguments' types.  For example:
+ 
+ @smallexample
+ #define foo(x)                                                        \
+   (@{                                                                 \
+     typeof (x) tmp;                                                   \
+     if (__builtin_types_compatible_p (typeof (x), long double))       \
+       tmp = foo_long_double (tmp);                                    \
+     else if (__builtin_types_compatible_p (typeof (x), double))       \
+       tmp = foo_double (tmp);                                         \
+     else if (__builtin_types_compatible_p (typeof (x), float))        \
+       tmp = foo_float (tmp);                                          \
+     else                                                              \
+       abort ();                                                       \
+     tmp;                                                              \
+   @})
+ @end smallexample
+ 
+ @end deftypefn
+ 
+ @deftypefn {Built-in Function} int __builtin_choose_expr (@var{const_exp}, @var{exp1}, @var{exp2})
+ 
+ You can use the builtin function @code{__builtin_choose_expr} to
+ evaluate code depending on the value of a constant expression.  This
+ builtin returns @var{exp1} if @var{const_exp}, which is a constant
+ expression that must be able to be determined at runtime, is non zero.
+ Otherwise it returns 0.
+ 
+ This builtin is analogous to the @code{? :} operator in C, except that
+ the expression returned has its type unaltered by promotion rules.
+ Also, the builtin does not evaluate the expression that was not chosen.
+ For example, if @var{const_exp} evaluates to true, @var{exp2} is not
+ evaluated even if it has side-effects.
+ 
+ If @var{exp1} is returned, the return type is the same as @var{exp1}'s
+ type.  Similarly, if @var{exp2} is returned, its return type is the same
+ as @var{exp2}.
+ 
+ Example:
+ 
+ @smallexample
+ #define foo(x)                                                               \
+   __builtin_choose_expr (__builtin_types_compatible_p (typeof (x), double),  \
+     foo_double (x),                                                          \
+     __builtin_choose_expr (__builtin_types_compatible_p (typeof (x), float), \
+       foo_float (x),                                                         \
+       /* The void expression results in a compile-time error                 \
+          when assigning the result to something.  */                         \
+       (void)0))
+ @end smallexample
+ 
+ @end deftypefn
+ 
  @deftypefn {Built-in Function} int __builtin_constant_p (@var{exp})
  You can use the built-in function @code{__builtin_constant_p} to
  determine if a value is known to be constant at compile-time and hence
Index: testsuite/gcc.dg/builtin-choose-expr.c
===================================================================
RCS file: builtin-choose-expr.c
diff -N builtin-choose-expr.c
*** /dev/null	Tue May  5 13:32:27 1998
--- builtin-choose-expr.c	Fri Dec  7 22:02:09 2001
***************
*** 0 ****
--- 1,68 ----
+ /* { dg-do run { target *-*-* } } */
+ /* { dg-options { "-O1" } } */
+ 
+ /* Assertion that the type of a conditional expression between E1 and E2
+   is T.  Checks the expression both ways round.  */
+ #define ASSERT_COND_TYPE(E1, E2, T)                     \
+         do {                                            \
+           typedef T type;                               \
+           typedef type **typepp;                        \
+           typedef __typeof(0 ? (E1) : (E2)) ctype;      \
+           typedef __typeof(0 ? (E2) : (E1)) ctype2;     \
+           typedef ctype **ctypepp;                      \
+           typedef ctype2 **ctype2pp;                    \
+           typepp x = 0;                                 \
+           ctypepp y = 0;                                \
+           ctype2pp z = 0;                               \
+           x = y;                                        \
+           x = z;                                        \
+         } while (0)
+ 
+ double dd, d;
+ char c;
+ float f;
+ 
+ struct S { int x, y; } pour, some, sugar;
+ 
+ extern void abort ();
+ extern void exit ();
+ 
+ void bad ()
+ {
+   abort ();
+ }
+ 
+ void good ()
+ {
+   exit (0);
+ }
+ 
+ int main (void)
+ {
+   if (__builtin_choose_expr (0, 12, 0)
+       || !__builtin_choose_expr (45, 5, 0)
+       || !__builtin_choose_expr (45, 3, 0))
+     abort ();
+ 
+   ASSERT_COND_TYPE (dd, __builtin_choose_expr (0, 35, d), double);
+ 
+   ASSERT_COND_TYPE (f,
+ 		    __builtin_choose_expr
+ 		    (__builtin_types_compatible_p (char, typeof (c)),
+ 		     3.14F, 's'),
+ 		    float);
+ 
+   pour.y = 69;
+   __builtin_choose_expr (0, bad (), sugar) = pour;
+   if (sugar.y != 69)
+     abort ();
+ 
+   __builtin_choose_expr (sizeof (int), f, bad ()) = 3.5F;
+ 
+   if (f != 3.5F)
+     abort ();
+ 
+   __builtin_choose_expr (1, good, bad)();
+ 
+   exit (0);
+ }
Index: testsuite/gcc.c-torture/execute/builtin-types-compatible-p.c
===================================================================
RCS file: builtin-types-compatible-p.c
diff -N builtin-types-compatible-p.c
*** /dev/null	Tue May  5 13:32:27 1998
--- builtin-types-compatible-p.c	Fri Dec  7 22:02:09 2001
***************
*** 0 ****
--- 1,30 ----
+ int i;
+ double d;
+ 
+ typedef enum { hot, dog, poo, bear } dingos;
+ typedef enum { janette, laura, amanda } cranberry;
+ 
+ typedef float same1;
+ typedef float same2;
+ 
+ int main (void);
+ 
+ int main (void)
+ {
+   /* Compatible types.  */
+   if (!(__builtin_types_compatible_p (int, const int)
+ 	&& __builtin_types_compatible_p (typeof (hot), int)
+ 	&& __builtin_types_compatible_p (typeof (hot), typeof (laura))
+ 	&& __builtin_types_compatible_p (same1, same2)))
+     abort ();
+ 
+   /* Incompatible types.  */
+   if (__builtin_types_compatible_p (char *, int)
+       || __builtin_types_compatible_p (long double, double)
+       || __builtin_types_compatible_p (typeof (i), typeof (d))
+       || __builtin_types_compatible_p (char, int)
+       || __builtin_types_compatible_p (typeof (dingos), typeof (cranberry))
+       || __builtin_types_compatible_p (char *, char **))
+     abort ();
+   exit (0);
+ }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]