Quoting Joern Rennecke <amyl...@spamcop.net>:
Right now, to make a new target hook, you have to add a new field in
target.h, define a new default in target-def.h, place the new macro
in exactly the right position there of the right initializer macro,
describe the new hook in tm.texi, and if you need a new function with
a bunch of parameters returning a constant, you have to add this to
hooks.c .

I would like to be able to do all this by adding a single entry in a
new definition file; and the information should also be usable by
plugin sources so that they can automatically make wrappers for all
function-type hooks.

I've attached what I have so far.
There is an issue that the struct gcc_target member names don't always agree
with the TARGET_* macro names.

Should I rather change one or the other to make them agree, or add an extra
parameter in the definition file macros to specify these names independently?


Index: target.def
===================================================================
--- target.def  (revision 0)
+++ target.def  (revision 0)
@@ -0,0 +1,263 @@
+/* Target hook definitions.
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.
+
+   In other words, you are welcome to use, share and improve this program.
+   You are forbidden to forbid anyone else to use, share and improve
+   what you give them.   Help stamp out software-hoarding!  */
+
+/* The following macros should be provided by the including file:
+
+   DEFHOOK(NAME, DOC, TYPE, PARAMS, INIT): Define a function-valued hook.
+   DEFHOOKPOD(DOC, TYPE, NAME, INIT): Define a piece-of-data 'hook'.  */
+
+/* Defaults for optional macros:
+   DEFHOOKPODX(NAME, NAME, INIT): Like DEFHOOKPOD, but share documentation
+   with the previous 'hook'.  */
+#ifndef DEFHOOKPODX
+#define DEFHOOKPODX(NAME, TYPE, INIT) DEFHOOKPOD (NAME, 0, TYPE, INIT)
+#endif
+   
+/* HOOKSTRUCT(FRAGMENT): Declarator fragments to encapsulate all the
+   members into a struct gcc_target, which in turn contains several
+   sub-structs.  */
+#ifndef HOOKSTRUCT
+#define HOOKSTRUCT(FRAGMENT)
+#endif
+
+HOOKSTRUCT (struct gcc_target {)
+
+/* Functions that output assembler for the target.  */
+#define HOOK_PREFIX "TARGET_ASM_"
+HOOKSTRUCT (struct asm_out {)
+
+DEFHOOKPOD
+(open_paren,
+"These target hooks are C string constants, describing the syntax in the\
+ assembler for grouping arithmetic expressions.  If not overridden, they\
+ default to normal parentheses, which is correct for most assemblers.",
+ const char *, "(")
+DEFHOOKPODX (close_paren, const char *, ")")
+
+DEFHOOKPOD
+(byte_op,
+"@deftypevrx {Target Hook} {const char *} TARGET_ASM_ALIGNED_HI_OP\n"
+"@deftypevrx {Target Hook} {const char *} TARGET_ASM_ALIGNED_SI_OP\n"
+"@deftypevrx {Target Hook} {const char *} TARGET_ASM_ALIGNED_DI_OP\n"
+"@deftypevrx {Target Hook} {const char *} TARGET_ASM_ALIGNED_TI_OP\n"
+"@deftypevrx {Target Hook} {const char *} TARGET_ASM_UNALIGNED_HI_OP\n"
+"@deftypevrx {Target Hook} {const char *} TARGET_ASM_UNALIGNED_SI_OP\n"
+"@deftypevrx {Target Hook} {const char *} TARGET_ASM_UNALIGNED_DI_OP\n"
+"@deftypevrx {Target Hook} {const char *} TARGET_ASM_UNALIGNED_TI_OP\n"
+"These hooks specify assembly directives for creating certain kinds\
+ of integer object.  The @code{TARGET_ASM_BYTE_OP} directive creates a\
+ byte-sized object, the @code{TARGET_ASM_ALIGNED_HI_OP} one creates an\
+ aligned two-byte object, and so on.  Any of the hooks may be\
+ @code{NULL}, indicating that no suitable directive is available.\n\n"
+
+"The compiler will print these strings at the start of a new line,\
+ followed immediately by the object's initial value.  In most cases,\
+ the string should contain a tab, a pseudo-op, and then another tab.",
+ const char *, "\t.byte\t")
+DEFHOOKPOD
+(aligned_op, "*", struct asm_int_op,
+ ({ TARGET_ASM_ALIGNED_HI_OP, TARGET_ASM_ALIGNED_SI_OP,
+    TARGET_ASM_ALIGNED_DI_OP, TARGET_ASM_ALIGNED_TI_OP }) )
+DEFHOOKPOD
+(unaligned_op, "*", struct asm_int_op,
+ ({ TARGET_ASM_UNALIGNED_HI_OP, TARGET_ASM_UNALIGNED_SI_OP,
+    TARGET_ASM_UNALIGNED_DI_OP, TARGET_ASM_UNALIGNED_TI_OP }) )
+    /* Assembler instructions for creating various kinds of integer object.  */
+
+DEFHOOK
+(integer,
+"The @code{assemble_integer} function uses this hook to output an\
+ integer object.  @var{x} is the object's value, @var{size} is its size\
+ in bytes and @var{aligned_p} indicates whether it is aligned.  The\
+ function should return @code{true} if it was able to output the\
+ object.  If it returns false, @code{assemble_integer} will try to\
+ split the object into smaller parts.\n\n"
+
+"The default implementation of this hook will use the\
+ @code{TARGET_ASM_BYTE_OP} family of strings, returning @code{false}\
+ when the relevant string is @code{NULL}.",
+ /* Only handles cases for which BYTE_OP, ALIGNED_OP and UNALIGNED_OP are
+    NULL.  */
+ bool, (rtx x, unsigned int size, int aligned_p),
+ default_assemble_integer)
+
+DEFHOOK
+(globalize_label,
+"This target hook is a function to output to the stdio stream\
+ @var{stream} some commands that will make the label @var{name} global;\
+ that is, available for reference from other files.\n\n"
+
+"The default implementation relies on a proper definition of\
+ @code{GLOBAL_ASM_OP}.",
+ void, (FILE *stream, const char *name),
+ default_globalize_label)
+
+DEFHOOK
+(globalize_decl_name,
+"This target hook is a function to output to the stdio stream\
+ @var{stream} some commands that will make the name associated with @var{decl}\
+ global; that is, available for reference from other files.\n\n"
+
+"The default implementation uses the TARGET_ASM_GLOBALIZE_LABEL target hook.",
+ void, (FILE *stream, tree decl), default_globalize_decl_name)
+
+DEFHOOK
+(emit_unwind_label,
+"This target hook emits a label at the beginning of each f...@.  It \
+ should be defined on targets where FDEs need special labels, and it \
+ should write the appropriate label, for the FDE associated with the \
+ function declaration @var{decl}, to the stdio stream @var{stream}. \
+ The third argument, @var{for_eh}, is a boolean: true if this is for an \
+ exception table.  The fourth argument, @var{empty}, is a boolean: \
+ true if this is a placeholder label for an omitted f...@.\n\n"
+
+"The default is that FDEs are not given nonlocal labels.",
+ void, (FILE *stream, tree decl, int for_eh, int empty),
+ default_emit_unwind_label)
+
+#if 0
+    /* Output code that will emit a label to divide up the exception
+       table.  */
+    void (* except_table_label) (FILE *);
+
+    /* Emit any directives required to unwind this instruction.  */
+    void (* unwind_emit) (FILE *, rtx);
+
+    /* Output an internal label.  */
+    void (* internal_label) (FILE *, const char *, unsigned long);
+
+    /* Emit a ttype table reference to a typeinfo object.  */
+    bool (* ttype) (rtx);
+
+    /* Emit an assembler directive to set visibility for the symbol
+       associated with the tree decl.  */
+    void (* visibility) (tree, int);
+
+    /* Output the assembler code for entry to a function.  */
+    void (* function_prologue) (FILE *, HOST_WIDE_INT);
+
+    /* Output the assembler code for end of prologue.  */
+    void (* function_end_prologue) (FILE *);
+
+    /* Output the assembler code for start of epilogue.  */
+    void (* function_begin_epilogue) (FILE *);
+
+    /* Output the assembler code for function exit.  */
+    void (* function_epilogue) (FILE *, HOST_WIDE_INT);
+
+    /* Initialize target-specific sections.  */
+    void (* init_sections) (void);
+
+    /* Tell assembler to change to section NAME with attributes FLAGS.
+       If DECL is non-NULL, it is the VAR_DECL or FUNCTION_DECL with
+       which this section is associated.  */
+    void (* named_section) (const char *name, unsigned int flags, tree decl);
+
+    /* Return a mask describing how relocations should be treated when
+       selecting sections.  Bit 1 should be set if global relocations
+       should be placed in a read-write section; bit 0 should be set if
+       local relocations should be placed in a read-write section.  */
+    int (*reloc_rw_mask) (void);
+
+    /* Return a section for EXP.  It may be a DECL or a constant.  RELOC
+       is nonzero if runtime relocations must be applied; bit 1 will be
+       set if the runtime relocations require non-local name resolution.
+       ALIGN is the required alignment of the data.  */
+    section *(* select_section) (tree, int, unsigned HOST_WIDE_INT);
+
+    /* Return a section for X.  MODE is X's mode and ALIGN is its
+       alignment in bits.  */
+    section *(* select_rtx_section) (enum machine_mode, rtx,
+                                     unsigned HOST_WIDE_INT);
+
+    /* Select a unique section name for DECL.  RELOC is the same as
+       for SELECT_SECTION.  */
+    void (* unique_section) (tree, int);
+
+    /* Return the readonly data section associated with function DECL.  */
+    section *(* function_rodata_section) (tree);
+
+    /* Output a constructor for a symbol with a given priority.  */
+    void (* constructor) (rtx, int);
+
+    /* Output a destructor for a symbol with a given priority.  */
+    void (* destructor) (rtx, int);
+
+    /* Output the assembler code for a thunk function.  THUNK_DECL is the
+       declaration for the thunk function itself, FUNCTION is the decl for
+       the target function.  DELTA is an immediate constant offset to be
+       added to THIS.  If VCALL_OFFSET is nonzero, the word at
+       *(*this + vcall_offset) should be added to THIS.  */
+    void (* output_mi_thunk) (FILE *file, tree thunk_decl,
+                              HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
+                              tree function_decl);
+
+    /* Determine whether output_mi_thunk would succeed.  */
+    /* ??? Ideally, this hook would not exist, and success or failure
+       would be returned from output_mi_thunk directly.  But there's
+       too much undo-able setup involved in invoking output_mi_thunk.
+       Could be fixed by making output_mi_thunk emit rtl instead of
+       text to the output file.  */
+    bool (* can_output_mi_thunk) (const_tree thunk_decl, HOST_WIDE_INT delta,
+                                  HOST_WIDE_INT vcall_offset,
+                                  const_tree function_decl);
+
+    /* Output any boilerplate text needed at the beginning of a
+       translation unit.  */
+    void (*file_start) (void);
+
+    /* Output any boilerplate text needed at the end of a
+       translation unit.  */
+    void (*file_end) (void);
+
+    /* Output an assembler pseudo-op to declare a library function name
+       external.  */
+    void (*external_libcall) (rtx);
+
+    /* Output an assembler directive to mark decl live. This instructs
+        linker to not dead code strip this symbol.  */
+    void (*mark_decl_preserved) (const char *);
+
+    /* Output a record of the command line switches that have been passed.  */
+    print_switch_fn_type record_gcc_switches;
+    /* The name of the section that the example ELF implementation of
+       record_gcc_switches will use to store the information.  Target
+       specific versions of record_gcc_switches may or may not use
+       this information.  */
+    const char * record_gcc_switches_section;
+
+    /* Output the definition of a section anchor.  */
+    void (*output_anchor) (rtx);
+
+    /* Output a DTP-relative reference to a TLS symbol.  */
+    void (*output_dwarf_dtprel) (FILE *file, int size, rtx x);
+
+    /* Some target machines need to postscan each insn after it is output.  */
+    void (*final_postscan_insn) (FILE *, rtx, rtx *, int);
+
+    /* Emit the trampoline template.  This hook may be NULL.  */
+    void (*trampoline_template) (FILE *);
+
+HOOKSTRUCT (} asm_out;)
+
+HOOKSTRUCT (struct sched {)
+#endif /* 0 */
Index: target.h
===================================================================
--- target.h    (revision 155367)
+++ target.h    (working copy)
@@ -108,7 +108,13 @@ struct asm_int_op
 };
 
 /* The target structure.  This holds all the backend hooks.  */
+#define DEFHOOKPOD(NAME, DOC, TYPE, INIT) TYPE NAME;
+#define DEFHOOK(NAME, DOC, TYPE, PARAMS, INIT) TYPE (* NAME) PARAMS;
+#define HOOKSTRUCT(FRAGMENT) FRAGMENT
 
+#include "target.def"
+
+#if 0
 struct gcc_target
 {
   /* Functions that output assembler for the target.  */
@@ -141,6 +147,7 @@ struct gcc_target
        this is only a placeholder for an omitted FDE.  */
     void (* unwind_label) (FILE *, tree, int, int);
 
+#endif /* 0 */
     /* Output code that will emit a label to divide up the exception
        table.  */
     void (* except_table_label) (FILE *);
Index: dwarf2out.c
===================================================================
--- dwarf2out.c (revision 155367)
+++ dwarf2out.c (working copy)
@@ -3457,8 +3457,8 @@ output_fde (dw_fde_ref fde, bool for_eh,
   char l1[20], l2[20];
   dw_cfi_ref cfi;
 
-  targetm.asm_out.unwind_label (asm_out_file, fde->decl, for_eh,
-                               /* empty */ 0);
+  targetm.asm_out.emit_unwind_label (asm_out_file, fde->decl, for_eh,
+                                    /* empty */ 0);
   targetm.asm_out.internal_label (asm_out_file, FDE_LABEL,
                                  for_eh + j);
   ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + j);
@@ -3651,8 +3651,8 @@ output_call_frame_info (int for_eh)
       if ((fde_table[i].nothrow || fde_table[i].all_throwers_are_sibcalls)
          && !fde_table[i].uses_eh_lsda
          && ! DECL_WEAK (fde_table[i].decl))
-       targetm.asm_out.unwind_label (asm_out_file, fde_table[i].decl,
-                                     for_eh, /* empty */ 1);
+       targetm.asm_out.emit_unwind_label (asm_out_file, fde_table[i].decl,
+                                          for_eh, /* empty */ 1);
 
   /* If we don't have any functions we'll want to unwind out of, don't
      emit any EH unwind information.  Note that if exceptions aren't
Index: gentarget.c
===================================================================
--- gentarget.c (revision 0)
+++ gentarget.c (revision 0)
@@ -0,0 +1,70 @@
+#include "bconfig.h"
+#include "system.h"
+#include <string.h>
+
+struct hook_desc { const char *doc, *type, *name, *param, *init; };
+static struct hook_desc hook_array[] = {
+#define DEFHOOKPOD(NAME, DOC, TYPE, INIT) \
+  { DOC, #TYPE, HOOK_PREFIX #NAME, 0, #INIT },
+#define DEFHOOK(NAME, DOC, TYPE, PARAMS, INIT) \
+  { DOC, #TYPE, HOOK_PREFIX #NAME, #PARAMS, #INIT },
+#include "target.def"
+#undef DEFHOOK
+};
+
+int
+main (int argc, char **argv)
+{
+  bool doc_p = false;
+  int i, j;
+
+  if (argc >= 2 && strcmp (argv[1], "-doc") == 0)
+    doc_p = true;
+  for (i = 0; i < (int) (sizeof hook_array / sizeof hook_array[0]); i++)
+    {
+      char *name = xstrdup (hook_array[i].name);
+      char *p;
+      const char *q, *e;
+
+      for (p = name; *p; p++)
+       *p = TOUPPER (*p);
+      if (doc_p)
+       {
+         const char *deftype;
+
+         if (!hook_array[i].doc)
+           continue;
+         if (*hook_array[i].doc == '*')
+           {
+             printf ("%s", hook_array[i].doc + 1);
+             continue;
+           }
+         deftype = hook_array[i].param ? "deftypefn" : "deftypevr";
+         printf ("@%s {Target Hook} {%s} %s",
+                 deftype, hook_array[i].type, name);
+         if (hook_array[i].param)
+           {
+             /* Print the parameter list, with the parameter names
+                enclosed in @var{}.  */
+             printf (" ");
+             for (q = hook_array[i].param; (e = strpbrk (q, " ,)"));
+                  q = e + 1)
+               if (*e == ' ')
+                 printf ("%.*s", e - q + 1, q);
+               else
+                 printf ("@var{%.*s}%c", e - q, q, *e);
+           }
+         printf ("\n");
+         for (j = i + 1;
+              j < (int) (sizeof hook_array / sizeof hook_array[0])
+              && hook_array[j].doc == 0; j++)
+           printf ("@%sx {Target Hook} {%s} %s\n",
+                   deftype, hook_array[i].type, name);
+         printf ("%...@end %s\n\n", hook_array[i].doc, deftype);
+       }
+      else
+       printf ("#ifndef %s\n#define %s %s\n#endif\n",
+               name, name, hook_array[i].init);
+    }
+  return 0;
+}
Index: Makefile.in
===================================================================
--- Makefile.in (revision 155367)
+++ Makefile.in (working copy)
@@ -3714,6 +3714,7 @@ build/genpreds.o : genpreds.c $(RTL_BASE
   coretypes.h $(GTM_H) errors.h gensupport.h $(OBSTACK_H)
 build/genrecog.o : genrecog.c $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H)   \
   coretypes.h $(GTM_H) errors.h gensupport.h
+build/gentarget.o : gentarget.c target.def $(BCONFIG_H) $(SYSTEM_H)
 
 # Compile the programs that generate insn-* from the machine description.
 # They are compiled with $(COMPILER_FOR_BUILD), and associated libraries,
@@ -3738,6 +3739,7 @@ build/gengenrtl$(build_exeext) : $(BUILD
 build/genmodes$(build_exeext) : $(BUILD_ERRORS)
 build/gengtype$(build_exeext) : build/gengtype-lex.o build/gengtype-parse.o \
                                $(BUILD_ERRORS)
+build/gentarget$(build_exeext) : $(BUILD_ERRORS)
 
 # Generated source files for gengtype.
 gengtype-lex.c : gengtype-lex.l

Reply via email to