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

📄 arm.c

📁 gcc库的原代码,对编程有很大帮助.
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Output routines for GCC for ARM/RISCiX.   Copyright (C) 1991, 1993, 1994, 1995 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 (rwe11@cl.cam.ac.uk)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 <string.h>#include "assert.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 "flags.h"#include "reload.h"#include "tree.h"#include "expr.h"/* The maximum number of insns skipped which will be conditionalised if   possible.  */#define MAX_INSNS_SKIPPED  5/* Some function declarations.  */extern FILE *asm_out_file;extern char *output_multi_immediate ();extern void arm_increase_location ();HOST_WIDE_INT int_log2 PROTO ((HOST_WIDE_INT));static int get_prologue_size PROTO ((void));/*  Define the information needed to generate branch insns.  This is   stored from the compare operation. */rtx arm_compare_op0, arm_compare_op1;int arm_compare_fp;/* What type of cpu are we compiling for? */enum processor_type arm_cpu;/* What type of floating point are we compiling for? */enum floating_point_type arm_fpu;/* 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;/* 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;/* A hash table is used to store text segment labels and their associated   offset from the start of the text segment.  */struct label_offset{  char *name;  int offset;  struct label_offset *cdr;};#define LABEL_HASH_SIZE  257static struct label_offset *offset_table[LABEL_HASH_SIZE];/* Set to 1 when a return insn is output, this means that the epilogue   is not needed. */static int return_used_this_function;/* For an explanation of these variables, see final_prescan_insn below.  */int arm_ccfsm_state;int 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"};#define ARM_INVERSE_CONDITION_CODE(X)  ((X) ^ 1)/* Return 1 if it is possible to return using a single instruction */intuse_return_insn (){  int regno;  if (!reload_completed ||current_function_pretend_args_size      || current_function_anonymous_args      || (get_frame_size () && !(TARGET_APCS || frame_pointer_needed)))    return 0;  /* Can't be done if any of the FPU regs are pushed, since this also     requires an insn */  for (regno = 20; regno < 24; regno++)    if (regs_ever_live[regno])      return 0;  return 1;}/* Return TRUE if int I is a valid immediate ARM constant.  */intconst_ok_for_arm (i)     HOST_WIDE_INT i;{  unsigned HOST_WIDE_INT mask = ~0xFF;  /* Fast return for 0 and powers of 2 */  if ((i & (i - 1)) == 0)    return TRUE;  do    {      if ((i & mask & (unsigned HOST_WIDE_INT) 0xffffffff) == 0)        return TRUE;      mask =	  (mask << 2) | ((mask & (unsigned HOST_WIDE_INT) 0xffffffff)			 >> (32 - 2)) | ~((unsigned HOST_WIDE_INT) 0xffffffff);    } while (mask != ~0xFF);  return FALSE;}/* Return true if I is a valid constant for the operation CODE. */intconst_ok_for_op (i, code, mode)     HOST_WIDE_INT i;     enum rtx_code code;     enum machine_mode mode;{  if (const_ok_for_arm (i))    return 1;  switch (code)    {    case PLUS:      return const_ok_for_arm (ARM_SIGN_EXTEND (-i));    case MINUS:		/* Should only occur with (MINUS I reg) => rsb */    case XOR:    case IOR:      return 0;    case AND:      return const_ok_for_arm (ARM_SIGN_EXTEND (~i));    default:      abort ();    }}/* Emit a sequence of insns to handle a large constant.   CODE is the code of the operation required, it can be any of SET, PLUS,   IOR, AND, XOR, MINUS;   MODE is the mode in which the operation is being performed;   VAL is the integer to operate on;   SOURCE is the other operand (a register, or a null-pointer for SET);   SUBTARGETS means it is safe to create scratch registers if that will   either produce a simpler sequence, or we will want to cse the values. */intarm_split_constant (code, mode, val, target, source, subtargets)     enum rtx_code code;     enum machine_mode mode;     HOST_WIDE_INT val;     rtx target;     rtx source;     int subtargets;{  int can_add = 0;  int can_invert = 0;  int can_negate = 0;  int can_negate_initial = 0;  int can_shift = 0;  int i;  int num_bits_set = 0;  int set_sign_bit_copies = 0;  int clear_sign_bit_copies = 0;  int clear_zero_bit_copies = 0;  int set_zero_bit_copies = 0;  int insns = 0;  rtx new_src;  unsigned HOST_WIDE_INT temp1, temp2;  unsigned HOST_WIDE_INT remainder = val & 0xffffffff;  /* find out which operations are safe for a given CODE.  Also do a quick     check for degenerate cases; these can occur when DImode operations     are split.  */  switch (code)    {    case SET:      can_invert = 1;      can_shift = 1;      can_negate = 1;      break;    case PLUS:      can_negate = 1;      can_negate_initial = 1;      break;    case IOR:      if (remainder == 0xffffffff)	{	  emit_insn (gen_rtx (SET, VOIDmode, target,			      GEN_INT (ARM_SIGN_EXTEND (val))));	  return 1;	}      if (remainder == 0)	{	  if (reload_completed && rtx_equal_p (target, source))	    return 0;	  emit_insn (gen_rtx (SET, VOIDmode, target, source));	  return 1;	}      break;    case AND:      if (remainder == 0)	{	  emit_insn (gen_rtx (SET, VOIDmode, target, const0_rtx));	  return 1;	}      if (remainder == 0xffffffff)	{	  if (reload_completed && rtx_equal_p (target, source))	    return 0;	  emit_insn (gen_rtx (SET, VOIDmode, target, source));	  return 1;	}      can_invert = 1;      break;    case XOR:      if (remainder == 0)	{	  if (reload_completed && rtx_equal_p (target, source))	    return 0;	  emit_insn (gen_rtx (SET, VOIDmode, target, source));	  return 1;	}      if (remainder == 0xffffffff)	{	  emit_insn (gen_rtx (SET, VOIDmode, target,			      gen_rtx (NOT, mode, source)));	  return 1;	}      /* We don't know how to handle this yet below.  */      abort ();    case MINUS:      /* We treat MINUS as (val - source), since (source - val) is always	 passed as (source + (-val)).  */      if (remainder == 0)	{	  emit_insn (gen_rtx (SET, VOIDmode, target,			      gen_rtx (NEG, mode, source)));	  return 1;	}      if (const_ok_for_arm (val))	{	  emit_insn (gen_rtx (SET, VOIDmode, target, 			      gen_rtx (MINUS, mode, GEN_INT (val), source)));	  return 1;	}      can_negate = 1;      break;    default:      abort ();    }  /* If we can do it in one insn get out quickly */  if (const_ok_for_arm (val)      || (can_negate_initial && const_ok_for_arm (-val))      || (can_invert && const_ok_for_arm (~val)))    {      emit_insn (gen_rtx (SET, VOIDmode, target,			  (source ? gen_rtx (code, mode, source,					     GEN_INT (val)) : GEN_INT (val))));      return 1;    }  /* Calculate a few attributes that may be useful for specific     optimizations. */  for (i = 31; i >= 0; i--)    {      if ((remainder & (1 << i)) == 0)	clear_sign_bit_copies++;      else	break;    }  for (i = 31; i >= 0; i--)    {      if ((remainder & (1 << i)) != 0)	set_sign_bit_copies++;      else	break;    }  for (i = 0; i <= 31; i++)    {      if ((remainder & (1 << i)) == 0)	clear_zero_bit_copies++;      else	break;    }  for (i = 0; i <= 31; i++)    {      if ((remainder & (1 << i)) != 0)	set_zero_bit_copies++;      else	break;    }  switch (code)    {    case SET:      /* See if we can do this by sign_extending a constant that is known	 to be negative.  This is a good, way of doing it, since the shift	 may well merge into a subsequent insn.  */      if (set_sign_bit_copies > 1)	{	  if (const_ok_for_arm	      (temp1 = ARM_SIGN_EXTEND (remainder 					<< (set_sign_bit_copies - 1))))	    {	      new_src = subtargets ? gen_reg_rtx (mode) : target;	      emit_insn (gen_rtx (SET, VOIDmode, new_src, GEN_INT (temp1)));	      emit_insn (gen_ashrsi3 (target, new_src, 				      GEN_INT (set_sign_bit_copies - 1)));	      return 2;	    }	  /* For an inverted constant, we will need to set the low bits,	     these will be shifted out of harm's way.  */	  temp1 |= (1 << (set_sign_bit_copies - 1)) - 1;	  if (const_ok_for_arm (~temp1))	    {	      new_src = subtargets ? gen_reg_rtx (mode) : target;	      emit_insn (gen_rtx (SET, VOIDmode, new_src, GEN_INT (temp1)));	      emit_insn (gen_ashrsi3 (target, new_src, 				      GEN_INT (set_sign_bit_copies - 1)));	      return 2;	    }	}      /* See if we can generate this by setting the bottom (or the top)	 16 bits, and then shifting these into the other half of the	 word.  We only look for the simplest cases, to do more would cost	 too much.  Be careful, however, not to generate this when the	 alternative would take fewer insns.  */      if (val & 0xffff0000)	{	  temp1 = remainder & 0xffff0000;	  temp2 = remainder & 0x0000ffff;	  /* Overlaps outside this range are best done using other methods. */	  for (i = 9; i < 24; i++)	    {	      if ((((temp2 | (temp2 << i)) & 0xffffffff) == remainder)		  && ! const_ok_for_arm (temp2))		{		  insns		    = arm_split_constant (code, mode, temp2,					  (new_src					   = subtargets ? gen_reg_rtx (mode)					   : target),					  source, subtargets);		  source = new_src;		  emit_insn (gen_rtx (SET, VOIDmode, target,				      gen_rtx (IOR, mode,					       gen_rtx (ASHIFT, mode, source,							GEN_INT (i)),					       source)));		  return insns + 1;		}	    }	  /* Don't duplicate cases already considered. */	  for (i = 17; i < 24; i++)	    {	      if (((temp1 | (temp1 >> i)) == remainder)		  && ! const_ok_for_arm (temp1))		{		  insns		    = arm_split_constant (code, mode, temp1,					  (new_src					   = subtargets ? gen_reg_rtx (mode)					   : target),					  source, subtargets);		  source = new_src;		  emit_insn (gen_rtx (SET, VOIDmode, target,				      gen_rtx (IOR, mode,					       gen_rtx (LSHIFTRT, mode, source,							GEN_INT (i)),					       source)));		  return insns + 1;		}	    }	}      break;    case IOR:    case XOR:      /* If we have IOR or XOR, and the inverse of the constant can be loaded	 in a single instruction, and we can find a temporary to put it in,	 then this can be done in two instructions instead of 3-4.  */      if (subtargets	  || (reload_completed && ! reg_mentioned_p (target, source)))	{	  if (const_ok_for_arm (ARM_SIGN_EXTEND (~ val)))	    {	      rtx sub = subtargets ? gen_reg_rtx (mode) : target;	      emit_insn (gen_rtx (SET, VOIDmode, sub,				  GEN_INT (ARM_SIGN_EXTEND (~ val))));	      emit_insn (gen_rtx (SET, VOIDmode, target, 				  gen_rtx (code, mode, source, sub)));	      return 2;	    }	}      if (code == XOR)	break;      if (set_sign_bit_copies > 8	  && (val & (-1 << (32 - set_sign_bit_copies))) == val)	{	  rtx sub = subtargets ? gen_reg_rtx (mode) : target;	  rtx shift = GEN_INT (set_sign_bit_copies);	  emit_insn (gen_rtx (SET, VOIDmode, sub,			      gen_rtx (NOT, mode, 				       gen_rtx (ASHIFT, mode, source, 						shift))));	  emit_insn (gen_rtx (SET, VOIDmode, target,			      gen_rtx (NOT, mode,				       gen_rtx (LSHIFTRT, mode, sub,						shift))));	  return 2;	}      if (set_zero_bit_copies > 8	  && (remainder & ((1 << set_zero_bit_copies) - 1)) == remainder)	{	  rtx sub = subtargets ? gen_reg_rtx (mode) : target;	  rtx shift = GEN_INT (set_zero_bit_copies);	  	  emit_insn (gen_rtx (SET, VOIDmode, sub,			      gen_rtx (NOT, mode,				       gen_rtx (LSHIFTRT, mode, source,						shift))));	  emit_insn (gen_rtx (SET, VOIDmode, target,			      gen_rtx (NOT, mode,				       gen_rtx (ASHIFT, mode, sub,						shift))));	  return 2;	}      if (const_ok_for_arm (temp1 = ARM_SIGN_EXTEND (~ val)))	{	  rtx sub = subtargets ? gen_reg_rtx (mode) : target;	  emit_insn (gen_rtx (SET, VOIDmode, sub,			      gen_rtx (NOT, mode, source)));	  source = sub;	  if (subtargets)	    sub = gen_reg_rtx (mode);	  emit_insn (gen_rtx (SET, VOIDmode, sub,			      gen_rtx (AND, mode, source, GEN_INT (temp1))));	  emit_insn (gen_rtx (SET, VOIDmode, target,			      gen_rtx (NOT, mode, sub)));	  return 3;	}      break;    case AND:      /* See if two shifts will do 2 or more insn's worth of work.  */      if (clear_sign_bit_copies >= 16 && clear_sign_bit_copies < 24)	{	  HOST_WIDE_INT shift_mask = ((0xffffffff 				       << (32 - clear_sign_bit_copies))

⌨️ 快捷键说明

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