Thank you for taking the time to respond. My machine_function is marked as GTY and defined as follow: /* Per-function machine data. */ struct GTY(()) machine_function { /* Number of bytes saved on the stack for local variables. */ int local_vars_size; /* The sum of 2 sizes: locals vars and padding byte for saving the * registers. Used in expand_prologue () and expand_epilogue(). */ int size_for_adjusting_sp; }; Please, also find attached gcc/config/pu32/pu32.{c,h} files that I am using. For now I am trying to get it to compile, even though the assembly that gcc will generate will not be correct. On Fri, Mar 22, 2019 at 1:39 AM Segher Boessenkool <segher@xxxxxxxxxxxxxxxxxxx> wrote: > > On Thu, Mar 21, 2019 at 10:30:31PM -0500, William Tambe wrote: > > I am porting GCC to a new 32bits cpu. > > > > Any idea what could be the reason that I am getting undefined references to: > > gt_ggc_mx_machine_function(void*) > > gt_pch_nx_machine_function(void*) > > > > Which macro or target-macro should I define to avoid such error ? > > You probably forgot to mark your machine_function as GTY. It should be > something like > > struct GTY (()) machine_function { > int a; > int b; > }; > > (See other ports for examples). > > > Segher
/* Target Code for pu32 Copyright (C) 2008-2018 Free Software Foundation, Inc. This file is part of GCC. GCC 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. GCC 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 GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ #define IN_TARGET_CODE 1 #include "config.h" #include "system.h" #include "coretypes.h" #include "backend.h" #include "target.h" #include "rtl.h" #include "tree.h" #include "stringpool.h" #include "attribs.h" #include "df.h" #include "regs.h" #include "memmodel.h" #include "emit-rtl.h" #include "diagnostic-core.h" #include "output.h" #include "stor-layout.h" #include "varasm.h" #include "calls.h" #include "expr.h" #include "builtins.h" /* This file should be included last. */ #include "target-def.h" #define LOSE_AND_RETURN(msgid, x) \ do \ { \ pu32_operand_lossage (msgid, x); \ return; \ } while (0) /* Worker function for TARGET_RETURN_IN_MEMORY. */ static bool pu32_return_in_memory (const_tree type ATTRIBUTE_UNUSED, const_tree fntype ATTRIBUTE_UNUSED) { return true; } /* Emit an error message when we're in an asm, and a fatal error for "normal" insns. Formatted output isn't easily implemented, since we use output_operand_lossage to output the actual message and handle the categorization of the error. */ static void pu32_operand_lossage (const char *msgid, rtx op) { debug_rtx (op); output_operand_lossage ("%s", msgid); } /* The PRINT_OPERAND_ADDRESS worker. */ static void pu32_print_operand_address (FILE *file, machine_mode, rtx x) { switch (GET_CODE (x)) { case REG: fprintf (file, "%s", reg_names[REGNO (x)]); break; case PLUS: internal_error ("internal error: %s: unsupported", __FUNCTION__); break; default: output_addr_const (file, x); break; } } /* The PRINT_OPERAND worker. */ static void pu32_print_operand (FILE *file, rtx x, int code) { rtx operand = x; switch (code) { case 0: /* No code, print as usual. */ break; default: LOSE_AND_RETURN ("invalid operand modifier letter", x); } /* Print an operand as without a modifier letter. */ switch (GET_CODE (operand)) { case REG: if (REGNO (operand) > PU32_R15) internal_error ("internal error: bad register: %d", REGNO (operand)); fprintf (file, "%s", reg_names[REGNO (operand)]); return; case MEM: output_address (GET_MODE (XEXP (operand, 0)), XEXP (operand, 0)); return; default: // No need to handle all strange variants, // let output_addr_const do it for us. if (CONSTANT_P (operand)) { output_addr_const (file, operand); return; } LOSE_AND_RETURN ("unexpected operand", x); } } /* Per-function machine data. */ struct GTY(()) machine_function { /* Number of bytes saved on the stack for local variables. */ int local_vars_size; /* The sum of 2 sizes: locals vars and padding byte for saving the * registers. Used in expand_prologue () and expand_epilogue(). */ int size_for_adjusting_sp; }; /* Zero initialization is OK for all current fields. */ static struct machine_function * pu32_init_machine_status (void) { return ggc_cleared_alloc<machine_function> (); } /* The TARGET_OPTION_OVERRIDE worker. */ static void pu32_option_override (void) { /* Set the per-function-data initializer. */ init_machine_status = pu32_init_machine_status; } // Compute the size of the local area // and the size to be adjusted by the // prologue and epilogue. static void pu32_compute_frame (void) { /* For aligning the local variables. */ int stack_alignment = STACK_BOUNDARY / BITS_PER_UNIT; int padding_locals; /* Padding needed for each element of the frame. */ cfun->machine->local_vars_size = get_frame_size (); /* Align to the stack alignment. */ padding_locals = cfun->machine->local_vars_size % stack_alignment; if (padding_locals) { padding_locals = stack_alignment - padding_locals; cfun->machine->local_vars_size += padding_locals; } cfun->machine->size_for_adjusting_sp = crtl->args.pretend_args_size + cfun->machine->local_vars_size + (ACCUMULATE_OUTGOING_ARGS ? (HOST_WIDE_INT)crtl->outgoing_args_size : 0); } void pu32_expand_prologue (void) { pu32_compute_frame (); if (flag_stack_usage_info) current_function_static_stack_size = cfun->machine->size_for_adjusting_sp; if (cfun->machine->size_for_adjusting_sp) { rtx insn = emit_insn ( gen_subsi3 ( stack_pointer_rtx, stack_pointer_rtx, GEN_INT (cfun->machine->size_for_adjusting_sp))); RTX_FRAME_RELATED_P (insn) = 1; } } void pu32_expand_epilogue (void) { emit_jump_insn (gen_returner ()); } static rtx pu32_function_arg (cumulative_args_t cum_v ATTRIBUTE_UNUSED, machine_mode mode ATTRIBUTE_UNUSED, const_tree type ATTRIBUTE_UNUSED, bool named ATTRIBUTE_UNUSED) { return NULL_RTX; } /* Return non-zero if the function argument described by TYPE is to be passed by reference. */ static bool pu32_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED, machine_mode mode, const_tree type, bool named ATTRIBUTE_UNUSED) { unsigned HOST_WIDE_INT size; if (type) size = int_size_in_bytes (type); else size = GET_MODE_SIZE (mode); return size > UNITS_PER_WORD; } /* Worker function for TARGET_STATIC_CHAIN. */ static rtx pu32_static_chain (const_tree ARG_UNUSED (fndecl_or_type), bool incoming_p) { rtx addr, mem; if (incoming_p) addr = plus_constant (Pmode, arg_pointer_rtx, 2*UNITS_PER_WORD); else addr = plus_constant (Pmode, stack_pointer_rtx, -UNITS_PER_WORD); mem = gen_rtx_MEM (Pmode, addr); MEM_NOTRAP_P (mem) = 1; return mem; } /* Worker function for TARGET_ASM_TRAMPOLINE_TEMPLATE. */ static void pu32_asm_trampoline_template (FILE *f) { fprintf (f, "\t_push $sp, $r0\n"); fprintf (f, "\t_ldi.l $r0, 0x0\n"); fprintf (f, "\t_sto.l 0x8($fp), $r0\n"); fprintf (f, "\t_pop $sp, $r0\n"); fprintf (f, "\t_jmpa 0x0\n"); } /* Worker function for TARGET_TRAMPOLINE_INIT. */ static void pu32_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) { rtx mem, fnaddr = XEXP (DECL_RTL (fndecl), 0); emit_block_move (m_tramp, assemble_trampoline_template (), GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL); mem = adjust_address (m_tramp, SImode, 4); emit_move_insn (mem, chain_value); mem = adjust_address (m_tramp, SImode, 16); emit_move_insn (mem, fnaddr); } static bool pu32_reg_ok_for_base_p (const_rtx reg, bool strict_p) { int regno = REGNO (reg); if (strict_p) return HARD_REGNO_OK_FOR_BASE_P (regno) || HARD_REGNO_OK_FOR_BASE_P (reg_renumber[regno]); else return !HARD_REGISTER_NUM_P (regno) || HARD_REGNO_OK_FOR_BASE_P (regno); } /* Worker function for TARGET_LEGITIMATE_ADDRESS_P. */ static bool pu32_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x, bool strict_p, addr_space_t as ATTRIBUTE_UNUSED) { /*if (GET_CODE(x) == PLUS && REG_P (XEXP (x, 0)) && pu32_reg_ok_for_base_p (XEXP (x, 0), strict_p) && CONST_INT_P (XEXP (x, 1))) return true;*/ if (REG_P (x) && pu32_reg_ok_for_base_p (x, strict_p)) return true; if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF || GET_CODE (x) == CONST) return true; return false; } #undef TARGET_PROMOTE_PROTOTYPES #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true #undef TARGET_RETURN_IN_MEMORY #define TARGET_RETURN_IN_MEMORY pu32_return_in_memory #undef TARGET_PASS_BY_REFERENCE #define TARGET_PASS_BY_REFERENCE pu32_pass_by_reference #undef TARGET_FUNCTION_ARG #define TARGET_FUNCTION_ARG pu32_function_arg #undef TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P #define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P pu32_legitimate_address_p #undef TARGET_FRAME_POINTER_REQUIRED #define TARGET_FRAME_POINTER_REQUIRED hook_bool_void_true #undef TARGET_STATIC_CHAIN #define TARGET_STATIC_CHAIN pu32_static_chain #undef TARGET_ASM_TRAMPOLINE_TEMPLATE #define TARGET_ASM_TRAMPOLINE_TEMPLATE pu32_asm_trampoline_template #undef TARGET_TRAMPOLINE_INIT #define TARGET_TRAMPOLINE_INIT pu32_trampoline_init //#undef TARGET_CUSTOM_FUNCTION_DESCRIPTORS //#define TARGET_CUSTOM_FUNCTION_DESCRIPTORS 1 #undef TARGET_OPTION_OVERRIDE #define TARGET_OPTION_OVERRIDE pu32_option_override #undef TARGET_PRINT_OPERAND #define TARGET_PRINT_OPERAND pu32_print_operand #undef TARGET_PRINT_OPERAND_ADDRESS #define TARGET_PRINT_OPERAND_ADDRESS pu32_print_operand_address #undef TARGET_CONSTANT_ALIGNMENT #define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings struct gcc_target targetm = TARGET_INITIALIZER;
/* Target Definitions for pu32. Copyright (C) 2008-2018 Free Software Foundation, Inc. This file is part of GCC. GCC 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. GCC 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 GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ #ifndef GCC_PU32_H #define GCC_PU32_H #undef STARTFILE_SPEC #define STARTFILE_SPEC "" #undef ENDFILE_SPEC #define ENDFILE_SPEC "" #undef LIB_SPEC #define LIB_SPEC "%{!shared:%{!symbolic:-lc}}" #undef LINK_SPEC #define LINK_SPEC "%{h*} %{v:-V} %{static:-Bstatic} %{shared:-shared} %{symbolic:-Bsymbolic}" /* Layout of Source Language Data Types */ #define INT_TYPE_SIZE 32 #define SHORT_TYPE_SIZE 16 #define LONG_TYPE_SIZE 32 #define LONG_LONG_TYPE_SIZE 64 #define FLOAT_TYPE_SIZE 32 #define DOUBLE_TYPE_SIZE 64 #define LONG_DOUBLE_TYPE_SIZE 64 #define DEFAULT_SIGNED_CHAR 0 #undef SIZE_TYPE #define SIZE_TYPE "unsigned int" #undef PTRDIFF_TYPE #define PTRDIFF_TYPE "int" #undef WCHAR_TYPE #define WCHAR_TYPE "unsigned int" #undef WCHAR_TYPE_SIZE #define WCHAR_TYPE_SIZE BITS_PER_WORD #define REGISTER_NAMES { \ "%0", "%1", "%2", "%3", \ "%4", "%5", "%6", "%7", \ "%8", "%9", "%10", "%11", \ "%12", "%13", "%14", "%15", \ "%fp", "%ap", "%pc" } #define PU32_SP 0 #define PU32_R1 1 #define PU32_R2 2 #define PU32_R3 3 #define PU32_R4 4 #define PU32_R5 5 #define PU32_R6 6 #define PU32_R7 7 #define PU32_R8 8 #define PU32_R9 9 #define PU32_R10 10 #define PU32_R11 11 #define PU32_R12 12 #define PU32_R13 13 #define PU32_R14 14 #define PU32_R15 15 #define PU32_FP 16 #define PU32_AP 17 #define PU32_PC 18 #define FIRST_PSEUDO_REGISTER 19 enum reg_class { NO_REGS, GENERAL_REGS, SPECIAL_REGS, ALL_REGS, LIM_REG_CLASSES }; #define REG_CLASS_CONTENTS \ { { 0x00000000 }, /* Empty */ \ { 0x0003FFFF }, /* %0 to %15, %fp, %ap */ \ { 0x00040000 }, /* %pc */ \ { 0x0007FFFF } /* All registers */ \ } #define N_REG_CLASSES LIM_REG_CLASSES #define REG_CLASS_NAMES { \ "NO_REGS", \ "GENERAL_REGS", \ "SPECIAL_REGS", \ "ALL_REGS" } #define FIXED_REGISTERS { 1, 0, 0, 0, \ 0, 0, 0, 0, \ 0, 0, 0, 0, \ 0, 0, 0, 0, \ 1, 1, 1 } #define CALL_USED_REGISTERS { 1, 0, 0, 0, \ 0, 0, 0, 0, \ 0, 0, 0, 0, \ 0, 0, 0, 0, \ 1, 1, 1 } #define REGNO_REG_CLASS(R) ((R < PU32_PC) ? GENERAL_REGS : SPECIAL_REGS) /* The Overall Framework of an Assembler File */ #undef ASM_SPEC #define ASM_SPEC "" #define ASM_COMMENT_START "#" #define ASM_APP_ON "" #define ASM_APP_OFF "" #define FILE_ASM_OP "\t.file\n" /* Switch to the text or data segment. */ #define TEXT_SECTION_ASM_OP "\t.text" #define DATA_SECTION_ASM_OP "\t.data" /* Assembler Commands for Alignment */ #define ASM_OUTPUT_ALIGN(STREAM,POWER) \ fprintf (STREAM, "\t.p2align\t%d\n", POWER); /* Output and Generation of Labels */ #define GLOBAL_ASM_OP "\t.global\t" #define DEFAULT_PCC_STRUCT_RETURN 0 /* A C type for declaring a variable that is used as the first argument of `FUNCTION_ARG' and other related values. */ #define CUMULATIVE_ARGS unsigned int /* If defined, the maximum amount of space required for outgoing arguments will be computed and placed into the variable `current_function_outgoing_args_size'. No space will be pushed onto the stack for each call; instead, the function prologue should increase the stack frame size by this amount. */ #define ACCUMULATE_OUTGOING_ARGS 1 #define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,FNDECL,N_NAMED_ARGS) \ ((CUM) = 0) /* How Scalar Function Values Are Returned */ /* STACK AND CALLING */ /* Define this macro if pushing a word onto the stack moves the stack pointer to a smaller address. */ #define STACK_GROWS_DOWNWARD 1 /* Define this if the above stack space is to be considered part of the space allocated by the caller. */ #define OUTGOING_REG_PARM_STACK_SPACE(FNTYPE) 1 #define FIRST_PARM_OFFSET(FNDECL) 0 #define FRAME_GROWS_DOWNWARD 1 /* A C expression whose value is RTL representing the location of the incoming return address at the beginning of any function, before the prologue. */ #define INCOMING_RETURN_ADDR_RTX \ gen_rtx_MEM (Pmode, stack_pointer_rtx) /* Storage Layout */ #define BITS_BIG_ENDIAN 0 #define BYTES_BIG_ENDIAN 0 #define WORDS_BIG_ENDIAN 0 /* Alignment required for a function entry point, in bits. */ #define FUNCTION_BOUNDARY 16 /* Define this macro as a C expression which is nonzero if accessing less than a word of memory (i.e. a `char' or a `short') is no faster than accessing a word of memory. */ #define SLOW_BYTE_ACCESS 1 /* Number of storage units in a word; normally the size of a general-purpose register, a power of two from 1 or 8. */ #define UNITS_PER_WORD 4 /* Define this macro to the minimum alignment enforced by hardware for the stack pointer on this machine. The definition is a C expression for the desired alignment (measured in bits). */ #define STACK_BOUNDARY 32 /* Normal alignment required for function parameters on the stack, in bits. All stack parameters receive at least this much alignment regardless of data type. */ #define PARM_BOUNDARY 32 /* Alignment of field after `int : 0' in a structure. */ #define EMPTY_FIELD_BOUNDARY 32 /* No data type wants to be aligned rounder than this. */ #define BIGGEST_ALIGNMENT 32 /* The best alignment to use in cases where we have a choice. */ #define FASTEST_ALIGNMENT 32 /* Every structures size must be a multiple of 8 bits. */ #define STRUCTURE_SIZE_BOUNDARY 8 /* Look at the fundamental type that is used for a bit-field and use that to impose alignment on the enclosing structure. struct s {int a:8}; should have same alignment as "int", not "char". */ #define PCC_BITFIELD_TYPE_MATTERS 1 /* Largest integer machine mode for structures. If undefined, the default is GET_MODE_SIZE(DImode). */ #define MAX_FIXED_MODE_SIZE 32 /* Make arrays of chars word-aligned for the same reasons. */ #define DATA_ALIGNMENT(TYPE, ALIGN) \ (TREE_CODE (TYPE) == ARRAY_TYPE \ && TYPE_MODE (TREE_TYPE (TYPE)) == QImode \ && (ALIGN) < FASTEST_ALIGNMENT ? FASTEST_ALIGNMENT : (ALIGN)) /* Set this nonzero if move instructions will actually fail to work when given unaligned data. */ #define STRICT_ALIGNMENT 1 /* Generating Code for Profiling */ #define FUNCTION_PROFILER(FILE,LABELNO) (abort (), 0) /* Trampolines for Nested Functions. */ #define TRAMPOLINE_SIZE (2 + 6 + 4 + 2 + 6) /* Alignment required for trampolines, in bits. */ #define TRAMPOLINE_ALIGNMENT 32 /* An alias for the machine mode for pointers. */ #define Pmode SImode /* An alias for the machine mode used for memory references to functions being called, in `call' RTL expressions. */ #define FUNCTION_MODE QImode /* The register number of the stack pointer register, which must also be a fixed register according to `FIXED_REGISTERS'. */ #define STACK_POINTER_REGNUM PU32_SP /* The register number of the frame pointer register, which is used to access automatic variables in the stack frame. */ #define FRAME_POINTER_REGNUM PU32_FP /* The register number of the arg pointer register, which is used to access the function's argument list. */ #define ARG_POINTER_REGNUM PU32_AP #define ELIMINABLE_REGS \ {{ FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM }, \ { ARG_POINTER_REGNUM, STACK_POINTER_REGNUM }} /* This macro returns the initial difference between the specified pair of registers. */ #define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ do { \ if ((FROM) == FRAME_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) \ (OFFSET) = 0; \ else if ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) \ (OFFSET) = get_frame_size() + UNITS_PER_WORD; \ else gcc_unreachable (); \ } while (0) /* A C expression that is nonzero if REGNO is the number of a hard register in which function arguments are sometimes passed. */ #define FUNCTION_ARG_REGNO_P(REGNO) 0 /* A macro whose definition is the name of the class to which a valid base register must belong. A base register is one used in an address which is the register value plus a displacement. */ #define BASE_REG_CLASS GENERAL_REGS #define INDEX_REG_CLASS NO_REGS #define HARD_REGNO_OK_FOR_BASE_P(REGNO) \ (REGNO_REG_CLASS(REGNO) == GENERAL_REGS) /* A C expression which is nonzero if REGNO is suitable for use as a base register in operand addresses. */ #ifdef REG_OK_STRICT #define REGNO_OK_FOR_BASE_P(REGNO) \ (HARD_REGNO_OK_FOR_BASE_P(REGNO) \ || HARD_REGNO_OK_FOR_BASE_P(reg_renumber[REGNO])) #else #define REGNO_OK_FOR_BASE_P(REGNO) \ ((REGNO) >= FIRST_PSEUDO_REGISTER || HARD_REGNO_OK_FOR_BASE_P(REGNO)) #endif /* A C expression which is nonzero if REGNO is suitable for use as an index register in operand addresses. */ #define REGNO_OK_FOR_INDEX_P(REGNO) REGNO_OK_FOR_BASE_P(REGNO) /* The maximum number of bytes that a single instruction can move quickly between memory and registers or between two memory locations. */ #define MOVE_MAX UNITS_PER_WORD /* All load operations zero extend. */ #define LOAD_EXTEND_OP(MEM) ZERO_EXTEND /* A number, the maximum number of registers that can appear in a valid memory address. */ #define MAX_REGS_PER_ADDRESS 1 /* An alias for a machine mode name. This is the machine mode that elements of a jump-table should have. */ #define CASE_VECTOR_MODE SImode /* Run-time Target Specification */ #define TARGET_CPU_CPP_BUILTINS() \ { \ builtin_define_std ("__pu32__"); \ builtin_define_std ("__PU32__"); \ } #define HAS_LONG_UNCOND_BRANCH true #endif /* GCC_PU32_H */