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

📄 i386.c

📁 gcc编译工具没有什么特别
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Subroutines for insn-output.c for Intel X86.   Copyright (C) 1988, 92, 94-98, 1999 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 <setjmp.h>#include "config.h"#include "system.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"#include "recog.h"#include "expr.h"#include "toplev.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 */};/* We use decoding time together with execution time.    To get correct vale add 1 for short decodable, 2 for long decodable   and 4 for vector decodable instruction to execution time and divide   by two (because CPU is able to do two insns at a time). */struct processor_costs k6_cost = {  1,					/* cost of an add instruction */  1,					/* cost of a lea instruction */  1,					/* variable shift costs */  1,					/* constant shift costs */  3,					/* cost of starting a multiply */  0,					/* cost of multiply per each bit set */  20					/* cost of a divide/mod */};struct processor_costs *ix86_cost = &pentium_cost;/* Processor feature/optimization bitmasks.  */#define m_386 (1<<PROCESSOR_I386)#define m_486 (1<<PROCESSOR_I486)#define m_PENT (1<<PROCESSOR_PENTIUM)#define m_PPRO (1<<PROCESSOR_PENTIUMPRO)#define m_K6  (1<<PROCESSOR_K6)const int x86_use_leave = m_386 | m_K6;const int x86_push_memory = m_386 | m_K6;const int x86_zero_extend_with_and = m_486 | m_PENT;const int x86_movx = m_386 | m_PPRO | m_K6;const int x86_double_with_add = ~(m_386 | m_PENT | m_PPRO);const int x86_use_bit_test = m_386;const int x86_unroll_strlen = m_486 | m_PENT | m_PPRO;const int x86_use_q_reg = m_PENT | m_PPRO | m_K6;const int x86_use_any_reg = m_486;const int x86_cmove = m_PPRO;const int x86_deep_branch = m_PPRO| m_K6;#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;/* Power of two alignment for stack boundary in bytes.  */char *i386_preferred_stack_boundary_string;/* Preferred alignment for stack boundary in bits.  */int i386_preferred_stack_boundary;/* 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;  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},      {PROCESSOR_K6_STRING, PROCESSOR_K6, &k6_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++)	{	  int regno = 0;	  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_K6)	  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.  */#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN  i386_align_loops = 4;#else  i386_align_loops = 2;#endif  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);    }  /* Validate -malign-jumps= value, or provide default.  */#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN  i386_align_jumps = 4;#else  i386_align_jumps = def_align;#endif  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);    }  /* Validate -malign-functions= value, or provide default. */  i386_align_funcs = def_align;  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);    }  /* Validate -mpreferred_stack_boundary= value, or provide default.     The default of 128 bits is for Pentium III's SSE __m128.  */  i386_preferred_stack_boundary = 128;  if (i386_preferred_stack_boundary_string)    {      i = atoi (i386_preferred_stack_boundary_string);      if (i < 2 || i > 31)	fatal ("-mpreferred_stack_boundary=%d is not between 2 and 31", i);      i386_preferred_stack_boundary = (1 << i) * BITS_PER_UNIT;    }  /* Validate -mbranch-cost= value, or provide default. */  i386_branch_cost = 1;  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);    }  /* 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;  /* User specified the register allocation order.  */  if (i386_reg_alloc_order)    {      for (i = order = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++)	{	  int regno = 0;	  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, size)     int level;     int size ATTRIBUTE_UNUSED;{  /* For -O2 and beyond, turn off -fschedule-insns by default.  It tends to

⌨️ 快捷键说明

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