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

📄 arm.c

📁 gcc编译工具没有什么特别
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Output routines for GCC for ARM.   Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000   Free Software Foundation, Inc.   Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl)   and Martin Simmons (@harleqn.co.uk).   More major hacks by Richard Earnshaw (rearnsha@arm.com).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 "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 "flags.h"#include "reload.h"#include "tree.h"#include "expr.h"#include "toplev.h"#include "recog.h"/* The maximum number of insns skipped which will be conditionalised if   possible.  */static int max_insns_skipped = 5;extern FILE * asm_out_file;/* Some function declarations.  */static HOST_WIDE_INT int_log2 PROTO ((HOST_WIDE_INT));static char * output_multi_immediate PROTO ((rtx *, char *, char *, int,					    HOST_WIDE_INT));static int arm_gen_constant PROTO ((enum rtx_code, enum machine_mode,				    HOST_WIDE_INT, rtx, rtx, int, int));static int arm_naked_function_p PROTO ((tree));static void init_fpa_table PROTO ((void));static enum machine_mode select_dominance_cc_mode PROTO ((rtx, rtx,							  HOST_WIDE_INT));static HOST_WIDE_INT add_constant PROTO ((rtx, enum machine_mode, int *));static void dump_table PROTO ((rtx));static int fixit PROTO ((rtx, enum machine_mode, int));static rtx find_barrier PROTO ((rtx, int));static int broken_move PROTO ((rtx));static char * fp_const_from_val PROTO ((REAL_VALUE_TYPE *));static int eliminate_lr2ip PROTO ((rtx *));static char * shift_op PROTO ((rtx, HOST_WIDE_INT *));static int pattern_really_clobbers_lr PROTO ((rtx));static int function_really_clobbers_lr PROTO ((rtx));static void emit_multi_reg_push PROTO ((int));static void emit_sfm PROTO ((int, int));static enum arm_cond_code get_arm_condition_code PROTO ((rtx));static int const_ok_for_op RTX_CODE_PROTO ((HOST_WIDE_INT, Rcode));/* True if we are currently building a constant table. */int making_const_table;/*  Define the information needed to generate branch insns.  This is   stored from the compare operation. */rtx arm_compare_op0, arm_compare_op1;/* What type of floating point are we tuning for? */enum floating_point_type arm_fpu;/* What type of floating point instructions are available? */enum floating_point_type arm_fpu_arch;/* What program mode is the cpu running in? 26-bit mode or 32-bit mode */enum prog_mode_type arm_prgmode;/* Set by the -mfp=... option */const char * target_fp_name = NULL;/* Used to parse -mstructure_size_boundary command line option.  */const char * structure_size_string = NULL;int    arm_structure_size_boundary = 32; /* Used to be 8 *//* Bit values used to identify processor capabilities.  */#define FL_CO_PROC    0x01            /* Has external co-processor bus */#define FL_FAST_MULT  0x02            /* Fast multiply */#define FL_MODE26     0x04            /* 26-bit mode support */#define FL_MODE32     0x08            /* 32-bit mode support */#define FL_ARCH4      0x10            /* Architecture rel 4 */#define FL_THUMB      0x20            /* Thumb aware */#define FL_LDSCHED    0x40	      /* Load scheduling necessary */#define FL_STRONG     0x80	      /* StrongARM *//* The bits in this mask specify which instructions we are allowed to generate.  */static int insn_flags = 0;/* The bits in this mask specify which instruction scheduling options should   be used.  Note - there is an overlap with the FL_FAST_MULT.  For some   hardware we want to be able to generate the multiply instructions, but to   tune as if they were not present in the architecture.  */static int tune_flags = 0;/* The following are used in the arm.md file as equivalents to bits   in the above two flag variables.  *//* Nonzero if this is an "M" variant of the processor.  */int arm_fast_multiply = 0;/* Nonzero if this chip supports the ARM Architecture 4 extensions */int arm_arch4 = 0;/* Nonzero if this chip can benefit from load scheduling.  */int arm_ld_sched = 0;/* Nonzero if this chip is a StrongARM.  */int arm_is_strong = 0;/* Nonzero if this chip is a an ARM6 or an ARM7.  */int arm_is_6_or_7 = 0;/* In case of a PRE_INC, POST_INC, PRE_DEC, POST_DEC memory reference, we   must report the mode of the memory reference from PRINT_OPERAND to   PRINT_OPERAND_ADDRESS.  */enum machine_mode output_memory_reference_mode;/* Nonzero if the prologue must setup `fp'.  */int current_function_anonymous_args;/* The register number to be used for the PIC offset register.  */int arm_pic_register = 9;/* Location counter of .text segment.  */int arm_text_location = 0;/* Set to one if we think that lr is only saved because of subroutine calls,   but all of these can be `put after' return insns */int lr_save_eliminated;/* Set to 1 when a return insn is output, this means that the epilogue   is not needed. */static int return_used_this_function;/* Set to 1 after arm_reorg has started.  Reset to start at the start of   the next function.  */static int after_arm_reorg = 0;/* The maximum number of insns to be used when loading a constant.  */static int arm_constant_limit = 3;/* For an explanation of these variables, see final_prescan_insn below.  */int arm_ccfsm_state;enum arm_cond_code arm_current_cc;rtx arm_target_insn;int arm_target_label;/* The condition codes of the ARM, and the inverse function.  */char * arm_condition_codes[] ={  "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",  "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"};static enum arm_cond_code get_arm_condition_code ();#define streq(string1, string2) (strcmp (string1, string2) == 0)/* Initialization code */struct processors{  char *       name;  unsigned int flags;};/* Not all of these give usefully different compilation alternatives,   but there is no simple way of generalizing them.  */static struct processors all_cores[] ={  /* ARM Cores */    {"arm2",	FL_CO_PROC | FL_MODE26 },  {"arm250",	FL_CO_PROC | FL_MODE26 },  {"arm3",	FL_CO_PROC | FL_MODE26 },  {"arm6",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },  {"arm60",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },  {"arm600",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },  {"arm610",	             FL_MODE26 | FL_MODE32 },  {"arm620",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },  {"arm7",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },   {"arm7m",	FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT }, /* arm7m doesn't exist on its own, */  {"arm7d",	FL_CO_PROC | FL_MODE26 | FL_MODE32 }, 		     /* but only with D, (and I),       */  {"arm7dm",	FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT }, /* but those don't alter the code, */  {"arm7di",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },		     /* so arm7m is sometimes used.     */  {"arm7dmi",	FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT },  {"arm70",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },  {"arm700",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },  {"arm700i",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },  {"arm710",	             FL_MODE26 | FL_MODE32 },  {"arm710c",	             FL_MODE26 | FL_MODE32 },  {"arm7100",	             FL_MODE26 | FL_MODE32 },  {"arm7500",	             FL_MODE26 | FL_MODE32 },  {"arm7500fe",	FL_CO_PROC | FL_MODE26 | FL_MODE32 }, /* Doesn't really have an external co-proc, but does have embedded fpu.  */  {"arm7tdmi",	FL_CO_PROC |             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB },  {"arm8",	             FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED },  {"arm810",	             FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED },  {"arm9",	                         FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },  {"arm9tdmi",	                         FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },  {"strongarm",	             FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED | FL_STRONG },  {"strongarm110",           FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED | FL_STRONG },  {"strongarm1100",          FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED | FL_STRONG },    {NULL, 0}};static struct processors all_architectures[] ={  /* ARM Architectures */    {"armv2",     FL_CO_PROC | FL_MODE26 },  {"armv2a",    FL_CO_PROC | FL_MODE26 },  {"armv3",     FL_CO_PROC | FL_MODE26 | FL_MODE32 },  {"armv3m",    FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT },  {"armv4",     FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4  },  /* Strictly, FL_MODE26 is a permitted option for v4t, but there are no     implementations that support it, so we will leave it out for now.  */  {"armv4t",    FL_CO_PROC |             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB },  {NULL, 0}};/* This is a magic stucture.  The 'string' field is magically filled in   with a pointer to the value specified by the user on the command line   assuming that the user has specified such a value.  */struct arm_cpu_select arm_select[] ={  /* string	  name            processors  */	  { NULL,	"-mcpu=",	all_cores  },  { NULL,	"-march=",	all_architectures },  { NULL,	"-mtune=",	all_cores }};/* Return the number of bits set in value' */static unsigned intbit_count (value)     signed int value;{  unsigned int count = 0;    while (value)    {      value &= ~(value & - value);      ++ count;    }  return count;}/* Fix up any incompatible options that the user has specified.   This has now turned into a maze.  */voidarm_override_options (){  unsigned i;    /* Set up the flags based on the cpu/architecture selected by the user.  */  for (i = sizeof (arm_select) / sizeof (arm_select[0]); i--;)    {      struct arm_cpu_select * ptr = arm_select + i;            if (ptr->string != NULL && ptr->string[0] != '\0')        {	  struct processors * sel;          for (sel = ptr->processors; sel->name != NULL; sel ++)            if (streq (ptr->string, sel->name))              {		if (i == 2)		  tune_flags = sel->flags;		else		  {		    /* If we have been given an architecture and a processor		       make sure that they are compatible.  We only generate		       a warning though, and we prefer the CPU over the		       architecture. */		    if (insn_flags != 0 && (insn_flags ^ sel->flags))		      warning ("switch -mcpu=%s conflicts with -mtune= switch",			       ptr->string);		    		    insn_flags = sel->flags;		  }		                break;              }          if (sel->name == NULL)            error ("bad value (%s) for %s switch", ptr->string, ptr->name);        }    }    /* If the user did not specify a processor, choose one for them.  */  if (insn_flags == 0)    {      struct processors * sel;      unsigned int        sought;      static struct cpu_default      {	int    cpu;	char * name;      }      cpu_defaults[] =      {	{ TARGET_CPU_arm2,      "arm2" },	{ TARGET_CPU_arm6,      "arm6" },	{ TARGET_CPU_arm610,    "arm610" },	{ TARGET_CPU_arm710,	"arm710" },	{ TARGET_CPU_arm7m,     "arm7m" },	{ TARGET_CPU_arm7500fe, "arm7500fe" },	{ TARGET_CPU_arm7tdmi,  "arm7tdmi" },	{ TARGET_CPU_arm8,      "arm8" },	{ TARGET_CPU_arm810,    "arm810" },	{ TARGET_CPU_arm9,      "arm9" },	{ TARGET_CPU_strongarm, "strongarm" },	{ TARGET_CPU_generic,   "arm" },	{ 0, 0 }      };      struct cpu_default * def;	        /* Find the default.  */      for (def = cpu_defaults; def->name; def ++)	if (def->cpu == TARGET_CPU_DEFAULT)	  break;      /* Make sure we found the default CPU.  */      if (def->name == NULL)	abort ();            /* Find the default CPU's flags.  */      for (sel = all_cores; sel->name != NULL; sel ++)	if (streq (def->name, sel->name))	  break;            if (sel->name == NULL)	abort ();      insn_flags = sel->flags;            /* Now check to see if the user has specified some command line	 switch that require certain abilities from the cpu.  */      sought = 0;            if (TARGET_THUMB_INTERWORK)	{	  sought |= (FL_THUMB | FL_MODE32);	  	  /* Force apcs-32 to be used for interworking.  */	  target_flags |= ARM_FLAG_APCS_32;	  /* There are no ARM processor that supports both APCS-26 and	     interworking.  Therefore we force FL_MODE26 to be removed	     from insn_flags here (if it was set), so that the search	     below will always be able to find a compatible processor.  */	  insn_flags &= ~ FL_MODE26;	}            if (! TARGET_APCS_32)	sought |= FL_MODE26;      if (sought != 0 && ((sought & insn_flags) != sought))	{	  /* Try to locate a CPU type that supports all of the abilities	     of the default CPU, plus the extra abilities requested by	     the user.  */	  for (sel = all_cores; sel->name != NULL; sel ++)	    if ((sel->flags & sought) == (sought | insn_flags))	      break;	  if (sel->name == NULL)	    {	      unsigned int        current_bit_count = 0;	      struct processors * best_fit = NULL;	      	      /* Ideally we would like to issue an error message here		 saying that it was not possible to find a CPU compatible		 with the default CPU, but which also supports the command		 line options specified by the programmer, and so they		 ought to use the -mcpu=<name> command line option to		 override the default CPU type.		 Unfortunately this does not work with multilibing.  We		 need to be able to support multilibs for -mapcs-26 and for		 -mthumb-interwork and there is no CPU that can support both		 options.  Instead if we cannot find a cpu that has both the		 characteristics of the default cpu and the given command line		 options we scan the array again looking for a best match.  */	      for (sel = all_cores; sel->name != NULL; sel ++)		if ((sel->flags & sought) == sought)		  {		    unsigned int count;		    count = bit_count (sel->flags & insn_flags);		    if (count >= current_bit_count)		      {			best_fit = sel;			current_bit_count = count;		      }		  }	      if (best_fit == NULL)		abort ();	      else		sel = best_fit;	    }	  insn_flags = sel->flags;	}    }    /* If tuning has not been specified, tune for whichever processor or     architecture has been selected.  */  if (tune_flags == 0)    tune_flags = insn_flags;    /* Make sure that the processor choice does not conflict with any of the     other command line choices.  */  if (TARGET_APCS_32 && !(insn_flags & FL_MODE32))    {      /* If APCS-32 was not the default then it must have been set by the	 user, so issue a warning message.  If the user has specified	 "-mapcs-32 -mcpu=arm2" then we loose here.  */      if ((TARGET_DEFAULT & ARM_FLAG_APCS_32) == 0)	warning ("target CPU does not support APCS-32" );      target_flags &= ~ ARM_FLAG_APCS_32;    }  else if (! TARGET_APCS_32 && !(insn_flags & FL_MODE26))    {      warning ("target CPU does not support APCS-26" );      target_flags |= ARM_FLAG_APCS_32;    }    if (TARGET_THUMB_INTERWORK && !(insn_flags & FL_THUMB))    {      warning ("target CPU does not support interworking" );      target_flags &= ~ARM_FLAG_THUMB;    }    /* If interworking is enabled then APCS-32 must be selected as well.  */  if (TARGET_THUMB_INTERWORK)    {      if (! TARGET_APCS_32)	warning ("interworking forces APCS-32 to be used" );      target_flags |= ARM_FLAG_APCS_32;    }    if (TARGET_APCS_STACK && ! TARGET_APCS)    {      warning ("-mapcs-stack-check incompatible with -mno-apcs-frame");      target_flags |= ARM_FLAG_APCS_FRAME;    }    if (write_symbols != NO_DEBUG && flag_omit_frame_pointer)    warning ("-g with -fomit-frame-pointer may not give sensible debugging");    if (TARGET_POKE_FUNCTION_NAME)    target_flags |= ARM_FLAG_APCS_FRAME;

⌨️ 快捷键说明

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