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

📄 bfin.c

📁 linux下编程用 编译软件
💻 C
📖 第 1 页 / 共 5 页
字号:
/* The Blackfin code generation auxiliary 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, 51 Franklin Street, Fifth Floor,   Boston, MA 02110-1301, 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 "insn-codes.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 "cgraph.h"#include "langhooks.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;/* Nonzero if -mshared-library-id was given.  */static int bfin_lib_id_given;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;}/* Legitimize PIC addresses.  If the address is already position-independent,   we return ORIG.  Newly generated position-independent addresses go into a   reg.  This is REG if nonzero, otherwise we allocate register(s) as   necessary.  PICREG is the register holding the pointer to the PIC offset   table.  */rtxlegitimize_pic_address (rtx orig, rtx reg, rtx picreg){  rtx addr = orig;  rtx new = orig;  if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)    {      if (GET_CODE (addr) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (addr))	reg = new = orig;      else	{	  if (reg == 0)	    {	      gcc_assert (!no_new_pseudos);	      reg = gen_reg_rtx (Pmode);	    }	  if (flag_pic == 2)	    {	      emit_insn (gen_movsi_high_pic (reg, addr));	      emit_insn (gen_movsi_low_pic (reg, reg, addr));	      emit_insn (gen_addsi3 (reg, reg, picreg));	      new = gen_const_mem (Pmode, reg);	    }	  else	    {	      rtx tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr),					UNSPEC_MOVE_PIC);	      new = gen_const_mem (Pmode,				   gen_rtx_PLUS (Pmode, picreg, tmp));	    }	  emit_move_insn (reg, new);	}      if (picreg == pic_offset_table_rtx)	current_function_uses_pic_offset_table = 1;      return reg;    }  else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)    {      rtx base;      if (GET_CODE (addr) == CONST)	{	  addr = XEXP (addr, 0);	  gcc_assert (GET_CODE (addr) == PLUS);	}      if (XEXP (addr, 0) == picreg)	return orig;      if (reg == 0)	{	  gcc_assert (!no_new_pseudos);	  reg = gen_reg_rtx (Pmode);	}      base = legitimize_pic_address (XEXP (addr, 0), reg, picreg);      addr = legitimize_pic_address (XEXP (addr, 1),				     base == reg ? NULL_RTX : reg,				     picreg);      if (GET_CODE (addr) == CONST_INT)	{	  gcc_assert (! reload_in_progress && ! reload_completed);	  addr = force_reg (Pmode, addr);	}      if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))	{	  base = gen_rtx_PLUS (Pmode, base, XEXP (addr, 0));	  addr = XEXP (addr, 1);	}      return gen_rtx_PLUS (Pmode, base, addr);    }  return new;}/* 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.   If IS_INTHANDLER, then everything that is live must be saved, even   if normally call-clobbered.  */static intn_dregs_to_save (bool is_inthandler){  unsigned i;  for (i = REG_R0; i <= REG_R7; i++)    {      if (regs_ever_live[i] && (is_inthandler || ! 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 (bool is_inthandler){  unsigned i;  for (i = REG_P0; i <= REG_P5; i++)    if ((regs_ever_live[i] && (is_inthandler || ! 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).  IS_INTHANDLER is true if we're doing   this for an interrupt (or exception) handler.  */static voidexpand_prologue_reg_save (rtx spreg, int saveall, bool is_inthandler){  int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler);  int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler);  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).  IS_INTHANDLER is true if we're doing   this for an interrupt (or exception) handler.  */static voidexpand_epilogue_reg_restore (rtx spreg, bool saveall, bool is_inthandler){  int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler);  int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler);  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 at least 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 -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));  bool is_inthandler = fkind != SUBROUTINE;  tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));  bool all = (lookup_attribute ("saveall", attrs) != NULL_TREE	      || (is_inthandler && !current_function_is_leaf));  int ndregs = all ? 8 : n_dregs_to_save (is_inthandler);  int npregs = all ? 6 : n_pregs_to_save (is_inthandler);    int n = ndregs + npregs;  if (all || 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)    {      int i;      /* Increment once for ASTAT.  */      n++;      /* RETE/X/N.  */

⌨️ 快捷键说明

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