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