(root)/
gcc-13.2.0/
gcc/
config/
microblaze/
microblaze.h
       1  /* Definitions of target machine for GNU compiler for Xilinx MicroBlaze.
       2     Copyright (C) 2009-2023 Free Software Foundation, Inc.
       3  
       4     Contributed by Michael Eager <eager@eagercon.com>.
       5  
       6     This file is part of GCC.
       7  
       8     GCC is free software; you can redistribute it and/or modify it
       9     under the terms of the GNU General Public License as published
      10     by the Free Software Foundation; either version 3, or (at your
      11     option) any later version.
      12  
      13     GCC is distributed in the hope that it will be useful, but WITHOUT
      14     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      15     or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
      16     License for more details.
      17  
      18     You should have received a copy of the GNU General Public License
      19     along with GCC; see the file COPYING3.  If not see
      20     <http://www.gnu.org/licenses/>.  */
      21  
      22  /* Standard GCC variables that we reference.  */
      23  
      24  /* MicroBlaze external variables defined in microblaze.cc.  */
      25  
      26  /* Which pipeline to schedule for.  */
      27  enum pipeline_type
      28  {
      29    MICROBLAZE_PIPE_3 = 0,
      30    MICROBLAZE_PIPE_5 = 1
      31  };
      32  
      33  #define MICROBLAZE_MASK_NO_UNSAFE_DELAY         0x00000001
      34  
      35  /* print_operand punctuation chars */
      36  extern char microblaze_print_operand_punct[];
      37  
      38  /* # bytes of data/sdata cutoff */
      39  extern int microblaze_section_threshold;
      40  
      41  /* Map register # to debug register # */
      42  extern int microblaze_debugger_regno[];
      43  
      44  extern int microblaze_no_unsafe_delay;
      45  extern int microblaze_has_clz;
      46  extern enum pipeline_type microblaze_pipe;
      47  
      48  #define OBJECT_FORMAT_ELF
      49  
      50  #if TARGET_BIG_ENDIAN_DEFAULT
      51  #define TARGET_ENDIAN_DEFAULT    0
      52  #define TARGET_ENDIAN_OPTION     "mbig-endian"
      53  #else
      54  #define TARGET_ENDIAN_DEFAULT    MASK_LITTLE_ENDIAN
      55  #define TARGET_ENDIAN_OPTION     "mlittle-endian"
      56  #endif
      57  
      58  /* Default target_flags if no switches are specified  */
      59  #define TARGET_DEFAULT      (MASK_SOFT_MUL | MASK_SOFT_DIV | MASK_SOFT_FLOAT \
      60                               | TARGET_ENDIAN_DEFAULT)
      61  
      62  /* Do we have CLZ?  */
      63  #define TARGET_HAS_CLZ      (TARGET_PATTERN_COMPARE && microblaze_has_clz)
      64  
      65  /* The default is to support PIC.  */
      66  #define TARGET_SUPPORTS_PIC 1
      67  
      68  /* The default is to not need GOT for TLS.  */
      69  #define TLS_NEEDS_GOT 0
      70  
      71  /* What is the default setting for -mcpu= . We set it to v4.00.a even though 
      72     we are actually ahead. This is safest version that has generate code 
      73     compatible for the original ISA */
      74  #define MICROBLAZE_DEFAULT_CPU      "v4.00.a"
      75  
      76  /* Macros to decide whether certain features are available or not,
      77     depending on the instruction set architecture level.  */
      78  
      79  #define DRIVER_SELF_SPECS    				\
      80  	"%{mxl-soft-mul:%<mno-xl-soft-mul}", 		\
      81  	"%{mno-xl-barrel-shift:%<mxl-barrel-shift}", 	\
      82  	"%{mno-xl-pattern-compare:%<mxl-pattern-compare}", \
      83  	"%{mxl-soft-div:%<mno-xl-soft-div}", 		\
      84  	"%{mxl-reorder:%<mno-xl-reorder}", 		\
      85  	"%{msoft-float:%<mhard-float}"
      86  
      87  /* Tell collect what flags to pass to nm.  */
      88  #ifndef NM_FLAGS
      89  #define NM_FLAGS "-Bn"
      90  #endif
      91  
      92  /* Names to predefine in the preprocessor for this target machine.  */
      93  #define TARGET_CPU_CPP_BUILTINS() microblaze_cpp_define (pfile)
      94  
      95  /* Assembler specs.  */
      96  
      97  #define TARGET_ASM_SPEC ""
      98  
      99  #define ASM_SPEC "\
     100  %(target_asm_spec) \
     101  %{mbig-endian:-EB} \
     102  %{mlittle-endian:-EL}"
     103  
     104  /* Extra switches sometimes passed to the linker.  */
     105  /* -xl-mode-xmdstub translated to -Zxl-mode-xmdstub -- deprecated.  */
     106  
     107  #define LINK_SPEC "%{shared:-shared} -N -relax \
     108    %{mbig-endian:-EB --oformat=elf32-microblaze} \
     109    %{mlittle-endian:-EL --oformat=elf32-microblazeel} \
     110    %{Zxl-mode-xmdstub:-defsym _TEXT_START_ADDR=0x800} \
     111    %{mxl-mode-xmdstub:-defsym _TEXT_START_ADDR=0x800} \
     112    %{mxl-gp-opt:%{G*}} %{!mxl-gp-opt: -G 0} \
     113    %{!T*: -dT xilinx.ld%s}"
     114  
     115  /* Specs for the compiler proper  */
     116  
     117  #ifndef CC1_SPEC
     118  #define CC1_SPEC " \
     119  %{G*} \
     120  %(subtarget_cc1_spec) \
     121  %{mxl-multiply-high:-mcpu=v6.00.a} \
     122  "
     123  #endif
     124  
     125  #define EXTRA_SPECS							\
     126    { "target_asm_spec", TARGET_ASM_SPEC },				\
     127    SUBTARGET_EXTRA_SPECS
     128  
     129  /* Local compiler-generated symbols must have a prefix that the assembler
     130     understands.   */
     131  
     132  #ifndef LOCAL_LABEL_PREFIX
     133  #define LOCAL_LABEL_PREFIX	"$"
     134  #endif
     135  
     136  /* fixed registers.  */
     137  #define MB_ABI_BASE_REGNUM                   0
     138  #define MB_ABI_STACK_POINTER_REGNUM          1
     139  #define MB_ABI_GPRO_REGNUM                   2
     140  #define MB_ABI_GPRW_REGNUM                  13
     141  #define MB_ABI_INTR_RETURN_ADDR_REGNUM      14
     142  #define MB_ABI_SUB_RETURN_ADDR_REGNUM       15
     143  #define MB_ABI_DEBUG_RETURN_ADDR_REGNUM     16
     144  #define MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM 17
     145  #define MB_ABI_ASM_TEMP_REGNUM              18	
     146  /* This is our temp register.  */
     147  #define MB_ABI_FRAME_POINTER_REGNUM         19
     148  #define MB_ABI_PIC_ADDR_REGNUM              20
     149  #define MB_ABI_PIC_FUNC_REGNUM              21
     150  /* Volatile registers.  */
     151  #define MB_ABI_INT_RETURN_VAL_REGNUM         3
     152  #define MB_ABI_INT_RETURN_VAL2_REGNUM        4
     153  #define MB_ABI_FIRST_ARG_REGNUM              5
     154  #define MB_ABI_LAST_ARG_REGNUM              10
     155  #define MB_ABI_MAX_ARG_REGS                 (MB_ABI_LAST_ARG_REGNUM 	\
     156  					     - MB_ABI_FIRST_ARG_REGNUM + 1)
     157  #define MB_ABI_STATIC_CHAIN_REGNUM           3
     158  #define MB_ABI_TEMP1_REGNUM                 11
     159  #define MB_ABI_TEMP2_REGNUM                 12
     160  #define MB_ABI_MSR_SAVE_REG                 11	
     161  /* Volatile register used to save MSR in interrupt handlers.  */
     162  
     163  
     164  /* Debug stuff.  */
     165  
     166  /* How to renumber registers for gdb.  */
     167  #define DEBUGGER_REGNO(REGNO) microblaze_debugger_regno[(REGNO)]
     168  
     169  /* Generate DWARF exception handling info.  */
     170  #define DWARF2_UNWIND_INFO 1
     171  
     172  /* Don't generate .loc operations.  */
     173  #define DWARF2_ASM_LINE_DEBUG_INFO 0
     174  
     175  /* The DWARF 2 CFA column which tracks the return address.  */
     176  #define DWARF_FRAME_RETURN_COLUMN \
     177  	(GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM)
     178  
     179  /* Initial state of return address on entry to func = R15.
     180     Actually, the RA is at R15+8, but gcc doesn't know how 
     181     to generate this. 
     182     NOTE:  GDB has a workaround and expects this incorrect value.
     183     If this is fixed, a corresponding fix to GDB is needed.  */
     184  #define INCOMING_RETURN_ADDR_RTX  			\
     185    gen_rtx_REG (Pmode, GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM)
     186  
     187  /* Specifies the offset from INCOMING_RETURN_ADDR_RTX and the actual return PC.  */
     188  #define RETURN_ADDR_OFFSET (8)
     189  
     190  /* Describe how we implement __builtin_eh_return.  */
     191  #define EH_RETURN_DATA_REGNO(N)					\
     192    (((N) < 2) ? MB_ABI_FIRST_ARG_REGNUM + (N) : INVALID_REGNUM)
     193  
     194  #define MB_EH_STACKADJ_REGNUM  MB_ABI_INT_RETURN_VAL2_REGNUM
     195  #define EH_RETURN_STACKADJ_RTX  gen_rtx_REG (Pmode, MB_EH_STACKADJ_REGNUM)
     196  
     197  /* Select a format to encode pointers in exception handling data.  CODE
     198     is 0 for data, 1 for code labels, 2 for function pointers.  GLOBAL is
     199     true if the symbol may be affected by dynamic relocations.  */
     200  #define ASM_PREFERRED_EH_DATA_FORMAT(CODE,GLOBAL) \
     201    ((flag_pic || GLOBAL) ? DW_EH_PE_aligned : DW_EH_PE_absptr)
     202  
     203  /* Use DWARF 2 debugging information by default.  */
     204  #define DWARF2_DEBUGGING_INFO
     205  #define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
     206  
     207  /* Target machine storage layout */
     208  
     209  #define BITS_BIG_ENDIAN 0
     210  #define BYTES_BIG_ENDIAN (TARGET_LITTLE_ENDIAN == 0)
     211  #define WORDS_BIG_ENDIAN (BYTES_BIG_ENDIAN)
     212  #define BITS_PER_WORD           32
     213  #define UNITS_PER_WORD          4
     214  #define MIN_UNITS_PER_WORD      4
     215  #define INT_TYPE_SIZE           32
     216  #define SHORT_TYPE_SIZE         16
     217  #define LONG_TYPE_SIZE          32
     218  #define LONG_LONG_TYPE_SIZE     64
     219  #define FLOAT_TYPE_SIZE         32
     220  #define DOUBLE_TYPE_SIZE        64
     221  #define LONG_DOUBLE_TYPE_SIZE   64
     222  #define POINTER_SIZE            32
     223  #define PARM_BOUNDARY           32
     224  #define FUNCTION_BOUNDARY       32
     225  #define EMPTY_FIELD_BOUNDARY    32
     226  #define STRUCTURE_SIZE_BOUNDARY 8
     227  #define BIGGEST_ALIGNMENT       32
     228  #define STRICT_ALIGNMENT        1
     229  #define PCC_BITFIELD_TYPE_MATTERS 1
     230  
     231  #undef SIZE_TYPE
     232  #define SIZE_TYPE "unsigned int"
     233  
     234  #undef PTRDIFF_TYPE
     235  #define PTRDIFF_TYPE "int"
     236  
     237  #define DATA_ALIGNMENT(TYPE, ALIGN)					\
     238    ((((ALIGN) < BITS_PER_WORD)						\
     239      && (TREE_CODE (TYPE) == ARRAY_TYPE					\
     240  	|| TREE_CODE (TYPE) == UNION_TYPE				\
     241  	|| TREE_CODE (TYPE) == RECORD_TYPE)) ? BITS_PER_WORD : (ALIGN))
     242  
     243  #define LOCAL_ALIGNMENT(TYPE, ALIGN)     				\
     244      (((TREE_CODE (TYPE) == ARRAY_TYPE 					\
     245         && TYPE_MODE (TREE_TYPE (TYPE)) == QImode)			\
     246       && (ALIGN) < BITS_PER_WORD) ? BITS_PER_WORD : (ALIGN))
     247  
     248  #define WORD_REGISTER_OPERATIONS 1
     249  
     250  #define LOAD_EXTEND_OP(MODE)  ZERO_EXTEND
     251  
     252  #define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE)	\
     253    if (GET_MODE_CLASS (MODE) == MODE_INT		\
     254        && GET_MODE_SIZE (MODE) < 4)		\
     255      (MODE) = SImode;
     256  
     257  /* Standard register usage.  */
     258  
     259  /* On the MicroBlaze, we have 32 integer registers */
     260  
     261  #define FIRST_PSEUDO_REGISTER 36
     262  
     263  #define FIXED_REGISTERS							\
     264  {									\
     265    1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,			\
     266    1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,			\
     267    1, 1, 1, 1 								\
     268  }
     269  
     270  #define CALL_USED_REGISTERS						\
     271  {									\
     272    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,			\
     273    1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,			\
     274    1, 1, 1, 1								\
     275  }
     276  #define GP_REG_FIRST    0
     277  #define GP_REG_LAST     31
     278  #define GP_REG_NUM      (GP_REG_LAST - GP_REG_FIRST + 1)
     279  #define GP_DEBUGGER_FIRST    0
     280  
     281  #define ST_REG		32
     282  #define AP_REG_NUM      33
     283  #define RAP_REG_NUM     34
     284  #define FRP_REG_NUM     35
     285  
     286  #define GP_REG_P(REGNO) ((unsigned) ((REGNO) - GP_REG_FIRST) < GP_REG_NUM)
     287  #define ST_REG_P(REGNO) ((REGNO) == ST_REG)
     288  
     289  #define STACK_POINTER_REGNUM   (GP_REG_FIRST + MB_ABI_STACK_POINTER_REGNUM)
     290  
     291  #define STACK_POINTER_OFFSET   FIRST_PARM_OFFSET(FNDECL)
     292  
     293  /* Base register for access to local variables of the function.  We
     294     pretend that the frame pointer is
     295     MB_ABI_INTR_RETURN_ADDR_REGNUM, and then eliminate it
     296     to HARD_FRAME_POINTER_REGNUM.  We can get away with this because
     297     rMB_ABI_INTR_RETUREN_ADDR_REGNUM is a fixed
     298     register(return address for interrupt), and will not be used for
     299     anything else.  */
     300     
     301  #define FRAME_POINTER_REGNUM 		FRP_REG_NUM
     302  #define HARD_FRAME_POINTER_REGNUM       \
     303          (GP_REG_FIRST + MB_ABI_FRAME_POINTER_REGNUM)
     304  #define ARG_POINTER_REGNUM		AP_REG_NUM
     305  #define RETURN_ADDRESS_POINTER_REGNUM	RAP_REG_NUM
     306  #define STATIC_CHAIN_REGNUM             \
     307          (GP_REG_FIRST + MB_ABI_STATIC_CHAIN_REGNUM)
     308  
     309  /* registers used in prologue/epilogue code when the stack frame
     310     is larger than 32K bytes.  These registers must come from the
     311     scratch register set, and not used for passing and returning
     312     arguments and any other information used in the calling sequence
     313     (such as pic).  */
     314  
     315  #define MICROBLAZE_TEMP1_REGNUM         \
     316          (GP_REG_FIRST + MB_ABI_TEMP1_REGNUM)
     317  
     318  #define MICROBLAZE_TEMP2_REGNUM         \
     319          (GP_REG_FIRST + MB_ABI_TEMP2_REGNUM)
     320  
     321  #define NO_FUNCTION_CSE                 1
     322  
     323  #define PIC_OFFSET_TABLE_REGNUM   (GP_REG_FIRST + MB_ABI_PIC_ADDR_REGNUM)
     324  
     325  enum reg_class
     326  {
     327    NO_REGS,			/* no registers in set.  */
     328    GR_REGS,			/* integer registers.  */
     329    ST_REGS,			/* status register.  */
     330    ALL_REGS,			/* all registers.  */
     331    LIM_REG_CLASSES		/* max value + 1.  */
     332  };
     333  
     334  #define N_REG_CLASSES 		(int) LIM_REG_CLASSES
     335  
     336  #define GENERAL_REGS 		GR_REGS
     337  
     338  #define REG_CLASS_NAMES							\
     339  {									\
     340    "NO_REGS",								\
     341    "GR_REGS",								\
     342    "ST_REGS",								\
     343    "ALL_REGS"								\
     344  }
     345  
     346  #define REG_CLASS_CONTENTS						\
     347  {									\
     348    { 0x00000000, 0x00000000 },		/* no registers.  */		\
     349    { 0xffffffff, 0x00000000 },		/* integer registers.  */	\
     350    { 0x00000000, 0x00000001 },		/* status registers.  */	\
     351    { 0xffffffff, 0x0000000f }		/* all registers.  */		\
     352  }
     353  
     354  extern enum reg_class microblaze_regno_to_class[];
     355  
     356  #define REGNO_REG_CLASS(REGNO) 		microblaze_regno_to_class[ (REGNO) ]
     357  
     358  #define BASE_REG_CLASS  		GR_REGS
     359  
     360  #define INDEX_REG_CLASS 		GR_REGS
     361  
     362  #define GR_REG_CLASS_P(CLASS) 		((CLASS) == GR_REGS)
     363  
     364  /* REGISTER AND CONSTANT CLASSES */
     365  
     366  #define SMALL_INT(X) ((unsigned HOST_WIDE_INT) (INTVAL (X) + 0x8000) < 0x10000)
     367  #define LARGE_INT(X) \
     368    (INTVAL (X) > 0 && UINTVAL (X) >= 0x80000000 && UINTVAL (X) <= 0xffffffff)
     369  #define PLT_ADDR_P(X) (GET_CODE (X) == UNSPEC && XINT (X,1) == UNSPEC_PLT)
     370  /* Test for a valid operand for a call instruction.
     371     Don't allow the arg pointer register or virtual regs
     372     since they may change into reg + const, which the patterns
     373     can't handle yet.  */
     374  #define CALL_INSN_OP(X) (CONSTANT_ADDRESS_P (X) \
     375                           || (GET_CODE (X) == REG && X != arg_pointer_rtx\
     376                               && ! (REGNO (X) >= FIRST_PSEUDO_REGISTER	\
     377                               && REGNO (X) <= LAST_VIRTUAL_REGISTER)))
     378  
     379  /* True if VALUE is a signed 16-bit number.  */
     380  #define SMALL_OPERAND(VALUE) 						\
     381    ((unsigned HOST_WIDE_INT) (VALUE) + 0x8000 < 0x10000)
     382  
     383  /* Constant which cannot be loaded in one instruction.  */
     384  #define LARGE_OPERAND(VALUE)						\
     385    ((((VALUE) & ~0x0000ffff) != 0)					\
     386     && (((VALUE) & ~0x0000ffff) != ~0x0000ffff)				\
     387     && (((VALUE) & 0x0000ffff) != 0					\
     388         || (((VALUE) & ~2147483647) != 0					\
     389  	   && ((VALUE) & ~2147483647) != ~2147483647)))
     390  	
     391  #define PREFERRED_RELOAD_CLASS(X,CLASS)					\
     392    ((CLASS) != ALL_REGS							\
     393     ? (CLASS)							\
     394     : ((GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT			\
     395         || GET_MODE_CLASS (GET_MODE (X)) == MODE_COMPLEX_FLOAT)		\
     396        ? (GR_REGS)			\
     397        : ((GET_MODE_CLASS (GET_MODE (X)) == MODE_INT			\
     398  	  || GET_MODE (X) == VOIDmode)					\
     399  	 ? (GR_REGS) : (CLASS))))
     400  
     401  /* Stack layout; function entry, exit and calling.  */
     402  
     403  #define STACK_GROWS_DOWNWARD 1
     404  
     405  /* The return address for the current frame is in r31 if this is a leaf
     406     function.  Otherwise, it is on the stack.  It is at a variable offset
     407     from sp/fp/ap, so we define a fake hard register rap which is a
     408     poiner to the return address on the stack.  This always gets eliminated
     409     during reload to be either the frame pointer or the stack pointer plus
     410     an offset.  */
     411  
     412  #define RETURN_ADDR_RTX(count, frame)			\
     413    microblaze_return_addr(count,frame)
     414  
     415  extern struct microblaze_frame_info current_frame_info;
     416  
     417  #define ELIMINABLE_REGS							\
     418  {{ ARG_POINTER_REGNUM,   STACK_POINTER_REGNUM},				\
     419   { ARG_POINTER_REGNUM,   GP_REG_FIRST + MB_ABI_FRAME_POINTER_REGNUM},	\
     420   { RETURN_ADDRESS_POINTER_REGNUM, STACK_POINTER_REGNUM},		\
     421   { RETURN_ADDRESS_POINTER_REGNUM, 					\
     422     GP_REG_FIRST + MB_ABI_FRAME_POINTER_REGNUM},				\
     423   { RETURN_ADDRESS_POINTER_REGNUM, 					\
     424     GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM},			\
     425   { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM},				\
     426   { FRAME_POINTER_REGNUM, GP_REG_FIRST + MB_ABI_FRAME_POINTER_REGNUM}}
     427  
     428  #define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET)			 \
     429          (OFFSET) = microblaze_initial_elimination_offset ((FROM), (TO))
     430  
     431  #define ACCUMULATE_OUTGOING_ARGS        1
     432  
     433  #define FIRST_PARM_OFFSET(FNDECL)		(UNITS_PER_WORD)
     434  
     435  #define ARG_POINTER_CFA_OFFSET(FNDECL)		0
     436  
     437  #define REG_PARM_STACK_SPACE(FNDECL)  		(MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD)
     438  
     439  #define OUTGOING_REG_PARM_STACK_SPACE(FNTYPE)	1
     440  
     441  #define STACK_BOUNDARY				32
     442  
     443  #define NUM_OF_ARGS				6
     444  
     445  #define GP_RETURN				(GP_REG_FIRST + MB_ABI_INT_RETURN_VAL_REGNUM)
     446  
     447  #define GP_ARG_FIRST				(GP_REG_FIRST + MB_ABI_FIRST_ARG_REGNUM)
     448  #define GP_ARG_LAST				(GP_REG_FIRST + MB_ABI_LAST_ARG_REGNUM)
     449  
     450  #define MAX_ARGS_IN_REGISTERS			MB_ABI_MAX_ARG_REGS
     451  
     452  #define LIBCALL_VALUE(MODE)						\
     453    gen_rtx_REG (								\
     454  	   ((GET_MODE_CLASS (MODE) != MODE_INT				\
     455  	     || GET_MODE_SIZE (MODE) >= 4)				\
     456  	    ? (MODE)							\
     457  	    : SImode), GP_RETURN)
     458  
     459  /* 1 if N is a possible register number for a function value.
     460     On the MicroBlaze, R2 R3 are the only register thus used.
     461     Currently, R2 are only implemented  here (C has no complex type)  */
     462  
     463  #define FUNCTION_VALUE_REGNO_P(N)		((N) == GP_RETURN)
     464  
     465  #define FUNCTION_ARG_REGNO_P(N)			(((N) >= GP_ARG_FIRST && (N) <= GP_ARG_LAST))
     466  
     467  typedef struct microblaze_args
     468  {
     469    int gp_reg_found;		/* whether a gp register was found yet */
     470    int arg_number;		/* argument number */
     471    int arg_words;		/* # total words the arguments take */
     472    int fp_arg_words;		/* # words for FP args */
     473    int last_arg_fp;		/* nonzero if last arg was FP (EABI only) */
     474    int fp_code;			/* Mode of FP arguments */
     475    int num_adjusts;		/* number of adjustments made */
     476    /* Adjustments made to args pass in regs.  */
     477    /* ??? The size is doubled to work around a bug in the code that sets the 
     478       adjustments in function_arg.  */
     479    rtx adjust[MAX_ARGS_IN_REGISTERS * 2];
     480  } CUMULATIVE_ARGS;
     481  
     482  #define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,FNDECL,N_NAMED_ARGS)	\
     483    init_cumulative_args (&CUM, FNTYPE, LIBNAME)
     484  
     485  #define NO_PROFILE_COUNTERS			1
     486  
     487  #define FUNCTION_PROFILER(FILE, LABELNO) { \
     488    {                                        \
     489      fprintf (FILE, "\tbrki\tr16,_mcount\n");           \
     490    }                                                    \
     491   }
     492  
     493  #define EXIT_IGNORE_STACK			1
     494  
     495  /* 4 insns + 2 words of data.  */
     496  #define TRAMPOLINE_SIZE				(6 * 4)
     497  
     498  #define TRAMPOLINE_ALIGNMENT			32
     499  
     500  #define REGNO_OK_FOR_BASE_P(regno)		microblaze_regno_ok_for_base_p ((regno), 1)
     501  
     502  #define REGNO_OK_FOR_INDEX_P(regno)		microblaze_regno_ok_for_base_p ((regno), 1)
     503  
     504  #ifndef REG_OK_STRICT
     505  #define REG_STRICT_FLAG				0
     506  #else
     507  #define REG_STRICT_FLAG				1
     508  #endif
     509  
     510  #define REG_OK_FOR_BASE_P(X)    \
     511    microblaze_regno_ok_for_base_p (REGNO (X), REG_STRICT_FLAG)
     512  
     513  #define REG_OK_FOR_INDEX_P(X)   \
     514    microblaze_regno_ok_for_base_p (REGNO (X), REG_STRICT_FLAG)
     515  
     516  #define MAX_REGS_PER_ADDRESS 2
     517  
     518  
     519  /* Identify valid constant addresses.  Exclude if PIC addr which 
     520     needs scratch register.  */
     521  #define CONSTANT_ADDRESS_P(X)	microblaze_constant_address_p(X)
     522  
     523  /* Define this, so that when PIC, reload won't try to reload invalid
     524     addresses which require two reload registers.  */
     525  #define LEGITIMATE_PIC_OPERAND_P(X)  microblaze_legitimate_pic_operand (X)
     526  
     527  #define CASE_VECTOR_MODE			(SImode)
     528  
     529  #ifndef DEFAULT_SIGNED_CHAR
     530  #define DEFAULT_SIGNED_CHAR			1
     531  #endif
     532  
     533  #define MOVE_MAX				4
     534  #define MAX_MOVE_MAX				8
     535  
     536  #define SLOW_BYTE_ACCESS			1
     537  
     538  /* sCOND operations return 1.  */
     539  #define STORE_FLAG_VALUE			1
     540  
     541  #define SHIFT_COUNT_TRUNCATED			1
     542  
     543  #define Pmode SImode
     544  
     545  #define FUNCTION_MODE   SImode
     546  
     547  /* Mode should always be SImode */
     548  #define REGISTER_MOVE_COST(MODE, FROM, TO)			\
     549    ( GR_REG_CLASS_P (FROM) && GR_REG_CLASS_P (TO) ? 2 		\
     550     : (FROM) == ST_REGS && GR_REG_CLASS_P (TO) ? 4		\
     551     : 12)
     552  
     553  #define MEMORY_MOVE_COST(MODE,CLASS,TO_P) \
     554    (4 + memory_move_secondary_cost ((MODE), (CLASS), (TO_P)))
     555  
     556  #define BRANCH_COST(speed_p, predictable_p)	2
     557  
     558  /* Control the assembler format that we output.  */
     559  #define ASM_APP_ON " #APP\n"
     560  #define ASM_APP_OFF " #NO_APP\n"
     561  
     562  #define REGISTER_NAMES {						\
     563    "r0",   "r1",   "r2",   "r3",   "r4",   "r5",   "r6",   "r7",		\
     564    "r8",   "r9",   "r10",  "r11",  "r12",  "r13",  "r14",  "r15",	\
     565    "r16",  "r17",  "r18",  "r19",  "r20",  "r21",  "r22",  "r23",	\
     566    "r24",  "r25",  "r26",  "r27",  "r28",  "r29",  "r30",  "r31",	\
     567    "rmsr", "$ap",  "$rap", "$frp" }
     568  
     569  #define ADDITIONAL_REGISTER_NAMES					\
     570  {									\
     571    { "r0",	 0 + GP_REG_FIRST },					\
     572    { "r1",	 1 + GP_REG_FIRST },					\
     573    { "r2",	 2 + GP_REG_FIRST },					\
     574    { "r3",	 3 + GP_REG_FIRST },					\
     575    { "r4",	 4 + GP_REG_FIRST },					\
     576    { "r5",	 5 + GP_REG_FIRST },					\
     577    { "r6",	 6 + GP_REG_FIRST },					\
     578    { "r7",	 7 + GP_REG_FIRST },					\
     579    { "r8",	 8 + GP_REG_FIRST },					\
     580    { "r9",	 9 + GP_REG_FIRST },					\
     581    { "r10",	10 + GP_REG_FIRST },					\
     582    { "r11",	11 + GP_REG_FIRST },					\
     583    { "r12",	12 + GP_REG_FIRST },					\
     584    { "r13",	13 + GP_REG_FIRST },					\
     585    { "r14",	14 + GP_REG_FIRST },					\
     586    { "r15",	15 + GP_REG_FIRST },					\
     587    { "r16",	16 + GP_REG_FIRST },					\
     588    { "r17",	17 + GP_REG_FIRST },					\
     589    { "r18",	18 + GP_REG_FIRST },					\
     590    { "r19",	19 + GP_REG_FIRST },					\
     591    { "r20",	20 + GP_REG_FIRST },					\
     592    { "r21",	21 + GP_REG_FIRST },					\
     593    { "r22",	22 + GP_REG_FIRST },					\
     594    { "r23",	23 + GP_REG_FIRST },					\
     595    { "r24",	24 + GP_REG_FIRST },					\
     596    { "r25",	25 + GP_REG_FIRST },					\
     597    { "r26",	26 + GP_REG_FIRST },					\
     598    { "r27",	27 + GP_REG_FIRST },					\
     599    { "r28",	28 + GP_REG_FIRST },					\
     600    { "r29",	29 + GP_REG_FIRST },					\
     601    { "r30",	30 + GP_REG_FIRST },					\
     602    { "r31",	31 + GP_REG_FIRST },					\
     603    { "rmsr",     ST_REG}							\
     604  }
     605  
     606  #define PRINT_OPERAND(FILE, X, CODE) print_operand (FILE, X, CODE)
     607  
     608  #define PRINT_OPERAND_PUNCT_VALID_P(CODE) microblaze_print_operand_punct[CODE]
     609  
     610  #define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address (FILE, ADDR)
     611  
     612  /* ASM_OUTPUT_ALIGNED_COMMON and ASM_OUTPUT_ALIGNED_LOCAL
     613  
     614     Unfortunately, we still need to set the section explicitly. Somehow,
     615     our binutils assign .comm and .lcomm variables to the "current" section 
     616     in the assembly file, rather than where they implicitly belong. We need to
     617     remove this explicit setting in GCC when binutils can understand sections
     618     better.  */
     619  #undef	ASM_OUTPUT_ALIGNED_COMMON
     620  #define	ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN)		\
     621  do {									\
     622    if ((SIZE) > 0 && (SIZE) <= INT_MAX					\
     623        && (int) (SIZE) <= microblaze_section_threshold			\
     624        && TARGET_XLGPOPT)						\
     625      {                                                                   \
     626        switch_to_section (sbss_section);					\
     627      }									\
     628    else									\
     629      {									\
     630        switch_to_section (bss_section);					\
     631      }                                                                   \
     632    fprintf (FILE, "%s", COMMON_ASM_OP);                                  \
     633    assemble_name ((FILE), (NAME));					\
     634    fprintf ((FILE), "," HOST_WIDE_INT_PRINT_UNSIGNED",%u\n",		\
     635             (SIZE), (ALIGN) / BITS_PER_UNIT);                            \
     636    ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object");			\
     637  } while (0)
     638  
     639  #undef ASM_OUTPUT_ALIGNED_LOCAL
     640  #define	ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN)		\
     641  do {									\
     642    if ((SIZE) > 0 && (SIZE) <= INT_MAX					\
     643        && (int) (SIZE) <= microblaze_section_threshold			\
     644        && TARGET_XLGPOPT)						\
     645      {                                                                   \
     646        switch_to_section (sbss_section);					\
     647      }									\
     648    else									\
     649      {									\
     650        switch_to_section (bss_section);					\
     651      }                                                                   \
     652    fprintf (FILE, "%s", LCOMMON_ASM_OP);                                 \
     653    assemble_name ((FILE), (NAME));					\
     654    fprintf ((FILE), "," HOST_WIDE_INT_PRINT_UNSIGNED",%u\n",		\
     655             (SIZE), (ALIGN) / BITS_PER_UNIT);                            \
     656    ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object");			\
     657  } while (0)
     658  
     659  #define	ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN)		\
     660  do {									\
     661    ASM_OUTPUT_ALIGNED_LOCAL (FILE, NAME, SIZE, ALIGN);			\
     662  } while (0)
     663  
     664  #define ASM_DECLARE_FUNCTION_NAME(STREAM,NAME,DECL)                     \
     665  {                                                                       \
     666  }
     667  
     668  #undef TARGET_ASM_CONSTRUCTOR
     669  #define TARGET_ASM_CONSTRUCTOR microblaze_elf_asm_constructor
     670  
     671  #undef TARGET_ASM_DESTRUCTOR
     672  #define TARGET_ASM_DESTRUCTOR microblaze_elf_asm_destructor
     673  
     674  #define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM)			\
     675    sprintf ((LABEL), "*%s%s%ld", (LOCAL_LABEL_PREFIX), (PREFIX), (long)(NUM))
     676  
     677  #define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE)				\
     678    fprintf (STREAM, "\t%s\t%sL%d\n",					\
     679  	   ".gpword",                                                   \
     680  	   LOCAL_LABEL_PREFIX, VALUE)
     681  
     682  #define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM, BODY, VALUE, REL)		\
     683  do {									\
     684    if (flag_pic == 2)                                               \
     685      fprintf (STREAM, "\t%s\t%sL%d@GOTOFF\n",                            \
     686  	     ".gpword",                                                 \
     687  	     LOCAL_LABEL_PREFIX, VALUE);				\
     688    else                                                                  \
     689      fprintf (STREAM, "\t%s\t%sL%d\n",					\
     690  	     ".gpword",                                                 \
     691  	     LOCAL_LABEL_PREFIX, VALUE);				\
     692  } while (0)
     693  
     694  #define ASM_OUTPUT_ALIGN(STREAM,LOG)					\
     695    fprintf (STREAM, "\t.align\t%d\n", (LOG))
     696  
     697  #define ASM_OUTPUT_SKIP(STREAM,SIZE)					\
     698    fprintf (STREAM, "\t.space\t" HOST_WIDE_INT_PRINT_UNSIGNED "\n", (SIZE))
     699  
     700  #define ASCII_DATA_ASM_OP		"\t.ascii\t"
     701  #define STRING_ASM_OP			"\t.asciz\t"
     702  
     703  #undef TARGET_ASM_OUTPUT_IDENT
     704  #define TARGET_ASM_OUTPUT_IDENT microblaze_asm_output_ident
     705  
     706  /* Default to -G 8 */
     707  #ifndef MICROBLAZE_DEFAULT_GVALUE
     708  #define MICROBLAZE_DEFAULT_GVALUE 8
     709  #endif
     710  
     711  /* Given a decl node or constant node, choose the section to output it in
     712     and select that section.  */
     713  
     714  /* Store in OUTPUT a string (made with alloca) containing
     715     an assembler-name for a local static variable named NAME.
     716     LABELNO is an integer which is different for each call.  */
     717  #define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO)			\
     718  ( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 13),			\
     719    sprintf ((OUTPUT), "%s.%lu", (NAME), (unsigned long)(LABELNO)))
     720  
     721  /* How to start an assembler comment.
     722     The leading space is important (the microblaze assembler requires it).  */
     723  #ifndef ASM_COMMENT_START
     724  #define ASM_COMMENT_START		" #"
     725  #endif
     726  
     727  #define BSS_VAR         1
     728  #define SBSS_VAR        2
     729  #define DATA_VAR        4
     730  #define SDATA_VAR       5
     731  #define RODATA_VAR      6
     732  #define SDATA2_VAR      7
     733  
     734  /* These definitions are used in with the shift_type flag in the rtl.  */
     735  #define SHIFT_CONST     1
     736  #define SHIFT_REG       2
     737  #define USE_ADDK        3
     738  
     739  /* Handle interrupt attribute.  */
     740  extern int interrupt_handler;
     741  extern int fast_interrupt;
     742  extern int save_volatiles;
     743  
     744  #define INTERRUPT_HANDLER_NAME "_interrupt_handler"
     745  /* The function name for the function tagged with attribute break_handler
     746     has been set in the RTL as _break_handler. This function name is used
     747     in the generation of directives .ent .end and .global. */
     748  #define BREAK_HANDLER_NAME "_break_handler"
     749  #define FAST_INTERRUPT_NAME "_fast_interrupt"
     750  
     751  /* The following #defines are used in the headers files. Always retain these.  */
     752  
     753  /* Added for declaring size at the end of the function.  */
     754  #undef ASM_DECLARE_FUNCTION_SIZE
     755  #define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL)			\
     756    do {									\
     757      if (!flag_inhibit_size_directive)					\
     758        {									\
     759          char label[256];						\
     760  	static int labelno;						\
     761  	labelno++;							\
     762  	ASM_GENERATE_INTERNAL_LABEL (label, "Lfe", labelno);		\
     763          (*targetm.asm_out.internal_label) (FILE, "Lfe", labelno);	\
     764  	fprintf (FILE, "%s", SIZE_ASM_OP);				\
     765  	assemble_name (FILE, (FNAME));					\
     766          fprintf (FILE, ",");						\
     767  	assemble_name (FILE, label);					\
     768          fprintf (FILE, "-");						\
     769  	assemble_name (FILE, (FNAME));					\
     770  	putc ('\n', FILE);						\
     771        }									\
     772    } while (0)
     773  
     774  #define GLOBAL_ASM_OP			"\t.globl\t"
     775  #define TYPE_ASM_OP			"\t.type\t"
     776  #define SIZE_ASM_OP			"\t.size\t"
     777  #define COMMON_ASM_OP			"\t.comm\t"
     778  #define LCOMMON_ASM_OP			"\t.lcomm\t"
     779  
     780  #define MAX_OFILE_ALIGNMENT		(32768*8)
     781  
     782  #define TYPE_OPERAND_FMT        	"@%s"
     783  
     784  /* Write the extra assembler code needed to declare an object properly.  */
     785  #undef ASM_DECLARE_OBJECT_NAME
     786  #define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL)			\
     787    do {									\
     788      fprintf (FILE, "%s", TYPE_ASM_OP);			         	\
     789      assemble_name (FILE, NAME);						\
     790      putc (',', FILE);							\
     791      fprintf (FILE, TYPE_OPERAND_FMT, "object");				\
     792      putc ('\n', FILE);							\
     793      size_directive_output = 0;						\
     794      if (!flag_inhibit_size_directive && DECL_SIZE (DECL))		\
     795        {									\
     796  	size_directive_output = 1;					\
     797  	fprintf (FILE, "%s", SIZE_ASM_OP);				\
     798  	assemble_name (FILE, NAME);					\
     799  	fprintf (FILE, "," HOST_WIDE_INT_PRINT_DEC "\n",		\
     800  	int_size_in_bytes (TREE_TYPE (DECL)));				\
     801        }									\
     802      microblaze_declare_object (FILE, NAME, "", ":\n", 0);			\
     803    } while (0)
     804  
     805  #undef ASM_FINISH_DECLARE_OBJECT
     806  #define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END)	 \
     807  do {									 \
     808       const char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0);		 \
     809       if (!flag_inhibit_size_directive && DECL_SIZE (DECL)		 \
     810           && ! AT_END && TOP_LEVEL					 \
     811  	 && DECL_INITIAL (DECL) == error_mark_node			 \
     812  	 && !size_directive_output)					 \
     813         {								 \
     814  	 size_directive_output = 1;					 \
     815  	 fprintf (FILE, "%s", SIZE_ASM_OP);			         \
     816  	 assemble_name (FILE, name);					 \
     817  	 fprintf (FILE, "," HOST_WIDE_INT_PRINT_DEC "\n",		 \
     818  		  int_size_in_bytes (TREE_TYPE (DECL)));		 \
     819         }								 \
     820     } while (0)
     821  
     822  #define ASM_OUTPUT_DEF(FILE,LABEL1,LABEL2)                            \
     823   do { fputc ( '\t', FILE);                                            \
     824        assemble_name (FILE, LABEL1);                                   \
     825        fputs ( " = ", FILE);                                           \
     826        assemble_name (FILE, LABEL2);                                   \
     827        fputc ( '\n', FILE);                                            \
     828   } while (0)
     829  
     830  #define ASM_WEAKEN_LABEL(FILE,NAME) 					\
     831   do { fputs ("\t.weakext\t", FILE);					\
     832        assemble_name (FILE, NAME);					\
     833        fputc ('\n', FILE);						\
     834      } while (0)
     835  
     836  #define MAKE_DECL_ONE_ONLY(DECL)	(DECL_WEAK (DECL) = 1)
     837  #undef UNIQUE_SECTION_P
     838  #define UNIQUE_SECTION_P(DECL)		(DECL_ONE_ONLY (DECL))
     839  
     840  #undef TARGET_ASM_NAMED_SECTION
     841  #define TARGET_ASM_NAMED_SECTION        default_elf_asm_named_section
     842  
     843  /* Define the strings to put out for each section in the object file.  
     844     
     845     Note: For ctors/dtors, we want to give these sections the SHF_WRITE 
     846     attribute to allow shared libraries to patch/resolve addresses into 
     847     these locations.  On Microblaze, there is no concept of shared libraries 
     848     yet, so this is for future use.  */
     849  #define TEXT_SECTION_ASM_OP	"\t.text"
     850  #define DATA_SECTION_ASM_OP	"\t.data"
     851  #define READONLY_DATA_SECTION_ASM_OP    \
     852                                  "\t.rodata"
     853  #define BSS_SECTION_ASM_OP      "\t.bss"
     854  #define CTORS_SECTION_ASM_OP    "\t.section\t.ctors,\"aw\""
     855  #define DTORS_SECTION_ASM_OP    "\t.section\t.dtors,\"aw\""
     856  #define INIT_SECTION_ASM_OP     "\t.section\t.init,\"ax\""
     857  #define FINI_SECTION_ASM_OP     "\t.section\t.fini,\"ax\""
     858  
     859  #define SDATA_SECTION_ASM_OP	"\t.sdata"	/* Small RW initialized data   */
     860  #define SDATA2_SECTION_ASM_OP	"\t.sdata2"	/* Small RO initialized data   */
     861  #define SBSS_SECTION_ASM_OP     "\t.sbss"	/* Small RW uninitialized data */
     862  #define SBSS2_SECTION_ASM_OP    "\t.sbss2"	/* Small RO uninitialized data */
     863  
     864  /* We do this to save a few 10s of code space that would be taken up
     865     by the call_FUNC () wrappers, used by the generic CRT_CALL_STATIC_FUNCTION
     866     definition in crtstuff.c.  */
     867  #define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC)	\
     868      asm ( SECTION_OP "\n"                               \
     869            "\tbrlid   r15, " #FUNC "\n\t nop\n"         \
     870            TEXT_SECTION_ASM_OP);
     871  
     872  /* We need to group -lm as well, since some Newlib math functions 
     873     reference __errno!  */
     874  #undef LIB_SPEC
     875  #define LIB_SPEC \
     876  "%{!nostdlib: \
     877  %{pg:-start-group -lxilprofile -lgloss -lxil -lc -lm -end-group } \
     878  %{!pg:-start-group -lgloss -lxil -lc -lm -end-group }} "
     879  
     880  /* microblaze-unknown-elf target has no support of C99 runtime */
     881  #undef TARGET_LIBC_HAS_FUNCTION
     882  #define TARGET_LIBC_HAS_FUNCTION no_c99_libc_has_function
     883  
     884  #undef  ENDFILE_SPEC
     885  #define ENDFILE_SPEC "crtend.o%s crtn.o%s"
     886  
     887  #define STARTFILE_EXECUTABLE_SPEC   "crt0.o%s crti.o%s crtbegin.o%s"
     888  #define STARTFILE_XMDSTUB_SPEC      "crt1.o%s crti.o%s crtbegin.o%s"
     889  #define STARTFILE_BOOTSTRAP_SPEC    "crt2.o%s crti.o%s crtbegin.o%s"
     890  #define STARTFILE_NOVECTORS_SPEC    "crt3.o%s crti.o%s crtbegin.o%s"
     891  #define STARTFILE_CRTINIT_SPEC      "%{!pg: %{!mno-clearbss: crtinit.o%s} \
     892  %{mno-clearbss: sim-crtinit.o%s}} \
     893  %{pg: %{!mno-clearbss: pgcrtinit.o%s} %{mno-clearbss: sim-pgcrtinit.o%s}}"
     894  
     895  #define STARTFILE_DEFAULT_SPEC      STARTFILE_EXECUTABLE_SPEC
     896  
     897  #undef SUBTARGET_EXTRA_SPECS
     898  #define	SUBTARGET_EXTRA_SPECS						\
     899    { "startfile_executable",	STARTFILE_EXECUTABLE_SPEC },		\
     900    { "startfile_xmdstub",	STARTFILE_XMDSTUB_SPEC },		\
     901    { "startfile_bootstrap",	STARTFILE_BOOTSTRAP_SPEC },		\
     902    { "startfile_novectors",	STARTFILE_NOVECTORS_SPEC },		\
     903    { "startfile_crtinit",        STARTFILE_CRTINIT_SPEC },               \
     904    { "startfile_default",	STARTFILE_DEFAULT_SPEC },
     905  
     906  #undef  STARTFILE_SPEC
     907  #define STARTFILE_SPEC  "\
     908  %{Zxl-mode-executable   : %(startfile_executable)  ; \
     909    mxl-mode-executable   : %(startfile_executable)  ; \
     910    Zxl-mode-xmdstub      : %(startfile_xmdstub)     ; \
     911    mxl-mode-xmdstub      : %(startfile_xmdstub)     ; \
     912    Zxl-mode-bootstrap    : %(startfile_bootstrap)   ; \
     913    mxl-mode-bootstrap    : %(startfile_bootstrap)   ; \
     914    Zxl-mode-novectors    : %(startfile_novectors)   ; \
     915    mxl-mode-novectors    : %(startfile_novectors)   ; \
     916    Zxl-mode-xilkernel    : %(startfile_xilkernel)   ; \
     917    mxl-mode-xilkernel    : %(startfile_xilkernel)   ; \
     918                          : %(startfile_default)       \
     919  } \
     920  %(startfile_crtinit)"