⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 out-mips.c

📁 这是完整的gcc源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Subroutines for insn-output.c for MIPS   Contributed by A. Lichnewsky, lich@inria.inria.fr.   Changes by     Michael Meissner, meissner@osf.org.   Copyright (C) 1989, 1990 Free Software Foundation, Inc.This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 1, or (at your option)any later version.GNU CC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING.  If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */#include <stdio.h>#include <sys/types.h>#include <sys/file.h>#include "tree.h"#include "flags.h"#ifndef R_OK#define R_OK 4#define W_OK 2#define X_OK 1#endifextern void  debug_rtx ();extern void  abort_with_insn ();extern FILE *asm_out_file;extern tree current_function_decl;/* Global variables for machine-dependent things.  */char *reg_numchar[] = REGISTER_NUMCHAR;/* Threshold for data being put into the small data/bss area, instead   of the normal data area (references to the small data/bss area take   1 instruction, and use the global pointer, references to the normal   data area takes 2 instructions).  */int mips_section_threshold = -1;/* Count the number of .file directives, so that .loc is up to date.  */int num_source_filenames = 0;/* Count the number of words that are pushed to pass arguments.  */int stack_args_pushed = 0;/* # bytes for args preallocated by function_prolog. */int stack_args_preallocated = 0;/* Count of the number of functions created so far, in order to make   unique labels for omitting the frame pointer.  */int number_functions_processed = 0;/* Count the number of sdb related labels are generated (to find block   start and end boundaries).  */int sdb_label_count = 0;/* Next label # for each statment for Silicon Graphics IRIS systems. */int sym_lineno = 0;/* Non-zero if inside of a function, because the stupid MIPS asm can't   handle .files inside of functions.  */int inside_function = 0;/* String to be used for the unique name given to the difference between   the stack pointer and frame pointer when the frame pointer is to be   omitted.  */char *sp_fp_difference = 0;/* Files to separate the text and the data output, so that all of the data   can be emitted before the text, which will mean that the assembler will   generate smaller code, based on the global pointer.  */FILE *asm_out_data_file;FILE *asm_out_text_file;/* Linked list of all externals that are to be emitted when optimizing   for the global pointer if they haven't been declared by the end of   the program with an appropriate .comm or initialization.  */struct extern_list {  struct extern_list *next;	/* next external */  char *name;			/* name of the external */  int size;			/* size in bytes */} *extern_head = 0;/* Name of the current function.  */char *current_function_name;/* Size of the frame allocated for this function.  */int current_function_total_framesize;/* Number of bytes used to hold saved registers.  */int current_function_saved_reg_size;/* Return truth value of whether OP can be used as an operands   where a register or 16 bit unsigned integer is needed.  */intuns_arith_operand (op, mode)     rtx op;     enum machine_mode mode;{  return (register_operand (op, mode)	  || (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (op)));}/* Return truth value of whether OP can be used as an operands   where a 16 bit integer is needed  */intarith_operand (op, mode)     rtx op;     enum machine_mode mode;{  return (register_operand (op, mode)	  || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));}/* Return truth value of whether OP can be used as an operand in a two   address arithmetic insn (such as set 123456,%o4) of mode MODE.  */intarith32_operand (op, mode)     rtx op;     enum machine_mode mode;{  return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);}/* Return truth value of whether OP is a integer which fits in 16 bits  */intsmall_int (op, mode)     rtx op;     enum machine_mode mode;{  return (GET_CODE (op) == CONST_INT && SMALL_INT (op));}/* Argument support functions.  *//* Initialize CUMULATIVE_ARGS for a function.  */voidinit_cumulative_args (cum, fntype)     CUMULATIVE_ARGS cum;	/* argument info to initialize */     tree fntype;		/* tree ptr for function decl */{  tree param, next_param;  if (TARGET_DEBUGE_MODE)    {      fprintf (stderr, "\ninit_cumulative_args\n");      if (fntype != (tree)0)	{	  putc ('\n', stderr);	  debug_tree (fntype);	  putc ('\n', stderr);	}    }  cum->gp_reg_found = 0;  cum->arg_number = 0;  cum->arg_words = 0;  /* Determine if this function has variable arguments.  This is     indicated by the last argument being 'void_type_mode' if there     are no variable arguments.  The standard MIPS calling sequence     passes all arguments in the general purpose registers in this     case. */  for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0;       param != (tree)0;       param = next_param)    {      next_param = TREE_CHAIN (param);      if (next_param == (tree)0 && TREE_VALUE (param) != void_type_node)	cum->gp_reg_found = 1;    }  /* Determine if the function is returning a structure, if so,     advance by one argument.  */  if (fntype      && (TREE_CODE (fntype) == FUNCTION_TYPE || TREE_CODE (fntype) == METHOD_TYPE)      && TREE_TYPE (fntype) != 0)    {      tree ret_type = TREE_TYPE (fntype);      enum tree_code ret_code = TREE_CODE (ret_type);      if (ret_code == RECORD_TYPE || ret_code == UNION_TYPE)	{	  cum->gp_reg_found = 1;	  cum->arg_number = 1;	  cum->arg_words = 1;	}    }}/* Advance the argument to the next argument position.  */voidfunction_arg_advance (cum, mode, type, named)     CUMULATIVE_ARGS cum;	/* current arg information */     enum machine_mode mode;	/* current arg mode */     tree type;			/* type of the argument or 0 if lib support */{  if (TARGET_DEBUGE_MODE)    fprintf (stderr,	     "function_adv( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d )\n",	     cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode),	     type, named);  cum->arg_number++;  switch (mode)    {    default:      error ("Illegal mode given to function_arg_advance");      break;    case VOIDmode:      break;    case BLKmode:      cum->gp_reg_found = 1;      cum->arg_words += (int_size_in_bytes (type) + 3) / 4;      break;    case SFmode:      cum->arg_words++;      break;    case DFmode:      cum->arg_words += 2;      break;    case DImode:      cum->gp_reg_found = 1;      cum->arg_words += 2;      break;    case QImode:    case HImode:    case SImode:      cum->gp_reg_found = 1;      cum->arg_words++;      break;    }}/* Return a RTL expression containing the register for the given mode,   or 0 if the argument is too be passed on the stack.  */struct rtx_def *function_arg (cum, mode, type, named)     CUMULATIVE_ARGS cum;	/* current arg information */     enum machine_mode mode;	/* current arg mode */     tree type;			/* type of the argument or 0 if lib support */     int named;			/* != 0 for normal args, == 0 for ... args */{  int regbase = -1;  int bias = 0;  if (TARGET_DEBUGE_MODE)    fprintf (stderr,	     "function_arg( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d ) = ",	     cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode),	     type, named);  switch (mode)    {    default:      error ("Illegal mode given to function_arg");      break;    case SFmode:      if (cum->gp_reg_found || cum->arg_number >= 2)	regbase = GP_ARG_FIRST;      else {	regbase = FP_ARG_FIRST;	if (cum->arg_words == 1)	/* first arg was float */	  bias = 1;			/* use correct reg */      }      break;    case DFmode:      cum->arg_words += (cum->arg_words & 1);      regbase = (cum->gp_reg_found) ? GP_ARG_FIRST : FP_ARG_FIRST;      break;    case VOIDmode:    case BLKmode:    case QImode:    case HImode:    case SImode:    case DImode:      regbase = GP_ARG_FIRST;      break;    }  if (cum->arg_words >= MAX_ARGS_IN_REGISTERS)    {      if (TARGET_DEBUGE_MODE)	fprintf (stderr, "<stack>\n");      return 0;    }  if (regbase == -1)    abort ();  if (TARGET_DEBUGE_MODE)    fprintf (stderr, "%s\n", reg_numchar[ regbase + cum->arg_number + bias ]);  return gen_rtx (REG, mode, regbase + cum->arg_words + bias);}intfunction_arg_partial_nregs (cum, mode, type, named)     CUMULATIVE_ARGS cum;	/* current arg information */     enum machine_mode mode;	/* current arg mode */     tree type;			/* type of the argument or 0 if lib support */     int named;			/* != 0 for normal args, == 0 for ... args */{  if (mode == BLKmode && cum->arg_words < MAX_ARGS_IN_REGISTERS)    {      int words = (int_size_in_bytes (type) + 3) / 4;      if (words + cum->arg_words < MAX_ARGS_IN_REGISTERS)	return 0;		/* structure fits in registers */      if (TARGET_DEBUGE_MODE)	fprintf (stderr, "function_arg_partial_nregs = %d\n",		 MAX_ARGS_IN_REGISTERS - cum->arg_words);      return MAX_ARGS_IN_REGISTERS - cum->arg_words;    }  else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS-1)    {      if (TARGET_DEBUGE_MODE)	fprintf (stderr, "function_arg_partial_nregs = 1\n");      return 1;    }  return 0;}/* Routines to merge the compare and branch operators into a single entity.  */static  rtx branch_cmp_op[2];static  enum machine_mode branch_cmp_mode;/* Save the mode and operands on the current compare operator.  */voidcompare_collect (mode, op0, op1)     enum machine_mode mode;     rtx op0;     rtx op1;{  if (TARGET_DEBUGD_MODE)    {      fprintf (stderr, "compare_collect mode = %s, operands::",	       GET_MODE_NAME (mode));      debug_rtx (op0);      debug_rtx (op1);    }  branch_cmp_op[0] = op0;  branch_cmp_op[1] = op1;  branch_cmp_mode = mode;}/* Return the mode and operands saved with compare_collect for use   in a branch operator.  */voidcompare_restore (operands, mode, insn)     rtx *operands;     enum machine_mode *mode;     rtx insn;{  if (!branch_cmp_op[0] || !branch_cmp_op[1])    abort_with_insn (insn, "Compare_restore did not follow compare_collect");  if (TARGET_DEBUGD_MODE)    {      fprintf (stderr,	       "compare_restore returning mode = %s, operands:%X,%X:",	       GET_MODE_NAME (branch_cmp_mode),	       branch_cmp_op[0],	       branch_cmp_op[1]);      debug_rtx (branch_cmp_op[0]);      debug_rtx (branch_cmp_op[1]);    }  operands[0] = branch_cmp_op[0];  operands[1] = branch_cmp_op[1];  *mode = branch_cmp_mode;  /* If the next insn is not a JUMP (after accounting for line numbers),     zero out the branch_cmp_array.  Switch statements implemented as if's     tend to have multiple jumps.  */  do    {      insn = NEXT_INSN (insn);    }  while (insn && GET_CODE (insn) == NOTE);  if (!insn || GET_CODE (insn) != JUMP_INSN)    {      branch_cmp_op[0] = NULL;      branch_cmp_op[1] = NULL;      branch_cmp_mode = VOIDmode;    }}/* Print the options used in the assembly file.  */static struct {char *name; int value;} target_switches []  = TARGET_SWITCHES;voidprint_options (out)     FILE *out;{  int line_len;  int len;  int j;  char **p;  int mask = TARGET_DEFAULT;  extern char **save_argv;  extern char *version_string, *language_string;#if 0  /* Allow assembly language comparisons with -mdebug eliminating the     compiler version number and switch lists.  */  if (!TARGET_DEBUG_MODE)    {      fprintf (out, "\n # %s %s", language_string, version_string);#ifdef TARGET_VERSION_INTERNAL      TARGET_VERSION_INTERNAL (out);#endif#ifdef __GNUC__      fprintf (out, " compiled by GNU C\n\n");#else      fprintf (out, " compiled by CC\n\n");#endif      fprintf (out, " # Cc1 defaults:");      line_len = 32767;      for (j = 0; j < sizeof target_switches / sizeof target_switches[0]; j++)	if (target_switches[j].name[0] != '\0'	    && target_switches[j].value > 0	    && (target_switches[j].value & mask) == target_switches[j].value)	  {	    len = strlen (target_switches[j].name) + 1;	    if (len + line_len > 79)	      {		line_len = 2;		fputs ("\n #", out);	      }	    fprintf (out, " -m%s", target_switches[j].name);	    line_len += len;	  }      fprintf (out, "\n\n # Cc1 arguments (-G value = %d):",	       mips_section_threshold);      line_len = 32767;      for (p = &save_argv[1]; *p != (char *)0; p++)	if (**p == '-')	  {	    len = strlen (*p) + 1;	    if (len + line_len > 79)	      {		line_len = 2;		fputs ("\n #", out);	      }	    fprintf (out, " %s", *p);	    line_len += len;	  }      fputs ("\n\n", out);    }#endif}/* Abort after printing out a specific insn.  */voidabort_with_insn (insn, reason)     rtx insn;     char *reason;{  error (reason);  debug_rtx (insn);  abort ();}/* Write a message to stderr (for use in macros expanded in files that do not   include stdio.h).  */voidtrace (s, s1, s2)     char *s, *s1, *s2;{  fprintf (stderr, s, s1, s2);}/* Set up the threshold for data to go into the small data area, instead   of the normal data area, and detect any conflicts in the switches.  */voidoveride_options (){  register int i;  i = TARGET_GVALUE;  if (i >= 6)    i += 3;  mips_section_threshold = (i != 0) ? 1 << i : 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -