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]

Re: builtins: choose_expr and types_compatible_p


after a few iterations with joseph, regarding docs and test cases, i
think this is it.

ok?

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 22:01:16
*************** 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.118
diff -c -p -r1.118 c-parse.in
*** c-parse.in	2001/12/08 12:01:52	1.118
--- c-parse.in	2001/12/08 22:01:17
*************** end ifobjc
*** 110,116 ****
  %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. */
--- 110,116 ----
  %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:
*** 670,675 ****
--- 670,695 ----
  		{ $$ = 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));
+ 
+ 		  $$ = comptypes (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[] =
*** 3224,3229 ****
--- 3244,3251 ----
    { "__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] =
*** 3395,3400 ****
--- 3417,3425 ----
    /* 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 22:01:18
*************** the same names as the standard macros ( 
*** 4388,4393 ****
--- 4388,4483 ----
  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 built-in function @code{__builtin_types_compatible_p} to
+ determine whether two types are the same.
+ 
+ This built-in function 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 built-in function can be
+ used in integer constant expressions.
+ 
+ This built-in function ignores top level qualifiers (e.g., @code{const},
+ @code{volatile}).  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 considered to be compatible with another
+ @code{enum} type.  For example, @code{enum @{foo, bar@}} is similar to
+ @code{enum @{hot, dog@}}.
+ 
+ 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
+ 
+ @emph{Note:} This construct is only available for C.
+ 
+ @end deftypefn
+ 
+ @deftypefn {Built-in Function} @var{type} __builtin_choose_expr (@var{const_exp}, @var{exp1}, @var{exp2})
+ 
+ You can use the built-in function @code{__builtin_choose_expr} to
+ evaluate code depending on the value of a constant expression.  This
+ built-in function returns @var{exp1} if @var{const_exp}, which is a
+ constant expression that must be able to be determined at compile time,
+ is nonzero.  Otherwise it returns 0.
+ 
+ This built-in function is analogous to the @samp{? :} operator in C,
+ except that the expression returned has its type unaltered by promotion
+ rules.  Also, the built-in function 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.
+ 
+ This built-in function can return an lvalue if the chosen argument is an
+ lvalue.
+ 
+ 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),                                                         \
+       /* @r{The void expression results in a compile-time error}             \
+          @r{when assigning the result to something.}  */                     \
+       (void)0))
+ @end smallexample
+ 
+ @emph{Note:} This construct is only available for C.  Furthermore, the
+ unused expression (@var{exp1} or @var{exp2} depending on the value of
+ @var{const_exp}) may still generate syntax errors.  This may change in
+ future revisions.
+ 
+ @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	Sat Dec  8 14:01:18 2001
***************
*** 0 ****
--- 1,88 ----
+ /* { dg-do run } */
+ /* { dg-options "-O1 -Wall" } */
+ 
+ #define choose __builtin_choose_expr
+ 
+ /* Check the type of __builtin_choose_expr between E1 and E2, both
+    ways round and with both 0 and 1 as the condition.  */
+ #define ASSERT_COND_TYPE(E1, E2)				\
+         do {							\
+           typedef __typeof(E1) T1;				\
+           typedef __typeof(E2) T2;				\
+           typedef T1 **T1pp;					\
+           typedef T2 **T2pp;					\
+           typedef __typeof(choose (1, (E1), (E2))) T1a;		\
+           typedef __typeof(choose (0, (E2), (E1))) T1b;		\
+           typedef __typeof(choose (1, (E2), (E1))) T2a;		\
+           typedef __typeof(choose (0, (E1), (E2))) T2b;		\
+           typedef T1a **T1app;					\
+           typedef T1b **T1bpp;					\
+           typedef T2a **T2app;					\
+           typedef T2b **T2bpp;					\
+           T1pp t1 = 0;						\
+           T2pp t2 = 0;						\
+           T1app t1a = 0;					\
+           T1bpp t1b = 0;					\
+           T2app t2a = 0;					\
+           T2bpp t2b = 0;					\
+           t1 = t1a;						\
+           t1 = t1b;						\
+           t2 = t2a;						\
+           t2 = t2b;						\
+         } while (0)
+ 
+ 
+ extern void abort ();
+ extern void exit ();
+ 
+ void bad ()
+ {
+   abort ();
+ }
+ 
+ void good ()
+ {
+   exit (0);
+ }
+ 
+ int main (void)
+ {
+   signed char sc1, sc2;
+   void *v1;
+   int i, j;
+   double dd;
+   float f;
+   typedef void (*fpt)(void);
+   fpt triple;
+   struct S { int x, y; } pour, some, sugar;
+   union u { int p; } united, nations;
+ 
+   if (__builtin_choose_expr (0, 12, 0)
+       || !__builtin_choose_expr (45, 5, 0)
+       || !__builtin_choose_expr (45, 3, 0))
+     abort ();
+ 
+   ASSERT_COND_TYPE (sc1, sc2);
+   ASSERT_COND_TYPE (v1, sc1);
+   ASSERT_COND_TYPE (i, j);
+   ASSERT_COND_TYPE (dd, main);
+   ASSERT_COND_TYPE ((float)dd, i);
+   ASSERT_COND_TYPE (4, f);
+   ASSERT_COND_TYPE (triple, some);
+   ASSERT_COND_TYPE (united, nations);
+   ASSERT_COND_TYPE (nations, main);
+ 
+   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	Sat Dec  8 14:01:18 2001
***************
*** 0 ****
--- 1,35 ----
+ int i;
+ double d;
+ 
+ /* Make sure we return a constant.  */
+ float rootbeer[__builtin_types_compatible_p (int, typeof(i))];
+ 
+ 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 (int[5], int[])
+ 	&& __builtin_types_compatible_p (typeof (dingos), typeof (cranberry))
+ 	&& __builtin_types_compatible_p (same1, same2)))
+     abort ();
+ 
+   /* Incompatible types.  */
+   if (__builtin_types_compatible_p (char *, int)
+       || __builtin_types_compatible_p (char *, const char *)
+       || __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 (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]