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

📄 bfin.c

📁 Mac OS X 10.4.9 for x86 Source Code gcc 实现源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* The Blackfin code generation auxilary output file.   Copyright (C) 2005  Free Software Foundation, Inc.   Contributed by Analog Devices.   This file is part of GCC.   GCC is free software; you can redistribute it and/or modify it   under the terms of the GNU General Public License as published   by the Free Software Foundation; either version 2, or (at your   option) any later version.   GCC is distributed in the hope that it will be useful, but WITHOUT   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public   License for more details.   You should have received a copy of the GNU General Public License   along with GCC; see the file COPYING.  If not, write to   the Free Software Foundation, 59 Temple Place - Suite 330,   Boston, MA 02111-1307, USA.  */#include "config.h"#include "system.h"#include "coretypes.h"#include "tm.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 "input.h"#include "target.h"#include "target-def.h"#include "expr.h"#include "toplev.h"#include "recog.h"#include "ggc.h"#include "integrate.h"#include "bfin-protos.h"#include "tm-preds.h"#include "gt-bfin.h"/* Test and compare insns in bfin.md store the information needed to   generate branch and scc insns here.  */rtx bfin_compare_op0, bfin_compare_op1;/* RTX for condition code flag register and RETS register */extern GTY(()) rtx bfin_cc_rtx;extern GTY(()) rtx bfin_rets_rtx;rtx bfin_cc_rtx, bfin_rets_rtx;int max_arg_registers = 0;/* Arrays used when emitting register names.  */const char *short_reg_names[]  =  SHORT_REGISTER_NAMES;const char *high_reg_names[]   =  HIGH_REGISTER_NAMES;const char *dregs_pair_names[] =  DREGS_PAIR_NAMES;const char *byte_reg_names[]   =  BYTE_REGISTER_NAMES;static int arg_regs[] = FUNCTION_ARG_REGISTERS;const char *bfin_library_id_string;static voidbfin_globalize_label (FILE *stream, const char *name){  fputs (".global ", stream);  assemble_name (stream, name);  fputc (';',stream);  fputc ('\n',stream);}static void output_file_start (void) {  FILE *file = asm_out_file;  int i;  fprintf (file, ".file \"%s\";\n", input_filename);    for (i = 0; arg_regs[i] >= 0; i++)    ;  max_arg_registers = i;	/* how many arg reg used  */}/* Called early in the compilation to conditionally modify   fixed_regs/call_used_regs.  */void conditional_register_usage (void){  /* initialize condition code flag register rtx */  bfin_cc_rtx = gen_rtx_REG (BImode, REG_CC);  bfin_rets_rtx = gen_rtx_REG (Pmode, REG_RETS);}/* Examine machine-dependent attributes of function type FUNTYPE and return its   type.  See the definition of E_FUNKIND.  */static e_funkind funkind (tree funtype){  tree attrs = TYPE_ATTRIBUTES (funtype);  if (lookup_attribute ("interrupt_handler", attrs))    return INTERRUPT_HANDLER;  else if (lookup_attribute ("exception_handler", attrs))    return EXCPT_HANDLER;  else if (lookup_attribute ("nmi_handler", attrs))    return NMI_HANDLER;  else    return SUBROUTINE;}/* Stack frame layout. *//* Compute the number of DREGS to save with a push_multiple operation.   This could include registers that aren't modified in the function,   since push_multiple only takes a range of registers.  */static intn_dregs_to_save (void){  unsigned i;  for (i = REG_R0; i <= REG_R7; i++)    {      if (regs_ever_live[i] && ! call_used_regs[i])	return REG_R7 - i + 1;      if (current_function_calls_eh_return)	{	  unsigned j;	  for (j = 0; ; j++)	    {	      unsigned test = EH_RETURN_DATA_REGNO (j);	      if (test == INVALID_REGNUM)		break;	      if (test == i)		return REG_R7 - i + 1;	    }	}    }  return 0;}/* Like n_dregs_to_save, but compute number of PREGS to save.  */static intn_pregs_to_save (void){  unsigned i;  for (i = REG_P0; i <= REG_P5; i++)    if ((regs_ever_live[i] && ! call_used_regs[i])	|| (i == PIC_OFFSET_TABLE_REGNUM	    && (current_function_uses_pic_offset_table		|| (TARGET_ID_SHARED_LIBRARY && ! current_function_is_leaf))))      return REG_P5 - i + 1;  return 0;}/* Determine if we are going to save the frame pointer in the prologue.  */static boolmust_save_fp_p (void){  return (frame_pointer_needed || regs_ever_live[REG_FP]);}static boolstack_frame_needed_p (void){  /* EH return puts a new return address into the frame using an     address relative to the frame pointer.  */  if (current_function_calls_eh_return)    return true;  return frame_pointer_needed;}/* Emit code to save registers in the prologue.  SAVEALL is nonzero if we   must save all registers; this is used for interrupt handlers.   SPREG contains (reg:SI REG_SP).  */static voidexpand_prologue_reg_save (rtx spreg, int saveall){  int ndregs = saveall ? 8 : n_dregs_to_save ();  int npregs = saveall ? 6 : n_pregs_to_save ();  int dregno = REG_R7 + 1 - ndregs;  int pregno = REG_P5 + 1 - npregs;  int total = ndregs + npregs;  int i;  rtx pat, insn, val;  if (total == 0)    return;  val = GEN_INT (-total * 4);  pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total + 2));  XVECEXP (pat, 0, 0) = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, val),					UNSPEC_PUSH_MULTIPLE);  XVECEXP (pat, 0, total + 1) = gen_rtx_SET (VOIDmode, spreg,					     gen_rtx_PLUS (Pmode, spreg,							   val));  RTX_FRAME_RELATED_P (XVECEXP (pat, 0, total + 1)) = 1;  for (i = 0; i < total; i++)    {      rtx memref = gen_rtx_MEM (word_mode,				gen_rtx_PLUS (Pmode, spreg,					      GEN_INT (- i * 4 - 4)));      rtx subpat;      if (ndregs > 0)	{	  subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,							       dregno++));	  ndregs--;	}      else	{	  subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,							       pregno++));	  npregs++;	}      XVECEXP (pat, 0, i + 1) = subpat;      RTX_FRAME_RELATED_P (subpat) = 1;    }  insn = emit_insn (pat);  RTX_FRAME_RELATED_P (insn) = 1;}/* Emit code to restore registers in the epilogue.  SAVEALL is nonzero if we   must save all registers; this is used for interrupt handlers.   SPREG contains (reg:SI REG_SP).  */static voidexpand_epilogue_reg_restore (rtx spreg, int saveall){  int ndregs = saveall ? 8 : n_dregs_to_save ();  int npregs = saveall ? 6 : n_pregs_to_save ();  int total = ndregs + npregs;  int i, regno;  rtx pat, insn;  if (total == 0)    return;  pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total + 1));  XVECEXP (pat, 0, 0) = gen_rtx_SET (VOIDmode, spreg,				     gen_rtx_PLUS (Pmode, spreg,						   GEN_INT (total * 4)));  if (npregs > 0)    regno = REG_P5 + 1;  else    regno = REG_R7 + 1;  for (i = 0; i < total; i++)    {      rtx addr = (i > 0		  ? gen_rtx_PLUS (Pmode, spreg, GEN_INT (i * 4))		  : spreg);      rtx memref = gen_rtx_MEM (word_mode, addr);      regno--;      XVECEXP (pat, 0, i + 1)	= gen_rtx_SET (VOIDmode, gen_rtx_REG (word_mode, regno), memref);      if (npregs > 0)	{	  if (--npregs == 0)	    regno = REG_R7 + 1;	}    }  insn = emit_insn (pat);  RTX_FRAME_RELATED_P (insn) = 1;}/* Perform any needed actions needed for a function that is receiving a   variable number of arguments.   CUM is as above.   MODE and TYPE are the mode and type of the current parameter.   PRETEND_SIZE is a variable that should be set to the amount of stack   that must be pushed by the prolog to pretend that our caller pushed   it.   Normally, this macro will push all remaining incoming registers on the   stack and set PRETEND_SIZE to the length of the registers pushed.     Blackfin specific :   - VDSP C compiler manual (our ABI) says that a variable args function     should save the R0, R1 and R2 registers in the stack.   - The caller will always leave space on the stack for the     arguments that are passed in registers, so we dont have     to leave any extra space.   - now, the vastart pointer can access all arguments from the stack.  */static voidsetup_incoming_varargs (CUMULATIVE_ARGS *cum,			enum machine_mode mode ATTRIBUTE_UNUSED,			tree type ATTRIBUTE_UNUSED, int *pretend_size,			int no_rtl){  rtx mem;  int i;  if (no_rtl)    return;  /* The move for named arguments will be generated automatically by the     compiler.  We need to generate the move rtx for the unnamed arguments     if they are in the first 3 words.  We assume atleast 1 named argument     exists, so we never generate [ARGP] = R0 here.  */  for (i = cum->words + 1; i < max_arg_registers; i++)    {      mem = gen_rtx_MEM (Pmode,			 plus_constant (arg_pointer_rtx, (i * UNITS_PER_WORD)));      emit_move_insn (mem, gen_rtx_REG (Pmode, i));    }  *pretend_size = 0;}/* Value should be nonzero if functions must have frame pointers.   Zero means the frame pointer need not be set up (and parms may   be accessed via the stack pointer) in functions that seem suitable.  */intbfin_frame_pointer_required (void) {  e_funkind fkind = funkind (TREE_TYPE (current_function_decl));  if (fkind != SUBROUTINE)    return 1;  /* We turn on on -fomit-frame-pointer if -momit-leaf-frame-pointer is used,     so we have to override it for non-leaf functions.  */  if (TARGET_OMIT_LEAF_FRAME_POINTER && ! current_function_is_leaf)    return 1;  return 0;}/* Return the number of registers pushed during the prologue.  */static intn_regs_saved_by_prologue (void){  e_funkind fkind = funkind (TREE_TYPE (current_function_decl));  int n = n_dregs_to_save () + n_pregs_to_save ();  if (stack_frame_needed_p ())    /* We use a LINK instruction in this case.  */    n += 2;  else    {      if (must_save_fp_p ())	n++;      if (! current_function_is_leaf)	n++;    }  if (fkind != SUBROUTINE)    {      tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));      tree all = lookup_attribute ("saveall", attrs);      int i;      /* Increment once for ASTAT.  */      n++;      /* RETE/X/N.  */      if (lookup_attribute ("nesting", attrs))	n++;      for (i = REG_P7 + 1; i < REG_CC; i++)	if (all 	    || regs_ever_live[i]	    || (!leaf_function_p () && call_used_regs[i]))	  n += i == REG_A0 || i == REG_A1 ? 2 : 1;    }  return n;}/* Return the offset between two registers, one to be eliminated, and the other   its replacement, at the start of a routine.  */HOST_WIDE_INTbfin_initial_elimination_offset (int from, int to){  HOST_WIDE_INT offset = 0;  if (from == ARG_POINTER_REGNUM)    offset = n_regs_saved_by_prologue () * 4;  if (to == STACK_POINTER_REGNUM)    {      if (current_function_outgoing_args_size >= FIXED_STACK_AREA)	offset += current_function_outgoing_args_size;      else if (current_function_outgoing_args_size)	offset += FIXED_STACK_AREA;      offset += get_frame_size ();    }  return offset;}/* Emit code to load a constant CONSTANT into register REG; setting   RTX_FRAME_RELATED_P on all insns we generate.  Make sure that the insns   we generate need not be split.  */static voidframe_related_constant_load (rtx reg, HOST_WIDE_INT constant){  rtx insn;  rtx cst = GEN_INT (constant);  if (constant >= -32768 && constant < 65536)    insn = emit_move_insn (reg, cst);  else    {      /* We don't call split_load_immediate here, since dwarf2out.c can get	 confused about some of the more clever sequences it can generate.  */      insn = emit_insn (gen_movsi_high (reg, cst));      RTX_FRAME_RELATED_P (insn) = 1;      insn = emit_insn (gen_movsi_low (reg, reg, cst));    }  RTX_FRAME_RELATED_P (insn) = 1;}/* Generate efficient code to add a value to the frame pointer.  We   can use P1 as a scratch register.  Set RTX_FRAME_RELATED_P on the   generated insns if FRAME is nonzero.  */static voidadd_to_sp (rtx spreg, HOST_WIDE_INT value, int frame){  if (value == 0)    return;  /* Choose whether to use a sequence using a temporary register, or     a sequence with multiple adds.  We can add a signed 7 bit value     in one instruction.  */  if (value > 120 || value < -120)    {      rtx tmpreg = gen_rtx_REG (SImode, REG_P1);      rtx insn;      if (frame)	frame_related_constant_load (tmpreg, value);      else	{	  insn = emit_move_insn (tmpreg, GEN_INT (value));	  if (frame)	    RTX_FRAME_RELATED_P (insn) = 1;	}      insn = emit_insn (gen_addsi3 (spreg, spreg, tmpreg));      if (frame)	RTX_FRAME_RELATED_P (insn) = 1;    }  else    do      {	int size = value;	rtx insn;	if (size > 60)	  size = 60;	else if (size < -60)	  /* We could use -62, but that would leave the stack unaligned, so	     it's no good.  */	  size = -60;	insn = emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (size)));	if (frame)	  RTX_FRAME_RELATED_P (insn) = 1;	value -= size;

⌨️ 快捷键说明

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