OSDN Git Service

* alias.c (nonlocal_reference_p): Take a care for
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 13 Apr 2000 13:59:00 +0000 (13:59 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 13 Apr 2000 13:59:00 +0000 (13:59 +0000)
CALL_INSNS's fusage field.
* calls.c (ECF_PURE): New flag.
(emit_call_1): Handle ECF_PURE calls.
(initialize_argument_information): Unset ECF_PURE flag too.
(precompute_arguments): Precompute for ECF_PURE too.
(expand_call): Handle ECF_PURE calls too.
(emit_library_call_value_1): Rename no_queue argument to
fn_type, accept value of 2 as pure function.
(emit_library_call_value, emit_library_call): Rename no_queue argument
to fn_type.
* optabs.c (prepare_cmp_insn): Pass fn_type 2 to memcmp call.

* tree.h (DECL_IS_PURE): New macro.
(struct tree_decl): Add pure_flag.
* c-common.c (enum attrs): Add attribute "pure".
(init_attributes): Initialize attribute "pure"
(decl_attributes): Handle attribute "pure".
* extend.texi (Attribute "pure"): Document.
* calls.c (expand_call): Add (mem:BLK (scratch)) to "equal from"
in pure function.
(flags_from_decl_or_type): Support attribute "pure".

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@33138 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/alias.c
gcc/c-common.c
gcc/calls.c
gcc/extend.texi
gcc/optabs.c
gcc/tree.h

index 87c0522..ad5c15d 100644 (file)
@@ -1,3 +1,28 @@
+Thu Apr 13 15:55:08 MET DST 2000  Jan Hubicka  <jh@suse.cz>
+
+       * alias.c (nonlocal_reference_p): Take a care for
+       CALL_INSNS's fusage field.
+       * calls.c (ECF_PURE): New flag.
+       (emit_call_1): Handle ECF_PURE calls.
+       (initialize_argument_information): Unset ECF_PURE flag too.
+       (precompute_arguments): Precompute for ECF_PURE too.
+       (expand_call): Handle ECF_PURE calls too.
+       (emit_library_call_value_1): Rename no_queue argument to
+       fn_type, accept value of 2 as pure function.
+       (emit_library_call_value, emit_library_call): Rename no_queue argument
+       to fn_type.
+       * optabs.c (prepare_cmp_insn): Pass fn_type 2 to memcmp call.
+
+       * tree.h (DECL_IS_PURE): New macro.
+       (struct tree_decl): Add pure_flag.
+       * c-common.c (enum attrs): Add attribute "pure".
+       (init_attributes): Initialize attribute "pure"
+       (decl_attributes): Handle attribute "pure".
+       * extend.texi (Attribute "pure"): Document.
+       * calls.c (expand_call): Add (mem:BLK (scratch)) to "equal from"
+       in pure function.
+       (flags_from_decl_or_type): Support attribute "pure".
+
 2000-04-13  Jason Merrill  <jason@casey.cygnus.com>
 
        * cpplex.c (_cpp_lex_token): Handle digraphs.  Don't null-terminate
index db89ecc..fb493f8 100644 (file)
@@ -1424,10 +1424,15 @@ nonlocal_reference_p (x)
 
   if (GET_RTX_CLASS (code) == 'i')
     {
-      /* Constant functions are constant.  */
+      /* Constant functions can be constant if they don't use
+         scratch memory used to mark function w/o side effects.  */
       if (code == CALL_INSN && CONST_CALL_P (x))
-       return 0;
-      x = PATTERN (x);
+        {
+         x = CALL_INSN_FUNCTION_USAGE (x);
+         if (!x) return 0;
+        }
+      else
+        x = PATTERN (x);
       code = GET_CODE (x);
     }
 
@@ -1520,7 +1525,7 @@ nonlocal_reference_p (x)
     
     for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
       {
-       if (fmt[i] == 'e')
+       if (fmt[i] == 'e' && XEXP (x, i))
          {
            if (nonlocal_reference_p (XEXP (x, i)))
              return 1;
index 97aba25..1033035 100644 (file)
@@ -145,7 +145,7 @@ enum attrs {A_PACKED, A_NOCOMMON, A_COMMON, A_NORETURN, A_CONST, A_T_UNION,
            A_NO_CHECK_MEMORY_USAGE, A_NO_INSTRUMENT_FUNCTION,
            A_CONSTRUCTOR, A_DESTRUCTOR, A_MODE, A_SECTION, A_ALIGNED,
            A_UNUSED, A_FORMAT, A_FORMAT_ARG, A_WEAK, A_ALIAS, A_MALLOC,
-           A_NO_LIMIT_STACK};
+           A_NO_LIMIT_STACK, A_PURE};
 
 enum format_type { printf_format_type, scanf_format_type,
                   strftime_format_type };
@@ -457,6 +457,7 @@ init_attributes ()
   add_attribute (A_NO_CHECK_MEMORY_USAGE, "no_check_memory_usage", 0, 0, 1);
   add_attribute (A_MALLOC, "malloc", 0, 0, 1);
   add_attribute (A_NO_LIMIT_STACK, "no_stack_limit", 0, 0, 1);
+  add_attribute (A_PURE, "pure", 0, 0, 1);
 }
 \f
 /* Default implementation of valid_lang_attribute, below.  By default, there
@@ -596,6 +597,7 @@ decl_attributes (node, attributes, prefix_attributes)
        case A_MALLOC:
          if (TREE_CODE (decl) == FUNCTION_DECL)
            DECL_IS_MALLOC (decl) = 1;
+         /* ??? TODO: Support types.  */
          else
            warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
          break;
@@ -625,6 +627,15 @@ decl_attributes (node, attributes, prefix_attributes)
            warning ( "`%s' attribute ignored", IDENTIFIER_POINTER (name));
          break;
 
+       case A_PURE:
+         if (TREE_CODE (decl) == FUNCTION_DECL)
+           DECL_IS_PURE (decl) = 1;
+         /* ??? TODO: Support types.  */
+         else
+           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+         break;
+
+
        case A_T_UNION:
          if (is_type
              && TREE_CODE (type) == UNION_TYPE
index 6424955..2592a8e 100644 (file)
@@ -168,6 +168,9 @@ static int calls_function_1 PARAMS ((tree, int));
    the current one.  */
 #define ECF_FORK_OR_EXEC       128
 #define ECF_SIBCALL            256
+/* Nonzero if this is a call to "pure" function (like const function,
+   but may read memory.  */
+#define ECF_PURE               512
 
 static void emit_call_1                PARAMS ((rtx, tree, tree, HOST_WIDE_INT,
                                         HOST_WIDE_INT, HOST_WIDE_INT, rtx,
@@ -555,6 +558,15 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
   if (! call_insn)
     abort ();
 
+  /* Mark memory as used for "pure" function call.  */
+  if (ecf_flags & ECF_PURE)
+    {
+      call_fusage =  gen_rtx_EXPR_LIST (VOIDmode,
+       gen_rtx_USE (VOIDmode,
+                    gen_rtx_MEM (BLKmode,
+                                 gen_rtx_SCRATCH (VOIDmode))), call_fusage);
+    }
+
   /* Put the register usage information on the CALL.  If there is already
      some usage information, put ours at the end.  */
   if (CALL_INSN_FUNCTION_USAGE (call_insn))
@@ -571,7 +583,7 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
     CALL_INSN_FUNCTION_USAGE (call_insn) = call_fusage;
 
   /* If this is a const call, then set the insn's unchanging bit.  */
-  if (ecf_flags & ECF_CONST)
+  if (ecf_flags & (ECF_CONST | ECF_PURE))
     CONST_CALL_P (call_insn) = 1;
 
   /* If this call can't throw, attach a REG_EH_REGION reg note to that
@@ -610,7 +622,7 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
       if (rounded_stack_size != 0)
        {
          if (flag_defer_pop && inhibit_defer_pop == 0
-             && !(ecf_flags & ECF_CONST))
+             && !(ecf_flags & (ECF_CONST | ECF_PURE)))
            pending_stack_adjust += rounded_stack_size;
          else
            adjust_stack (rounded_stack_size_rtx);
@@ -759,6 +771,10 @@ flags_from_decl_or_type (exp)
       if (DECL_P (exp) && DECL_IS_MALLOC (exp))
        flags |= ECF_MALLOC;
 
+      /* The function exp may have the `pure' attribute.  */
+      if (DECL_P (exp) && DECL_IS_PURE (exp))
+       flags |= ECF_PURE;
+
       if (TREE_NOTHROW (exp))
        flags |= ECF_NOTHROW;
     }
@@ -1195,7 +1211,7 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args,
              MEM_SET_IN_STRUCT_P (copy, AGGREGATE_TYPE_P (type));
 
              store_expr (args[i].tree_value, copy, 0);
-             *ecf_flags &= ~ECF_CONST;
+             *ecf_flags &= ~(ECF_CONST | ECF_PURE);
 
              args[i].tree_value = build1 (ADDR_EXPR,
                                           build_pointer_type (type),
@@ -1254,7 +1270,7 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args,
       /* If this is an addressable type, we cannot pre-evaluate it.  Thus,
         we cannot consider this function call constant.  */
       if (TREE_ADDRESSABLE (type))
-       *ecf_flags &= ~ECF_CONST;
+       *ecf_flags &= ~(ECF_CONST | ECF_PURE);
 
       /* Compute the stack-size of this argument.  */
       if (args[i].reg == 0 || args[i].partial != 0
@@ -1435,7 +1451,7 @@ precompute_arguments (flags, must_preallocate, num_actuals, args, args_size)
      which have already been stored into the stack.  */
 
   for (i = 0; i < num_actuals; i++)
-    if ((flags & ECF_CONST)
+    if ((flags & (ECF_CONST | ECF_PURE))
        || ((args_size->var != 0 || args_size->constant != 0)
            && calls_function (args[i].tree_value, 1))
        || (must_preallocate
@@ -2038,7 +2054,7 @@ expand_call (exp, target, ignore)
   if (aggregate_value_p (exp))
     {
       /* This call returns a big structure.  */
-      flags &= ~ECF_CONST;
+      flags &= ~(ECF_CONST | ECF_PURE);
 
 #ifdef PCC_STATIC_STRUCT_RETURN
       {
@@ -2295,7 +2311,7 @@ expand_call (exp, target, ignore)
 
       /* When calling a const function, we must pop the stack args right away,
         so that the pop is deleted or moved with the call.  */
-      if (flags & ECF_CONST)
+      if (flags & (ECF_CONST | ECF_PURE))
        NO_DEFER_POP;
 
       /* Don't let pending stack adjusts add up to too much.
@@ -2416,7 +2432,7 @@ expand_call (exp, target, ignore)
 
             Also do not make a sibling call.  */
 
-         flags &= ~ECF_CONST;
+         flags &= ~(ECF_CONST | ECF_PURE);
          must_preallocate = 1;
          sibcall_failure = 1;
        }
@@ -2470,7 +2486,7 @@ expand_call (exp, target, ignore)
 
       /* Now we are about to start emitting insns that can be deleted
         if a libcall is deleted.  */
-      if (flags & (ECF_CONST | ECF_MALLOC))
+      if (flags & (ECF_CONST | ECF_PURE | ECF_MALLOC))
        start_sequence ();
 
       old_stack_allocated =  stack_pointer_delta - pending_stack_adjust;
@@ -2653,7 +2669,7 @@ expand_call (exp, target, ignore)
        {
          /* When the stack adjustment is pending, we get better code
             by combining the adjustments.  */
-         if (pending_stack_adjust && ! (flags & ECF_CONST)
+         if (pending_stack_adjust && ! (flags & (ECF_CONST | ECF_PURE))
              && ! inhibit_defer_pop)
            {
              int adjust;
@@ -2821,7 +2837,8 @@ expand_call (exp, target, ignore)
         Test valreg so we don't crash; may safely ignore `const'
         if return type is void.  Disable for PARALLEL return values, because
         we have no way to move such values into a pseudo register.  */
-      if ((flags & ECF_CONST) && valreg != 0 && GET_CODE (valreg) != PARALLEL)
+      if ((flags & (ECF_CONST | ECF_PURE))
+         && valreg != 0 && GET_CODE (valreg) != PARALLEL)
        {
          rtx note = 0;
          rtx temp = gen_reg_rtx (GET_MODE (valreg));
@@ -2840,11 +2857,17 @@ expand_call (exp, target, ignore)
          insns = get_insns ();
          end_sequence ();
 
+         if (flags & ECF_PURE)
+           note = gen_rtx_EXPR_LIST (VOIDmode,
+              gen_rtx_USE (VOIDmode,
+                           gen_rtx_MEM (BLKmode,
+                                        gen_rtx_SCRATCH (VOIDmode))), note);
+
          emit_libcall_block (insns, temp, valreg, note);
   
          valreg = temp;
        }
-      else if (flags & ECF_CONST)
+      else if (flags & (ECF_CONST | ECF_PURE))
        {
          /* Otherwise, just write out the sequence without a note.  */
          rtx insns = get_insns ();
@@ -3171,11 +3194,11 @@ libfunc_nothrow (fun)
    The RETVAL parameter specifies whether return value needs to be saved, other 
    parameters are documented in the emit_library_call function bellow.  */
 static rtx
-emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
+emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
      int retval;
      rtx orgfun;
      rtx value;
-     int no_queue;
+     int fn_type;
      enum machine_mode outmode;
      int nargs;
      va_list p;
@@ -3223,8 +3246,10 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
 #endif
 #endif
 
-  if (no_queue)
+  if (fn_type == 1)
     flags |= ECF_CONST;
+  else if (fn_type == 2)
+    flags |= ECF_PURE;
   fun = orgfun;
 
   if (libfunc_nothrow (fun))
@@ -3258,7 +3283,7 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
 #endif
 
       /* This call returns a big structure.  */
-      flags &= ~ECF_CONST;
+      flags &= ~(ECF_CONST | ECF_PURE);
     }
 
   /* ??? Unfinished: must pass the memory address as an argument.  */
@@ -3282,7 +3307,7 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
 
   /* Now we are about to start emitting insns that can be deleted
      if a libcall is deleted.  */
-  if (flags & ECF_CONST)
+  if (flags & (ECF_CONST | ECF_PURE))
     start_sequence ();
 
   push_temp_slots ();
@@ -3726,7 +3751,7 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
      Test valreg so we don't crash; may safely ignore `const'
      if return type is void.  Disable for PARALLEL return values, because
      we have no way to move such values into a pseudo register.  */
-  if ((flags & ECF_CONST)
+  if ((flags & (ECF_CONST | ECF_PURE))
       && valreg != 0 && GET_CODE (valreg) != PARALLEL)
     {
       rtx note = 0;
@@ -3743,11 +3768,17 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
       insns = get_insns ();
       end_sequence ();
 
+      if (flags & ECF_PURE)
+       note = gen_rtx_EXPR_LIST (VOIDmode,
+          gen_rtx_USE (VOIDmode,
+                       gen_rtx_MEM (BLKmode,
+                                    gen_rtx_SCRATCH (VOIDmode))), note);
+
       emit_libcall_block (insns, temp, valreg, note);
 
       valreg = temp;
     }
-  else if (flags & ECF_CONST)
+  else if (flags & (ECF_CONST | ECF_PURE))
     {
       /* Otherwise, just write out the sequence without a note.  */
       rtx insns = get_insns ();
@@ -3830,26 +3861,18 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
    and machine_modes to convert them to.
    The rtx values should have been passed through protect_from_queue already.
 
-   NO_QUEUE will be true if and only if the library call is a `const' call
-   which will be enclosed in REG_LIBCALL/REG_RETVAL notes; it is equivalent
-   to the flag ECF_CONST in expand_call.
-
-   NO_QUEUE must be true for const calls, because if it isn't, then
-   any pending increment will be emitted between REG_LIBCALL/REG_RETVAL notes,
-   and will be lost if the libcall sequence is optimized away.
-
-   NO_QUEUE must be false for non-const calls, because if it isn't, the
-   call insn will have its CONST_CALL_P bit set, and it will be incorrectly
-   optimized.  For instance, the instruction scheduler may incorrectly
-   move memory references across the non-const call.  */
+   FN_TYPE will is zero for `normal' calls, one for `const' calls, wich
+   which will be enclosed in REG_LIBCALL/REG_RETVAL notes and two for `pure'
+   calls, that are handled like `const' calls with extra
+   (use (memory (scratch)).  */
 
 void
-emit_library_call VPARAMS((rtx orgfun, int no_queue, enum machine_mode outmode,
+emit_library_call VPARAMS((rtx orgfun, int fn_type, enum machine_mode outmode,
                           int nargs, ...))
 {
 #ifndef ANSI_PROTOTYPES
   rtx orgfun;
-  int no_queue;
+  int fn_type;
   enum machine_mode outmode;
   int nargs;
 #endif
@@ -3859,12 +3882,12 @@ emit_library_call VPARAMS((rtx orgfun, int no_queue, enum machine_mode outmode,
 
 #ifndef ANSI_PROTOTYPES
   orgfun = va_arg (p, rtx);
-  no_queue = va_arg (p, int);
+  fn_type = va_arg (p, int);
   outmode = va_arg (p, enum machine_mode);
   nargs = va_arg (p, int);
 #endif
 
-  emit_library_call_value_1 (0, orgfun, NULL_RTX, no_queue, outmode, nargs, p);
+  emit_library_call_value_1 (0, orgfun, NULL_RTX, fn_type, outmode, nargs, p);
 
   va_end (p);
 }
@@ -3878,13 +3901,13 @@ emit_library_call VPARAMS((rtx orgfun, int no_queue, enum machine_mode outmode,
    If VALUE is nonzero, VALUE is returned.  */
 
 rtx
-emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
+emit_library_call_value VPARAMS((rtx orgfun, rtx value, int fn_type,
                                 enum machine_mode outmode, int nargs, ...))
 {
 #ifndef ANSI_PROTOTYPES
   rtx orgfun;
   rtx value;
-  int no_queue;
+  int fn_type;
   enum machine_mode outmode;
   int nargs;
 #endif
@@ -3895,12 +3918,12 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
 #ifndef ANSI_PROTOTYPES
   orgfun = va_arg (p, rtx);
   value = va_arg (p, rtx);
-  no_queue = va_arg (p, int);
+  fn_type = va_arg (p, int);
   outmode = va_arg (p, enum machine_mode);
   nargs = va_arg (p, int);
 #endif
 
-  value = emit_library_call_value_1 (1, orgfun, value, no_queue, outmode, nargs, p);
+  value = emit_library_call_value_1 (1, orgfun, value, fn_type, outmode, nargs, p);
 
   va_end (p);
 
index 4cce201..22fe741 100644 (file)
@@ -1379,22 +1379,44 @@ typedef void voidfn ();
 volatile voidfn fatal;
 @end smallexample
 
-@cindex @code{const} function attribute
-@item const
-Many functions do not examine any values except their arguments, and
-have no effects except the return value.  Such a function can be subject
+@cindex @code{pure} function attribute
+@item pure
+Many functions have no effects except the return value and their
+return value and depends only on the parameters and/or global variables.
+Such a function can be subject
 to common subexpression elimination and loop optimization just as an
 arithmetic operator would be.  These functions should be declared
-with the attribute @code{const}.  For example,
+with the attribute @code{pure}.  For example,
 
 @smallexample
-int square (int) __attribute__ ((const));
+int square (int) __attribute__ ((pure));
 @end smallexample
 
 @noindent
 says that the hypothetical function @code{square} is safe to call
 fewer times than the program says.
 
+Some of common examples of pure functions are @code{strlen} or @code{memcmp}.
+Interesting non-pure functions are functions with infinite loops or those
+depending on volatile memory or other system resource, that may change between
+two consetuctive calls (such as @code{feof} in multithreding environment).
+
+The attribute @code{pure} is not implemented in GNU C versions earlier
+than 2.96.
+@cindex @code{const} function attribute
+@item const
+Many functions do not examine any values except their arguments, and
+have no effects except the return value.  Basically this is just slightly
+more strict class than the "pure" attribute above, since function is not
+alloved to read global memory.
+
+@cindex pointer arguments
+Note that a function that has pointer arguments and examines the data
+pointed to must @emph{not} be declared @code{const}.  Likewise, a
+function that calls a non-@code{const} function usually must not be
+@code{const}.  It does not make sense for a @code{const} function to
+return @code{void}.
+
 The attribute @code{const} is not implemented in GNU C versions earlier
 than 2.5.  An alternative way to declare that a function has no side
 effects, which works in the current version and in some older versions,
@@ -1409,12 +1431,6 @@ extern const intfn square;
 This approach does not work in GNU C++ from 2.6.0 on, since the language
 specifies that the @samp{const} must be attached to the return value.
 
-@cindex pointer arguments
-Note that a function that has pointer arguments and examines the data
-pointed to must @emph{not} be declared @code{const}.  Likewise, a
-function that calls a non-@code{const} function usually must not be
-@code{const}.  It does not make sense for a @code{const} function to
-return @code{void}.
 
 @item format (@var{archetype}, @var{string-index}, @var{first-to-check})
 @cindex @code{format} function attribute
index dbdea04..85bb24e 100644 (file)
@@ -3020,14 +3020,14 @@ prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, align,
 #endif
        {
 #ifdef TARGET_MEM_FUNCTIONS
-         emit_library_call (memcmp_libfunc, 0,
+         emit_library_call (memcmp_libfunc, 2,
                             TYPE_MODE (integer_type_node), 3,
                             XEXP (x, 0), Pmode, XEXP (y, 0), Pmode,
                             convert_to_mode (TYPE_MODE (sizetype), size,
                                              TREE_UNSIGNED (sizetype)),
                             TYPE_MODE (sizetype));
 #else
-         emit_library_call (bcmp_libfunc, 0,
+         emit_library_call (bcmp_libfunc, 2,
                             TYPE_MODE (integer_type_node), 3,
                             XEXP (x, 0), Pmode, XEXP (y, 0), Pmode,
                             convert_to_mode (TYPE_MODE (integer_type_node),
index 0332102..9c426fa 100644 (file)
@@ -1253,6 +1253,10 @@ struct tree_type
    not an alias.  */
 #define DECL_IS_MALLOC(NODE) (FUNCTION_DECL_CHECK (NODE)->decl.malloc_flag)
 
+/* Nonzero in a FUNCTION_DECL means this function should be treated
+   as "pure" function (like const function, but may read global memory).  */
+#define DECL_IS_PURE(NODE) (FUNCTION_DECL_CHECK (NODE)->decl.pure_flag)
+
 /* Nonzero in a FIELD_DECL means it is a bit field, and must be accessed
    specially.  */
 #define DECL_BIT_FIELD(NODE) (FIELD_DECL_CHECK (NODE)->decl.bit_field_flag)
@@ -1392,6 +1396,7 @@ struct tree_decl
   unsigned comdat_flag : 1;
   unsigned malloc_flag : 1;
   unsigned no_limit_stack : 1;
+  unsigned pure_flag : 1;
 #ifdef ONLY_INT_FIELDS
   unsigned int built_in_class : 2;
 #else