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

📄 i386.c

📁 GCC编译器源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Subroutines for insn-output.c for Intel X86.   Copyright (C) 1988, 92, 94, 95, 96, 1997 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 "except.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#ifndef CHECK_STACK_LIMIT#define CHECK_STACK_LIMIT -1#endif/* Type of an operand for ix86_{binary,unary}_operator_ok */enum reg_mem{  reg_p,  mem_p,  imm_p};/* Processor costs (relative to an add) */struct processor_costs i386_cost = {	/* 386 specific costs */  1,					/* cost of an add instruction */  1,					/* cost of a lea instruction */  3,					/* variable shift costs */  2,					/* constant shift costs */  6,					/* cost of starting a multiply */  1,					/* cost of multiply per each bit set */  23					/* cost of a divide/mod */};struct processor_costs i486_cost = {	/* 486 specific costs */  1,					/* cost of an add instruction */  1,					/* cost of a lea instruction */  3,					/* variable shift costs */  2,					/* constant shift costs */  12,					/* cost of starting a multiply */  1,					/* cost of multiply per each bit set */  40					/* cost of a divide/mod */};struct processor_costs pentium_cost = {  1,					/* cost of an add instruction */  1,					/* cost of a lea instruction */  4,					/* variable shift costs */  1,					/* constant shift costs */  11,					/* cost of starting a multiply */  0,					/* cost of multiply per each bit set */  25					/* cost of a divide/mod */};struct processor_costs pentiumpro_cost = {  1,					/* cost of an add instruction */  1,					/* cost of a lea instruction */  3,					/* variable shift costs */  1,					/* constant shift costs */  4,					/* cost of starting a multiply */  0,					/* cost of multiply per each bit set */  17					/* cost of a divide/mod */};struct processor_costs *ix86_cost = &pentium_cost;#define AT_BP(mode) (gen_rtx (MEM, (mode), frame_pointer_rtx))extern FILE *asm_out_file;extern char *strcat ();static void ix86_epilogue PROTO((int));static void ix86_prologue PROTO((int));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)();/* which cpu are we scheduling for */enum processor_type ix86_cpu;/* which instruction set architecture to use.  */int ix86_arch;/* Strings to hold which cpu and instruction set architecture  to use.  */char *ix86_cpu_string;		/* for -mcpu=<xxx> */char *ix86_arch_string;		/* for -march=<xxx> *//* 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;/* i386_regparm_string as a number */int i386_regparm;/* Alignment to use for loops and jumps:  *//* Power of two alignment for loops. */char *i386_align_loops_string;/* Power of two alignment for non-loop jumps. */char *i386_align_jumps_string;/* Values 1-5: see jump.c */int i386_branch_cost;char *i386_branch_cost_string;/* Power of two alignment for functions. */int i386_align_funcs;char *i386_align_funcs_string;/* Power of two alignment for loops. */int i386_align_loops;/* Power of two alignment for non-loop jumps. */int i386_align_jumps;/* 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, j, regno;  char *p;  int def_align;  static struct ptt    {      char *name;		/* Canonical processor name.  */      enum processor_type processor; /* Processor type enum value.  */      struct processor_costs *cost; /* Processor costs */      int target_enable;	/* Target flags to enable.  */      int target_disable;	/* Target flags to disable.  */    } processor_target_table[]      = {{PROCESSOR_I386_STRING, PROCESSOR_I386, &i386_cost, 0, 0},	   {PROCESSOR_I486_STRING, PROCESSOR_I486, &i486_cost, 0, 0},	   {PROCESSOR_I586_STRING, PROCESSOR_PENTIUM, &pentium_cost, 0, 0},	   {PROCESSOR_PENTIUM_STRING, PROCESSOR_PENTIUM, &pentium_cost, 0, 0},	   {PROCESSOR_I686_STRING, PROCESSOR_PENTIUMPRO, &pentiumpro_cost,	      0, 0},	   {PROCESSOR_PENTIUMPRO_STRING, PROCESSOR_PENTIUMPRO,	      &pentiumpro_cost, 0, 0}};  int ptt_size = sizeof (processor_target_table) / sizeof (struct ptt);#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' already specified in allocation order", ch);	  regs_allocated[regno] = 1;	}    }  if (ix86_arch_string == 0)    {      ix86_arch_string = PROCESSOR_PENTIUM_STRING;      if (ix86_cpu_string == 0)	ix86_cpu_string = PROCESSOR_DEFAULT_STRING;    }    for (i = 0; i < ptt_size; i++)    if (! strcmp (ix86_arch_string, processor_target_table[i].name))      {	ix86_arch = processor_target_table[i].processor;	if (ix86_cpu_string == 0)	  ix86_cpu_string = processor_target_table[i].name;	break;      }  if (i == ptt_size)    {      error ("bad value (%s) for -march= switch", ix86_arch_string);      ix86_arch_string = PROCESSOR_PENTIUM_STRING;      ix86_arch = PROCESSOR_DEFAULT;    }  if (ix86_cpu_string == 0)    ix86_cpu_string = PROCESSOR_DEFAULT_STRING;  for (j = 0; j < ptt_size; j++)    if (! strcmp (ix86_cpu_string, processor_target_table[j].name))      {	ix86_cpu = processor_target_table[j].processor;	ix86_cost = processor_target_table[j].cost;	if (i > j && (int) ix86_arch >= (int) PROCESSOR_PENTIUMPRO)	  error ("-mcpu=%s does not support -march=%s",		 ix86_cpu_string, ix86_arch_string);	target_flags |= processor_target_table[j].target_enable;	target_flags &= ~processor_target_table[j].target_disable;	break;      }  if (j == ptt_size)    {      error ("bad value (%s) for -mcpu= switch", ix86_cpu_string);      ix86_cpu_string = PROCESSOR_DEFAULT_STRING;      ix86_cpu = PROCESSOR_DEFAULT;    }  /* 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);    }  /* The 486 suffers more from non-aligned cache line fills, and the     larger code size results in a larger cache foot-print and more misses.     The 486 has a 16 byte cache line, pentium and pentiumpro have a 32 byte     cache line.  */  def_align = (TARGET_486) ? 4 : 2;  /* 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;  /* Validate -mbranch-cost= value, or provide default. */  if (i386_branch_cost_string)    {      i386_branch_cost = atoi (i386_branch_cost_string);      if (i386_branch_cost < 0 || i386_branch_cost > 5)	fatal ("-mbranch-cost=%d is not between 0 and 5",	       i386_branch_cost);    }  else    i386_branch_cost = 1;  /* Keep nonleaf frame pointers.  */  if (TARGET_OMIT_LEAF_FRAME_POINTER)    flag_omit_frame_pointer = 1;}/* 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 user did not specify a register allocation order, use natural order. */  else    {      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)	reg_alloc_order[i] = i;    }}voidoptimization_options (level)     int level;{  /* For -O2 and beyond, turn off -fschedule-insns by default.  It tends to     make the problem with not enough registers even worse.  */#ifdef INSN_SCHEDULING  if (level > 1)    flag_schedule_insns = 0;#endif}/* Sign-extend a 16-bit constant */struct rtx_def *i386_sext16_if_const (op)     struct rtx_def *op;{  if (GET_CODE (op) == CONST_INT)    {      HOST_WIDE_INT val = INTVAL (op);      HOST_WIDE_INT sext_val;      if (val & 0x8000)	sext_val = val | ~0xffff;      else	sext_val = val & 0xffff;      if (sext_val != val)	op = GEN_INT (sext_val);    }  return op;}/* Return nonzero if the rtx is aligned */static inti386_aligned_reg_p (regno)     int regno;{  return (regno == STACK_POINTER_REGNUM	  || (! flag_omit_frame_pointer && regno == FRAME_POINTER_REGNUM));}inti386_aligned_p (op)     rtx op;{  /* Registers and immediate operands are always "aligned". */  if (GET_CODE (op) != MEM)    return 1;  /* Don't even try to do any aligned optimizations with volatiles. */  if (MEM_VOLATILE_P (op))    return 0;  /* Get address of memory operand. */  op = XEXP (op, 0);  switch (GET_CODE (op))    {    case CONST_INT:      if (INTVAL (op) & 3)	break;      return 1;      /* Match "reg + offset" */    case PLUS:      if (GET_CODE (XEXP (op, 1)) != CONST_INT)	break;      if (INTVAL (XEXP (op, 1)) & 3)	break;      op = XEXP (op, 0);      if (GET_CODE (op) != REG)	break;      /* ... fall through ... */    case REG:

⌨️ 快捷键说明

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