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

📄 i386.c

📁 gcc库的原代码,对编程有很大帮助.
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Subroutines for insn-output.c for Intel X86.   Copyright (C) 1988, 1992, 1994, 1995 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 2, 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, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA.  */#include <stdio.h>#include <setjmp.h>#include <ctype.h>#include "config.h"#include "rtl.h"#include "regs.h"#include "hard-reg-set.h"#include "real.h"#include "insn-config.h"#include "conditions.h"#include "insn-flags.h"#include "output.h"#include "insn-attr.h"#include "tree.h"#include "flags.h"#include "function.h"#ifdef EXTRA_CONSTRAINT/* If EXTRA_CONSTRAINT is defined, then the 'S'   constraint in REG_CLASS_FROM_LETTER will no longer work, and various   asm statements that need 'S' for class SIREG will break.  */ error EXTRA_CONSTRAINT conflicts with S constraint letter/* The previous line used to be #error, but some compilers barf   even if the conditional was untrue.  */#endif#define AT_BP(mode) (gen_rtx (MEM, (mode), frame_pointer_rtx))extern FILE *asm_out_file;extern char *strcat ();char *singlemove_string ();char *output_move_const_single ();char *output_fp_cc0_set ();char *hi_reg_name[] = HI_REGISTER_NAMES;char *qi_reg_name[] = QI_REGISTER_NAMES;char *qi_high_reg_name[] = QI_HIGH_REGISTER_NAMES;/* Array of the smallest class containing reg number REGNO, indexed by   REGNO.  Used by REGNO_REG_CLASS in i386.h. */enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] ={  /* ax, dx, cx, bx */  AREG, DREG, CREG, BREG,  /* si, di, bp, sp */  SIREG, DIREG, INDEX_REGS, GENERAL_REGS,  /* FP registers */  FP_TOP_REG, FP_SECOND_REG, FLOAT_REGS, FLOAT_REGS,  FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,         /* arg pointer */  INDEX_REGS};/* Test and compare insns in i386.md store the information needed to   generate branch and scc insns here.  */struct rtx_def *i386_compare_op0 = NULL_RTX;struct rtx_def *i386_compare_op1 = NULL_RTX;struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)();/* Register allocation order */char *i386_reg_alloc_order;static char regs_allocated[FIRST_PSEUDO_REGISTER];/* # of registers to use to pass arguments. */char *i386_regparm_string;			/* # registers to use to pass args */int i386_regparm;				/* i386_regparm_string as a number *//* Alignment to use for loops and jumps */char *i386_align_loops_string;			/* power of two alignment for loops */char *i386_align_jumps_string;			/* power of two alignment for non-loop jumps */char *i386_align_funcs_string;			/* power of two alignment for functions */int i386_align_loops;				/* power of two alignment for loops */int i386_align_jumps;				/* power of two alignment for non-loop jumps */int i386_align_funcs;				/* power of two alignment for functions *//* Sometimes certain combinations of command options do not make   sense on a particular target machine.  You can define a macro   `OVERRIDE_OPTIONS' to take account of this.  This macro, if   defined, is executed once just after all the command options have   been parsed.   Don't use this macro to turn on various extra optimizations for   `-O'.  That is what `OPTIMIZATION_OPTIONS' is for.  */voidoverride_options (){  int ch, i, regno;  char *p;  int def_align;#ifdef SUBTARGET_OVERRIDE_OPTIONS  SUBTARGET_OVERRIDE_OPTIONS;#endif  /* Validate registers in register allocation order */  if (i386_reg_alloc_order)    {      for (i = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++)	{	  switch (ch)	    {	    case 'a':	regno = 0;	break;	    case 'd':	regno = 1;	break;	    case 'c':	regno = 2;	break;	    case 'b':	regno = 3;	break;	    case 'S':	regno = 4;	break;	    case 'D':	regno = 5;	break;	    case 'B':	regno = 6;	break;	    default:	fatal ("Register '%c' is unknown", ch);	    }	  if (regs_allocated[regno])	    fatal ("Register '%c' was already specified in the allocation order", ch);	  regs_allocated[regno] = 1;	}    }  /* Validate -mregparm= value */  if (i386_regparm_string)    {      i386_regparm = atoi (i386_regparm_string);      if (i386_regparm < 0 || i386_regparm > REGPARM_MAX)	fatal ("-mregparm=%d is not between 0 and %d", i386_regparm, REGPARM_MAX);    }  def_align = (TARGET_386) ? 2 : 4;  /* Validate -malign-loops= value, or provide default */  if (i386_align_loops_string)    {      i386_align_loops = atoi (i386_align_loops_string);      if (i386_align_loops < 0 || i386_align_loops > MAX_CODE_ALIGN)	fatal ("-malign-loops=%d is not between 0 and %d",	       i386_align_loops, MAX_CODE_ALIGN);    }  else    i386_align_loops = 2;  /* Validate -malign-jumps= value, or provide default */  if (i386_align_jumps_string)    {      i386_align_jumps = atoi (i386_align_jumps_string);      if (i386_align_jumps < 0 || i386_align_jumps > MAX_CODE_ALIGN)	fatal ("-malign-jumps=%d is not between 0 and %d",	       i386_align_jumps, MAX_CODE_ALIGN);    }  else    i386_align_jumps = def_align;  /* Validate -malign-functions= value, or provide default */  if (i386_align_funcs_string)    {      i386_align_funcs = atoi (i386_align_funcs_string);      if (i386_align_funcs < 0 || i386_align_funcs > MAX_CODE_ALIGN)	fatal ("-malign-functions=%d is not between 0 and %d",	       i386_align_funcs, MAX_CODE_ALIGN);    }  else    i386_align_funcs = def_align;}/* A C statement (sans semicolon) to choose the order in which to   allocate hard registers for pseudo-registers local to a basic   block.   Store the desired register order in the array `reg_alloc_order'.   Element 0 should be the register to allocate first; element 1, the   next register; and so on.   The macro body should not assume anything about the contents of   `reg_alloc_order' before execution of the macro.   On most machines, it is not necessary to define this macro.  */voidorder_regs_for_local_alloc (){  int i, ch, order, regno;  /* User specified the register allocation order */  if (i386_reg_alloc_order)    {      for (i = order = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++)	{	  switch (ch)	    {	    case 'a':	regno = 0;	break;	    case 'd':	regno = 1;	break;	    case 'c':	regno = 2;	break;	    case 'b':	regno = 3;	break;	    case 'S':	regno = 4;	break;	    case 'D':	regno = 5;	break;	    case 'B':	regno = 6;	break;	    }	  reg_alloc_order[order++] = regno;	}      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)	{	  if (!regs_allocated[i])	    reg_alloc_order[order++] = i;	}    }  /* If users did not specify a register allocation order, favor eax     normally except if DImode variables are used, in which case     favor edx before eax, which seems to cause less spill register     not found messages.  */  else    {      rtx insn;      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)	reg_alloc_order[i] = i;      if (optimize)	{	  int use_dca = FALSE;	  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))	    {	      if (GET_CODE (insn) == INSN)		{		  rtx set = NULL_RTX;		  rtx pattern = PATTERN (insn);		  if (GET_CODE (pattern) == SET)		    set = pattern;		  else if ((GET_CODE (pattern) == PARALLEL			    || GET_CODE (pattern) == SEQUENCE)			   && GET_CODE (XVECEXP (pattern, 0, 0)) == SET)		    set = XVECEXP (pattern, 0, 0);		  if (set && GET_MODE (SET_SRC (set)) == DImode)		    {		      use_dca = TRUE;		      break;		    }		}	    }	  if (use_dca)	    {	      reg_alloc_order[0] = 1;	/* edx */	      reg_alloc_order[1] = 2;	/* ecx */	      reg_alloc_order[2] = 0;	/* eax */	    }	}    }}/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific   attribute for DECL.  The attributes in ATTRIBUTES have previously been   assigned to DECL.  */inti386_valid_decl_attribute_p (decl, attributes, identifier, args)     tree decl;     tree attributes;     tree identifier;     tree args;{  return 0;}/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific   attribute for TYPE.  The attributes in ATTRIBUTES have previously been   assigned to TYPE.  */inti386_valid_type_attribute_p (type, attributes, identifier, args)     tree type;     tree attributes;     tree identifier;     tree args;{  if (TREE_CODE (type) != FUNCTION_TYPE      && TREE_CODE (type) != FIELD_DECL      && TREE_CODE (type) != TYPE_DECL)    return 0;  /* Stdcall attribute says callee is responsible for popping arguments     if they are not variable.  */  if (is_attribute_p ("stdcall", identifier))    return (args == NULL_TREE);  /* Cdecl attribute says the callee is a normal C declaration */  if (is_attribute_p ("cdecl", identifier))    return (args == NULL_TREE);  /* Regparm attribute specifies how many integer arguments are to be     passed in registers */  if (is_attribute_p ("regparm", identifier))    {      tree cst;      if (!args || TREE_CODE (args) != TREE_LIST	  || TREE_CHAIN (args) != NULL_TREE	  || TREE_VALUE (args) == NULL_TREE)	return 0;      cst = TREE_VALUE (args);      if (TREE_CODE (cst) != INTEGER_CST)	return 0;      if (TREE_INT_CST_HIGH (cst) != 0	  || TREE_INT_CST_LOW (cst) < 0	  || TREE_INT_CST_LOW (cst) > REGPARM_MAX)	return 0;      return 1;    }  return 0;}/* Return 0 if the attributes for two types are incompatible, 1 if they   are compatible, and 2 if they are nearly compatible (which causes a   warning to be generated).  */inti386_comp_type_attributes (type1, type2)     tree type1;     tree type2;{  return 1;}/* Value is the number of bytes of arguments automatically   popped when returning from a subroutine call.   FUNDECL is the declaration node of the function (as a tree),   FUNTYPE is the data type of the function (as a tree),   or for a library call it is an identifier node for the subroutine name.   SIZE is the number of bytes of arguments passed on the stack.   On the 80386, the RTD insn may be used to pop them if the number     of args is fixed, but if the number is variable then the caller     must pop them all.  RTD can't be used for library calls now     because the library is compiled with the Unix compiler.   Use of RTD is a selectable option, since it is incompatible with   standard Unix calling sequences.  If the option is not selected,   the caller must always pop the args.   The attribute stdcall is equivalent to RTD on a per module basis.  */inti386_return_pops_args (fundecl, funtype, size)     tree fundecl;     tree funtype;     int size;{  int rtd = TARGET_RTD;  if (TREE_CODE (funtype) == IDENTIFIER_NODE)    return 0;  /* Cdecl functions override -mrtd, and never pop the stack */  if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype)))    return 0;  /* Stdcall functions will pop the stack if not variable args */  if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype)))    rtd = 1;  if (rtd)    {      if (TYPE_ARG_TYPES (funtype) == NULL_TREE	  || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node))	return size;      if (aggregate_value_p (TREE_TYPE (funtype)))	return GET_MODE_SIZE (Pmode);    }  return 0;}/* Argument support functions.  *//* Initialize a variable CUM of type CUMULATIVE_ARGS   for a call to a function whose data type is FNTYPE.   For a library call, FNTYPE is 0.  */voidinit_cumulative_args (cum, fntype, libname)     CUMULATIVE_ARGS *cum;	/* argument info to initialize */     tree fntype;		/* tree ptr for function decl */     rtx libname;		/* SYMBOL_REF of library name or 0 */{  static CUMULATIVE_ARGS zero_cum;  tree param, next_param;  if (TARGET_DEBUG_ARG)    {      fprintf (stderr, "\ninit_cumulative_args (");      if (fntype)	{	  tree ret_type = TREE_TYPE (fntype);	  fprintf (stderr, "fntype code = %s, ret code = %s",		   tree_code_name[ (int)TREE_CODE (fntype) ],		   tree_code_name[ (int)TREE_CODE (ret_type) ]);	}      else	fprintf (stderr, "no fntype");      if (libname)	fprintf (stderr, ", libname = %s", XSTR (libname, 0));    }  *cum = zero_cum;  /* Set up the number of registers to use for passing arguments.  */  cum->nregs = i386_regparm;  if (fntype)    {      tree attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (fntype));      if (attr)	cum->nregs = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr)));    }  /* Determine if this function has variable arguments.  This is     indicated by the last argument being 'void_type_mode' if there     are no variable arguments.  If there are variable arguments, then     we won't pass anything in registers */  if (cum->nregs)    {      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->nregs = 0;	}    }  if (TARGET_DEBUG_ARG)    fprintf (stderr, ", nregs=%d )\n", cum->nregs);  return;}/* Update the data in CUM to advance over an argument   of mode MODE and data type TYPE.   (TYPE is null for libcalls where that information may not be available.)  */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 */

⌨️ 快捷键说明

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