diff mbox

[SPARC] Hookize PRINT_OPERAND, PRINT_OPERAND_ADDRESS and PRINT_OPERAND_PUNCT_VALID_P

Message ID 9410569723.20110427221316@post.ru
State New
Headers show

Commit Message

Anatoly Sokolov April 27, 2011, 6:13 p.m. UTC
Hello.

  This patch removes obsolete PRINT_OPERAND, PRINT_OPERAND_ADDRESS and
PRINT_OPERAND_PUNCT_VALID_P macros from SPARC back end in the GCC and 
introduces equivalent TARGET_PRINT_OPERAND, TARGET_PRINT_OPERAND_ADDRESS and 
TARGET_PRINT_OPERAND_PUNCT_VALID_P target hooks. 


   Bootstrapped and regression tested on sparc64-unknown-linux-gnu.

  OK to install?

        * config/sparc/sparc.h (PRINT_OPERAND, PRINT_OPERAND_ADDRESS,
        PRINT_OPERAND_PUNCT_VALID_P): Remove.
        * config/sparc/sparc-protos.h (print_operand): Remove declaration.
        * config/sparc/sparc.c (TARGET_PRINT_OPERAND_PUNCT_VALID_P,
        TARGET_PRINT_OPERAND, TARGET_PRINT_OPERAND_ADDRESS): Define.
        (print_operand): Rename to...
        (sparc_print_operand): ...this. Make static. Adjust
        sparc_print_operand function call.
        (sparc_print_operand_punct_valid_p, sparc_print_operand_address): New
        functions.



Anatoly.

Comments

Richard Henderson April 28, 2011, 3:52 p.m. UTC | #1
On 04/27/2011 11:13 AM, Anatoly Sokolov wrote:
>         * config/sparc/sparc.h (PRINT_OPERAND, PRINT_OPERAND_ADDRESS,
>         PRINT_OPERAND_PUNCT_VALID_P): Remove.
>         * config/sparc/sparc-protos.h (print_operand): Remove declaration.
>         * config/sparc/sparc.c (TARGET_PRINT_OPERAND_PUNCT_VALID_P,
>         TARGET_PRINT_OPERAND, TARGET_PRINT_OPERAND_ADDRESS): Define.
>         (print_operand): Rename to...
>         (sparc_print_operand): ...this. Make static. Adjust
>         sparc_print_operand function call.
>         (sparc_print_operand_punct_valid_p, sparc_print_operand_address): New
>         functions.

Ok, except, 

> +  if(code == '#'

Space before (, re-indenting the rest of the condition to match.


r~
Rainer Orth May 3, 2011, 6:55 p.m. UTC | #2
Richard Henderson <rth@redhat.com> writes:

> On 04/27/2011 11:13 AM, Anatoly Sokolov wrote:
>>         * config/sparc/sparc.h (PRINT_OPERAND, PRINT_OPERAND_ADDRESS,
>>         PRINT_OPERAND_PUNCT_VALID_P): Remove.
>>         * config/sparc/sparc-protos.h (print_operand): Remove declaration.
>>         * config/sparc/sparc.c (TARGET_PRINT_OPERAND_PUNCT_VALID_P,
>>         TARGET_PRINT_OPERAND, TARGET_PRINT_OPERAND_ADDRESS): Define.
>>         (print_operand): Rename to...
>>         (sparc_print_operand): ...this. Make static. Adjust
>>         sparc_print_operand function call.
>>         (sparc_print_operand_punct_valid_p, sparc_print_operand_address): New
>>         functions.
>
> Ok, except, 
>
>> +  if(code == '#'
>
> Space before (, re-indenting the rest of the condition to match.

This patch broke Solaris 2/SPARC bootstrap which still uses
print_operand in sparc/sol2.h (ASM_OUTPUT_CALL).  A bootstrap with the
obvious fix is currently running.

What is so hard about running grep when removing/renaming symbols???

	Rainer
Joseph Myers May 3, 2011, 7:15 p.m. UTC | #3
On Tue, 3 May 2011, Rainer Orth wrote:

> This patch broke Solaris 2/SPARC bootstrap which still uses
> print_operand in sparc/sol2.h (ASM_OUTPUT_CALL).  A bootstrap with the
> obvious fix is currently running.
> 
> What is so hard about running grep when removing/renaming symbols???

Generically, the presence of lots of nonobvious places that may turn out 
to use a symbol - ada/gcc-interface/, go/gofrontend, config/ for what one 
thinks of as front-end symbols, libgcc/ and other places outside of gcc/ 
(being outside gcc/ is probably how the remaining use of ROUND_TYPE_SIZE 
in libobjc was missed when that macro was removed from GCC in 2003), C 
symbols used directly in Ada source code, ....  The ongoing work on 
narrowing interfaces (so that it's well-defined whether particular headers 
are used for the host or the target, tm.h isn't included in so many 
places, etc.) may help - though another thing to watch out for there is 
random declarations in .c files or inappropriate headers that mean that 
something uses a symbol from some part of the compiler despite not 
including the normal header that declares it (I found plenty of such cases 
when making options variables into macros).  Help in cleaning up 
interfaces is always welcome - there's a lot to do 
(<http://gcc.gnu.org/wiki/Top-Level_Libgcc_Migration> has notes dealing 
with the very narrow area of target macros in code built for the target).
Rainer Orth May 4, 2011, 11:49 a.m. UTC | #4
"Joseph S. Myers" <joseph@codesourcery.com> writes:

>> What is so hard about running grep when removing/renaming symbols???
>
> Generically, the presence of lots of nonobvious places that may turn out 
> to use a symbol - ada/gcc-interface/, go/gofrontend, config/ for what one 
> thinks of as front-end symbols, libgcc/ and other places outside of gcc/ 
> (being outside gcc/ is probably how the remaining use of ROUND_TYPE_SIZE 
> in libobjc was missed when that macro was removed from GCC in 2003), C 
> symbols used directly in Ada source code, ....  The ongoing work on 
> narrowing interfaces (so that it's well-defined whether particular headers 
> are used for the host or the target, tm.h isn't included in so many 
> places, etc.) may help - though another thing to watch out for there is 
> random declarations in .c files or inappropriate headers that mean that 
> something uses a symbol from some part of the compiler despite not 
> including the normal header that declares it (I found plenty of such cases 
> when making options variables into macros).  Help in cleaning up 
> interfaces is always welcome - there's a lot to do 
> (<http://gcc.gnu.org/wiki/Top-Level_Libgcc_Migration> has notes dealing 
> with the very narrow area of target macros in code built for the target).

certainly true in general, although grep -r over the whole tree isn't
too hard to use either ;-)  But in the case at hand, 

$ grep print_operand *

in gcc/config/sparc would have turned up the problem at once, that's why
I'm complaining.

Your expansion of the wiki page on toplevel libgcc migration is
certainly welcome: I hadn't seen before that *-unwind.h files and
related macros can be moved over as well.

Thanks.
	Rainer
Joseph Myers May 4, 2011, noon UTC | #5
On Wed, 4 May 2011, Rainer Orth wrote:

> Your expansion of the wiki page on toplevel libgcc migration is
> certainly welcome: I hadn't seen before that *-unwind.h files and
> related macros can be moved over as well.

I've no idea whether they can be moved *at present*, but certainly the 
eventual aim should be to move them.

Before more macros are moved to files in libgcc/config I'd really rather 
the libgcc headers go in a separate libgcc_tm_file or similar, not 
included on the host and with the moved macros poisoned in the host 
system.h, to avoid the situation listed on that page of "RENAME_LIBRARY 
(in gcc/config/arm/symbian.h, otherwise moved to libgcc headers)" where a 
macro is only partly migrated to the libgcc headers but this partial state 
isn't obvious.  This has the advantage of avoiding the 
../../libgcc/config/ kludge in tm_file as well.
Rainer Orth May 26, 2011, 11:05 a.m. UTC | #6
"Joseph S. Myers" <joseph@codesourcery.com> writes:

> On Wed, 4 May 2011, Rainer Orth wrote:
>
>> Your expansion of the wiki page on toplevel libgcc migration is
>> certainly welcome: I hadn't seen before that *-unwind.h files and
>> related macros can be moved over as well.
>
> I've no idea whether they can be moved *at present*, but certainly the 
> eventual aim should be to move them.
>
> Before more macros are moved to files in libgcc/config I'd really rather 
> the libgcc headers go in a separate libgcc_tm_file or similar, not 
> included on the host and with the moved macros poisoned in the host 
> system.h, to avoid the situation listed on that page of "RENAME_LIBRARY 
> (in gcc/config/arm/symbian.h, otherwise moved to libgcc headers)" where a 
> macro is only partly migrated to the libgcc headers but this partial state 
> isn't obvious.  This has the advantage of avoiding the 
> ../../libgcc/config/ kludge in tm_file as well.

But doesn't this mean that e.g. MD_UNWIND_SUPPORT can only be moved to
libgcc/config for all targets together?  How can you poison the macro
when a single target using it is left behind in gcc/config?

To actually test such a move, one had to setup complete
cross-environments for every affected target, which is way beyond what I
have the time and inclination to do.  This would mean that even targets
where the toplevel libgcc move could be completed and the maintainers
are motivated to do so are stalled until all other related ones are
done.  Doesn't seem highly desirable to me.

	Rainer
Joseph Myers May 26, 2011, 12:18 p.m. UTC | #7
On Thu, 26 May 2011, Rainer Orth wrote:

> But doesn't this mean that e.g. MD_UNWIND_SUPPORT can only be moved to
> libgcc/config for all targets together?  How can you poison the macro
> when a single target using it is left behind in gcc/config?

Nothing about the libgcc_tm.h implementation stops you moving a macro 
(that is not, in fact, used on the host) for only some targets if you 
don't poison it.  But I do think moving it for all targets together, and 
poisoning it, is much better.

> To actually test such a move, one had to setup complete
> cross-environments for every affected target, which is way beyond what I
> have the time and inclination to do.  This would mean that even targets
> where the toplevel libgcc move could be completed and the maintainers
> are motivated to do so are stalled until all other related ones are
> done.  Doesn't seem highly desirable to me.

Well, no, you post the patch (I'd guess all thirty or so target-only 
macros could be moved in a few hours, but moving them in smaller groups 
might be easier), test on the targets you can readily test on (building 
just cc1 and xgcc for the others), invite target maintainers (CC:ed) to 
test for other targets and seek approval to commit in maybe a week in the 
absence of problem reports from target maintainers.

I think completing the move for a particular macro is more meaningful, and 
has a better way to ensure the move doesn't regress, than completing it 
for a particular target.
Rainer Orth May 26, 2011, 12:30 p.m. UTC | #8
"Joseph S. Myers" <joseph@codesourcery.com> writes:

> On Thu, 26 May 2011, Rainer Orth wrote:
>
>> But doesn't this mean that e.g. MD_UNWIND_SUPPORT can only be moved to
>> libgcc/config for all targets together?  How can you poison the macro
>> when a single target using it is left behind in gcc/config?
>
> Nothing about the libgcc_tm.h implementation stops you moving a macro 
> (that is not, in fact, used on the host) for only some targets if you 
> don't poison it.  But I do think moving it for all targets together, and 
> poisoning it, is much better.

Ok, I see.  It sounded to me as you wanted to somehow
discourage/prohibit those partial moves by policy.  Clearly achieving
some consistency here is a laudable goal and far better than having just
another incomplete transition that lingers forever.

>> To actually test such a move, one had to setup complete
>> cross-environments for every affected target, which is way beyond what I
>> have the time and inclination to do.  This would mean that even targets
>> where the toplevel libgcc move could be completed and the maintainers
>> are motivated to do so are stalled until all other related ones are
>> done.  Doesn't seem highly desirable to me.
>
> Well, no, you post the patch (I'd guess all thirty or so target-only 
> macros could be moved in a few hours, but moving them in smaller groups 
> might be easier), test on the targets you can readily test on (building 
> just cc1 and xgcc for the others), invite target maintainers (CC:ed) to 
> test for other targets and seek approval to commit in maybe a week in the 
> absence of problem reports from target maintainers.

Ok, that sounds doable.  AFAICS, the only ones of interest to my targets
are MD_UNWIND_SUPPORT and ENABLE_EXECUTE_STACK.  I'll probably do those
separately once the basic toplevel libgcc moves for Solaris, Tru64 UNIX
and IRIX are in.

Right now, I'm close for Solaris, but just noticed that
sparc/sol2-c[in].asm are used by sparc*-elf and sparc*-rtems, too, so
I'll have to deal with them as well before sparc*-*-solaris2* can be done.
The other two are pratically done, but rely on the Solaris move to go in
first.

> I think completing the move for a particular macro is more meaningful, and 
> has a better way to ensure the move doesn't regress, than completing it 
> for a particular target.

On the other hand, doing it per target has the advantage that you can
easily test the whole beast once, detect may cleanup opportunities, and
be done with it, rather than redoing the stuff on a per-macro basis.
But my targets above indicate that the number of macros per target may
actually be quite small.

	Rainer
diff mbox

Patch

Index: gcc/config/sparc/sparc-protos.h
===================================================================
--- gcc/config/sparc/sparc-protos.h     (revision 172733)
+++ gcc/config/sparc/sparc-protos.h     (working copy)
@@ -76,7 +76,6 @@ 
 extern const char *output_probe_stack_range (rtx, rtx);
 extern bool emit_scc_insn (rtx []);
 extern void emit_conditional_branch_insn (rtx []);
-extern void print_operand (FILE *, rtx, int);
 extern int mems_ok_for_ldd_peep (rtx, rtx, rtx);
 extern int arith_double_4096_operand (rtx, enum machine_mode);
 extern int arith_4096_operand (rtx, enum machine_mode);
Index: gcc/config/sparc/sparc.c
===================================================================
--- gcc/config/sparc/sparc.c    (revision 172733)
+++ gcc/config/sparc/sparc.c    (working copy)
@@ -468,6 +468,9 @@ 
 static void sparc_trampoline_init (rtx, tree, rtx);
 static enum machine_mode sparc_preferred_simd_mode (enum machine_mode);
 static reg_class_t sparc_preferred_reload_class (rtx x, reg_class_t rclass);
+static bool sparc_print_operand_punct_valid_p (unsigned char);
+static void sparc_print_operand (FILE *, rtx, int);
+static void sparc_print_operand_address (FILE *, rtx);
 
 #ifdef SUBTARGET_ATTRIBUTE_TABLE
 /* Table of valid machine attributes.  */
@@ -663,6 +666,13 @@ 
 #undef TARGET_TRAMPOLINE_INIT
 #define TARGET_TRAMPOLINE_INIT sparc_trampoline_init
 
+#undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
+#define TARGET_PRINT_OPERAND_PUNCT_VALID_P sparc_print_operand_punct_valid_p
+#undef TARGET_PRINT_OPERAND
+#define TARGET_PRINT_OPERAND sparc_print_operand
+#undef TARGET_PRINT_OPERAND_ADDRESS
+#define TARGET_PRINT_OPERAND_ADDRESS sparc_print_operand_address
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 /* Validate and override various options, and do some machine dependent
@@ -7326,12 +7336,29 @@ 
   return 1;
 }
 
-/* Print operand X (an rtx) in assembler syntax to file FILE.
+/* Implement TARGET_PRINT_OPERAND_PUNCT_VALID_P.  */
+
+static bool
+sparc_print_operand_punct_valid_p (unsigned char code)
+{
+  if(code == '#'
+     || code == '*'
+     || code == '('
+     || code == ')'
+     || code == '_'
+     || code == '&')
+    return true;
+
+  return false;
+}
+
+/* Implement TARGET_PRINT_OPERAND.
+   Print operand X (an rtx) in assembler syntax to file FILE.
    CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
    For `%' followed by punctuation, CODE is the punctuation and X is null.  */
 
-void
-print_operand (FILE *file, rtx x, int code)
+static void
+sparc_print_operand (FILE *file, rtx x, int code)
 {
   switch (code)
     {
@@ -7609,7 +7636,7 @@ 
     }
   else if (GET_CODE (x) == LO_SUM)
     {
-      print_operand (file, XEXP (x, 0), 0);
+      sparc_print_operand (file, XEXP (x, 0), 0);
       if (TARGET_CM_MEDMID)
        fputs ("+%l44(", file);
       else
@@ -7633,6 +7660,89 @@ 
     output_operand_lossage ("floating point constant not a valid immediate operand");
   else { output_addr_const (file, x); }
 }
+
+/* Implement TARGET_PRINT_OPERAND_ADDRESS.  */
+
+static void
+sparc_print_operand_address (FILE *file, rtx x)
+{
+  register rtx base, index = 0;
+  int offset = 0;
+  register rtx addr = x;
+
+  if (REG_P (addr))
+    fputs (reg_names[REGNO (addr)], file);
+  else if (GET_CODE (addr) == PLUS)
+    {
+      if (CONST_INT_P (XEXP (addr, 0)))
+       offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1);
+      else if (CONST_INT_P (XEXP (addr, 1)))
+       offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0);
+      else
+       base = XEXP (addr, 0), index = XEXP (addr, 1);
+      if (GET_CODE (base) == LO_SUM)
+       {
+         gcc_assert (USE_AS_OFFSETABLE_LO10
+                     && TARGET_ARCH64
+                     && ! TARGET_CM_MEDMID);
+         output_operand (XEXP (base, 0), 0);
+         fputs ("+%lo(", file);
+         output_address (XEXP (base, 1));
+         fprintf (file, ")+%d", offset);
+       }
+      else
+       {
+         fputs (reg_names[REGNO (base)], file);
+         if (index == 0)
+           fprintf (file, "%+d", offset);
+         else if (REG_P (index))
+           fprintf (file, "+%s", reg_names[REGNO (index)]);
+         else if (GET_CODE (index) == SYMBOL_REF
+                  || GET_CODE (index) == LABEL_REF
+                  || GET_CODE (index) == CONST)
+           fputc ('+', file), output_addr_const (file, index);
+         else gcc_unreachable ();
+       }
+    }
+  else if (GET_CODE (addr) == MINUS
+          && GET_CODE (XEXP (addr, 1)) == LABEL_REF)
+    {
+      output_addr_const (file, XEXP (addr, 0));
+      fputs ("-(", file);
+      output_addr_const (file, XEXP (addr, 1));
+      fputs ("-.)", file);
+    }
+  else if (GET_CODE (addr) == LO_SUM)
+    {
+      output_operand (XEXP (addr, 0), 0);
+      if (TARGET_CM_MEDMID)
+        fputs ("+%l44(", file);
+      else
+        fputs ("+%lo(", file);
+      output_address (XEXP (addr, 1));
+      fputc (')', file);
+    }
+  else if (flag_pic
+          && GET_CODE (addr) == CONST
+          && GET_CODE (XEXP (addr, 0)) == MINUS
+          && GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST
+          && GET_CODE (XEXP (XEXP (XEXP (addr, 0), 1), 0)) == MINUS
+          && XEXP (XEXP (XEXP (XEXP (addr, 0), 1), 0), 1) == pc_rtx)
+    {
+      addr = XEXP (addr, 0);
+      output_addr_const (file, XEXP (addr, 0));
+      /* Group the args of the second CONST in parenthesis.  */
+      fputs ("-(", file);
+      /* Skip past the second CONST--it does nothing for us.  */
+      output_addr_const (file, XEXP (XEXP (addr, 1), 0));
+      /* Close the parenthesis.  */
+      fputc (')', file);
+    }
+  else
+    {
+      output_addr_const (file, addr);
+    }
+}
 
 /* Target hook for assembling integer objects.  The sparc version has
    special handling for aligned DI-mode objects.  */
Index: gcc/config/sparc/sparc.h
===================================================================
--- gcc/config/sparc/sparc.h    (revision 172733)
+++ gcc/config/sparc/sparc.h    (working copy)
@@ -1922,95 +1922,6 @@ 
       }                                        \
   } while (0)
 
-#define PRINT_OPERAND_PUNCT_VALID_P(CHAR) \
-  ((CHAR) == '#' || (CHAR) == '*' || (CHAR) == '('             \
-   || (CHAR) == ')' || (CHAR) == '_' || (CHAR) == '&')
-
-/* Print operand X (an rtx) in assembler syntax to file FILE.
-   CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
-   For `%' followed by punctuation, CODE is the punctuation and X is null.  */
-
-#define PRINT_OPERAND(FILE, X, CODE) print_operand (FILE, X, CODE)
-
-/* Print a memory address as an operand to reference that memory location.  */
-
-#define PRINT_OPERAND_ADDRESS(FILE, ADDR)  \
-{ register rtx base, index = 0;                                        \
-  int offset = 0;                                              \
-  register rtx addr = ADDR;                                    \
-  if (GET_CODE (addr) == REG)                                  \
-    fputs (reg_names[REGNO (addr)], FILE);                     \
-  else if (GET_CODE (addr) == PLUS)                            \
-    {                                                          \
-      if (GET_CODE (XEXP (addr, 0)) == CONST_INT)              \
-       offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1);\
-      else if (GET_CODE (XEXP (addr, 1)) == CONST_INT)         \
-       offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0);\
-      else                                                     \
-       base = XEXP (addr, 0), index = XEXP (addr, 1);          \
-      if (GET_CODE (base) == LO_SUM)                           \
-       {                                                       \
-         gcc_assert (USE_AS_OFFSETABLE_LO10                    \
-                     && TARGET_ARCH64                          \
-                     && ! TARGET_CM_MEDMID);                   \
-         output_operand (XEXP (base, 0), 0);                   \
-         fputs ("+%lo(", FILE);                                \
-         output_address (XEXP (base, 1));                      \
-         fprintf (FILE, ")+%d", offset);                       \
-       }                                                       \
-      else                                                     \
-       {                                                       \
-         fputs (reg_names[REGNO (base)], FILE);                \
-         if (index == 0)                                       \
-           fprintf (FILE, "%+d", offset);                      \
-         else if (GET_CODE (index) == REG)                     \
-           fprintf (FILE, "+%s", reg_names[REGNO (index)]);    \
-         else if (GET_CODE (index) == SYMBOL_REF               \
-                  || GET_CODE (index) == LABEL_REF             \
-                  || GET_CODE (index) == CONST)                \
-           fputc ('+', FILE), output_addr_const (FILE, index); \
-         else gcc_unreachable ();                              \
-       }                                                       \
-    }                                                          \
-  else if (GET_CODE (addr) == MINUS                            \
-          && GET_CODE (XEXP (addr, 1)) == LABEL_REF)           \
-    {                                                          \
-      output_addr_const (FILE, XEXP (addr, 0));                        \
-      fputs ("-(", FILE);                                      \
-      output_addr_const (FILE, XEXP (addr, 1));                        \
-      fputs ("-.)", FILE);                                     \
-    }                                                          \
-  else if (GET_CODE (addr) == LO_SUM)                          \
-    {                                                          \
-      output_operand (XEXP (addr, 0), 0);                      \
-      if (TARGET_CM_MEDMID)                                    \
-        fputs ("+%l44(", FILE);                                        \
-      else                                                     \
-        fputs ("+%lo(", FILE);                                 \
-      output_address (XEXP (addr, 1));                         \
-      fputc (')', FILE);                                       \
-    }                                                          \
-  else if (flag_pic && GET_CODE (addr) == CONST                        \
-          && GET_CODE (XEXP (addr, 0)) == MINUS                \
-          && GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST      \
-          && GET_CODE (XEXP (XEXP (XEXP (addr, 0), 1), 0)) == MINUS    \
-          && XEXP (XEXP (XEXP (XEXP (addr, 0), 1), 0), 1) == pc_rtx)   \
-    {                                                          \
-      addr = XEXP (addr, 0);                                   \
-      output_addr_const (FILE, XEXP (addr, 0));                        \
-      /* Group the args of the second CONST in parenthesis.  */        \
-      fputs ("-(", FILE);                                      \
-      /* Skip past the second CONST--it does nothing for us.  */\
-      output_addr_const (FILE, XEXP (XEXP (addr, 1), 0));      \
-      /* Close the parenthesis.  */                            \
-      fputc (')', FILE);                                       \
-    }                                                          \
-  else                                                         \
-    {                                                          \
-      output_addr_const (FILE, addr);                          \
-    }                                                          \
-}
-
 /* TLS support defaulting to original Sun flavor.  GNU extensions
    must be activated in separate configuration files.  */
 #ifdef HAVE_AS_TLS