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

📄 c4x.c

📁 gcc编译工具没有什么特别
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Subroutines for assembler code output on the TMS320C[34]x   Copyright (C) 1994-98, 1999 Free Software Foundation, Inc.   Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz)              and Herman Ten Brugge (Haj.Ten.Brugge@net.HCC.nl).   This file is part of GNU CC.   GNU CC 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.   GNU CC 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 GNU CC; see the file COPYING.  If not, write to   the Free Software Foundation, 59 Temple Place - Suite 330,   Boston, MA 02111-1307, USA.  *//* Some output-actions in c4x.md need these.  */#include "config.h"#include "system.h"#include "toplev.h"#include "rtl.h"#include "regs.h"#include "hard-reg-set.h"#include "basic-block.h"#include "real.h"#include "insn-config.h"#include "insn-attr.h"#include "insn-codes.h"#include "conditions.h"#include "insn-flags.h"#include "output.h"#include "tree.h"#include "expr.h"#include "flags.h"#include "loop.h"#include "recog.h"#include "c-tree.h"static int c4x_leaf_function;static char *float_reg_names[] = FLOAT_REGISTER_NAMES;/* Array of the smallest class containing reg number REGNO, indexed by   REGNO.  Used by REGNO_REG_CLASS in c4x.h.  We assume that all these   registers are available and set the class to NO_REGS for registers    that the target switches say are unavailable.  */enum reg_class c4x_regclass_map[FIRST_PSEUDO_REGISTER] ={                                /* Reg          Modes           Saved  */  R0R1_REGS,			/* R0           QI, QF, HF      No  */  R0R1_REGS,			/* R1           QI, QF, HF      No  */  R2R3_REGS,			/* R2           QI, QF, HF      No  */  R2R3_REGS,			/* R3           QI, QF, HF      No  */  EXT_LOW_REGS,			/* R4           QI, QF, HF      QI  */  EXT_LOW_REGS,			/* R5           QI, QF, HF      QI  */  EXT_LOW_REGS,			/* R6           QI, QF, HF      QF  */  EXT_LOW_REGS,			/* R7           QI, QF, HF      QF  */  ADDR_REGS,			/* AR0          QI              No  */  ADDR_REGS,			/* AR1          QI              No  */  ADDR_REGS,			/* AR2          QI              No  */  ADDR_REGS,			/* AR3          QI              QI  */  ADDR_REGS,			/* AR4          QI              QI  */  ADDR_REGS,			/* AR5          QI              QI  */  ADDR_REGS,			/* AR6          QI              QI  */  ADDR_REGS,			/* AR7          QI              QI  */  DP_REG,			/* DP           QI              No  */  INDEX_REGS,			/* IR0          QI              No  */  INDEX_REGS,			/* IR1          QI              No  */  BK_REG,			/* BK           QI              QI  */  SP_REG,			/* SP           QI              No  */  ST_REG,			/* ST           CC              No  */  NO_REGS,			/* DIE/IE                       No  */  NO_REGS,			/* IIE/IF                       No  */  NO_REGS,			/* IIF/IOF                      No  */  INT_REGS,			/* RS           QI              No  */  INT_REGS,			/* RE           QI              No  */  RC_REG,			/* RC           QI              No  */  EXT_REGS,			/* R8           QI, QF, HF      QI  */  EXT_REGS,			/* R9           QI, QF, HF      No  */  EXT_REGS,			/* R10          QI, QF, HF      No  */  EXT_REGS,			/* R11          QI, QF, HF      No  */};enum machine_mode c4x_caller_save_map[FIRST_PSEUDO_REGISTER] ={                                /* Reg          Modes           Saved  */  HFmode,			/* R0           QI, QF, HF      No  */  HFmode,			/* R1           QI, QF, HF      No  */  HFmode,			/* R2           QI, QF, HF      No  */  HFmode,			/* R3           QI, QF, HF      No  */  QFmode,			/* R4           QI, QF, HF      QI  */  QFmode,			/* R5           QI, QF, HF      QI  */  QImode,			/* R6           QI, QF, HF      QF  */  QImode,			/* R7           QI, QF, HF      QF  */  QImode,			/* AR0          QI              No  */  QImode,			/* AR1          QI              No  */  QImode,			/* AR2          QI              No  */  QImode,			/* AR3          QI              QI  */  QImode,			/* AR4          QI              QI  */  QImode,			/* AR5          QI              QI  */  QImode,			/* AR6          QI              QI  */  QImode,			/* AR7          QI              QI  */  VOIDmode,			/* DP           QI              No  */  QImode,			/* IR0          QI              No  */  QImode,			/* IR1          QI              No  */  QImode,			/* BK           QI              QI  */  VOIDmode,			/* SP           QI              No  */  VOIDmode,			/* ST           CC              No  */  VOIDmode,			/* DIE/IE                       No  */  VOIDmode,			/* IIE/IF                       No  */  VOIDmode,			/* IIF/IOF                      No  */  QImode,			/* RS           QI              No  */  QImode,			/* RE           QI              No  */  VOIDmode,			/* RC           QI              No  */  QFmode,			/* R8           QI, QF, HF      QI  */  HFmode,			/* R9           QI, QF, HF      No  */  HFmode,			/* R10          QI, QF, HF      No  */  HFmode,			/* R11          QI, QF, HF      No  */};/* Test and compare insns in c4x.md store the information needed to   generate branch and scc insns here.  */struct rtx_def *c4x_compare_op0 = NULL_RTX;struct rtx_def *c4x_compare_op1 = NULL_RTX;char *c4x_rpts_cycles_string;int c4x_rpts_cycles = 0;	/* Max. cycles for RPTS */char *c4x_cpu_version_string;int c4x_cpu_version = 40;	/* CPU version C30/31/32/40/44 *//* Pragma definitions.  */tree code_tree = NULL_TREE;tree data_tree = NULL_TREE;tree pure_tree = NULL_TREE;tree noreturn_tree = NULL_TREE;tree interrupt_tree = NULL_TREE;/* Override command line options.   Called once after all options have been parsed.   Mostly we process the processor   type and sometimes adjust other TARGET_ options.  */voidc4x_override_options (){  if (c4x_rpts_cycles_string)    c4x_rpts_cycles = atoi (c4x_rpts_cycles_string);  else    c4x_rpts_cycles = 0;  if (TARGET_C30)    c4x_cpu_version = 30;  else if (TARGET_C31)    c4x_cpu_version = 31;  else if (TARGET_C32)    c4x_cpu_version = 32;  else if (TARGET_C40)    c4x_cpu_version = 40;  else if (TARGET_C44)    c4x_cpu_version = 44;  else    c4x_cpu_version = 40;	         /* -mcpu=xx overrides -m40 etc.  */  if (c4x_cpu_version_string)    c4x_cpu_version = atoi (c4x_cpu_version_string);  target_flags &= ~(C30_FLAG | C31_FLAG | C32_FLAG | C40_FLAG | C44_FLAG);  switch (c4x_cpu_version)    {    case 30: target_flags |= C30_FLAG; break;    case 31: target_flags |= C31_FLAG; break;    case 32: target_flags |= C32_FLAG; break;    case 40: target_flags |= C40_FLAG; break;    case 44: target_flags |= C44_FLAG; break;    default:      warning ("Unknown CPU version %d, using 40.\n", c4x_cpu_version);      c4x_cpu_version = 40;      target_flags |= C40_FLAG;    }  if (TARGET_C30 || TARGET_C31 || TARGET_C32)    target_flags |= C3X_FLAG;  else    target_flags &= ~C3X_FLAG;  /* Convert foo / 8.0 into foo * 0.125, etc.  */  flag_fast_math = 1;  /* We should phase out the following at some stage.     This provides compatibility with the old -mno-aliases option.  */  if (! TARGET_ALIASES && ! flag_argument_noalias)    flag_argument_noalias = 1;}/* This is called before c4x_override_options.  */voidc4x_optimization_options (level, size)     int level;     int size ATTRIBUTE_UNUSED;{  /* Scheduling before register allocation can screw up global     register allocation, especially for functions that use MPY||ADD     instructions.  The benefit we gain we get by scheduling before     register allocation is probably marginal anyhow.  */  flag_schedule_insns = 0;  /* When optimizing, enable use of RPTB instruction.  */  if (level >= 1)    flag_branch_on_count_reg = 1;}/* Write an ASCII string.  */#define C4X_ASCII_LIMIT 40voidc4x_output_ascii (stream, ptr, len)     FILE *stream;     unsigned char *ptr;     int len;{  char sbuf[C4X_ASCII_LIMIT + 1];  int s, first, onlys;  if (len)    {      fprintf (stream, "\t.byte\t");      first = 1;    }  for (s = 0; len > 0; --len, ++ptr)    {      onlys = 0;      /* Escape " and \ with a \".  */      if (*ptr == '\"' || *ptr == '\\')	sbuf[s++] = '\\';      /* If printable - add to buff.  */      if (*ptr >= 0x20 && *ptr < 0x7f)	{	  sbuf[s++] = *ptr;	  if (s < C4X_ASCII_LIMIT - 1)	    continue;	  onlys = 1;	}      if (s)	{	  if (first)	    first = 0;	  else	    fputc (',', stream);	  sbuf[s] = 0;	  fprintf (stream, "\"%s\"", sbuf);	  s = 0;	}      if (onlys)	continue;      if (first)	first = 0;      else	fputc (',', stream);      fprintf (stream, "%d", *ptr);    }  if (s)    {      if (! first)	fputc (',', stream);      sbuf[s] = 0;      fprintf (stream, "\"%s\"", sbuf);      s = 0;    }  fputc ('\n', stream);}intc4x_hard_regno_mode_ok (regno, mode)     int regno;     enum machine_mode mode;{  switch (mode)    {#if Pmode != QImode    case Pmode:			/* Pointer (24/32 bits) */#endif    case QImode:		/* Integer (32 bits) */      return IS_INT_REG (regno);    case QFmode:		/* Float, Double (32 bits) */    case HFmode:		/* Long Double (40 bits) */      return IS_EXT_REG (regno);    case CCmode:		/* Condition Codes */    case CC_NOOVmode:		/* Condition Codes */      return IS_ST_REG (regno);    case HImode:		/* Long Long (64 bits) */      /* We need two registers to store long longs.  Note that 	 it is much easier to constrain the first register	 to start on an even boundary.  */      return IS_INT_REG (regno)	&& IS_INT_REG (regno + 1)	&& (regno & 1) == 0;    default:      return 0;			/* We don't support these modes */    }  return 0;}/* The TI C3x C compiler register argument runtime model uses 6 registers,   AR2, R2, R3, RC, RS, RE.   The first two floating point arguments (float, double, long double)   that are found scanning from left to right are assigned to R2 and R3.   The remaining integer (char, short, int, long) or pointer arguments   are assigned to the remaining registers in the order AR2, R2, R3,   RC, RS, RE when scanning left to right, except for the last named   argument prior to an ellipsis denoting variable number of   arguments.  We don't have to worry about the latter condition since   function.c treats the last named argument as anonymous (unnamed).   All arguments that cannot be passed in registers are pushed onto   the stack in reverse order (right to left).  GCC handles that for us.   c4x_init_cumulative_args() is called at the start, so we can parse   the args to see how many floating point arguments and how many   integer (or pointer) arguments there are.  c4x_function_arg() is   then called (sometimes repeatedly) for each argument (parsed left   to right) to obtain the register to pass the argument in, or zero   if the argument is to be passed on the stack.  Once the compiler is   happy, c4x_function_arg_advance() is called.   Don't use R0 to pass arguments in, we use 0 to indicate a stack   argument.  */static int c4x_int_reglist[3][6] ={  {AR2_REGNO, R2_REGNO, R3_REGNO, RC_REGNO, RS_REGNO, RE_REGNO},  {AR2_REGNO, R3_REGNO, RC_REGNO, RS_REGNO, RE_REGNO, 0},  {AR2_REGNO, RC_REGNO, RS_REGNO, RE_REGNO, 0, 0}};static int c4x_fp_reglist[2] = {R2_REGNO, R3_REGNO};/* Initialize a variable CUM of type CUMULATIVE_ARGS for a call to a   function whose data type is FNTYPE.   For a library call, FNTYPE is  0.  */voidc4x_init_cumulative_args (cum, fntype, libname)     CUMULATIVE_ARGS *cum;	/* argument info to initialize */     tree fntype;		/* tree ptr for function decl */     rtx libname;		/* SYMBOL_REF of library name or 0 */{  tree param, next_param;  cum->floats = cum->ints = 0;  cum->init = 0;  cum->var = 0;  cum->args = 0;  if (TARGET_DEBUG)    {      fprintf (stderr, "\nc4x_init_cumulative_args (");      if (fntype)	{	  tree ret_type = TREE_TYPE (fntype);	  fprintf (stderr, "fntype code = %s, ret code = %s",		   tree_code_name[(int) TREE_CODE (fntype)],		   tree_code_name[(int) TREE_CODE (ret_type)]);	}      else	fprintf (stderr, "no fntype");      if (libname)	fprintf (stderr, ", libname = %s", XSTR (libname, 0));    }  cum->prototype = (fntype && TYPE_ARG_TYPES (fntype));  for (param = fntype ? TYPE_ARG_TYPES (fntype) : 0;       param; param = next_param)    {      tree type;      next_param = TREE_CHAIN (param);      type = TREE_VALUE (param);      if (type && type != void_type_node)	{	  enum machine_mode mode;	  /* If the last arg doesn't have void type then we have	     variable arguments.  */	  if (! next_param)	    cum->var = 1;	  if ((mode = TYPE_MODE (type)))	    {	      if (! MUST_PASS_IN_STACK (mode, type))		{		  /* Look for float, double, or long double argument.  */		  if (mode == QFmode || mode == HFmode)		    cum->floats++;		  /* Look for integer, enumeral, boolean, char, or pointer		     argument.  */		  else if (mode == QImode || mode == Pmode)		    cum->ints++;		}	    }	  cum->args++;	}    }  if (TARGET_DEBUG)    fprintf (stderr, "%s%s, args = %d)\n",	     cum->prototype ? ", prototype" : "",	     cum->var ? ", variable args" : "",	     cum->args);}/* Update the data in CUM to advance over an argument   of mode MODE and data type TYPE.   (TYPE is null for libcalls where that information may not be available.)  */voidc4x_function_arg_advance (cum, mode, type, named)     CUMULATIVE_ARGS *cum;	/* current arg information */     enum machine_mode mode;	/* current arg mode */     tree type;			/* type of the argument or 0 if lib support */     int named;			/* whether or not the argument was named */{  if (TARGET_DEBUG)    fprintf (stderr, "c4x_function_adv(mode=%s, named=%d)\n\n",	     GET_MODE_NAME (mode), named);  if (! TARGET_MEMPARM       && named      && type      && ! MUST_PASS_IN_STACK (mode, type))    {      /* Look for float, double, or long double argument.  */      if (mode == QFmode || mode == HFmode)	cum->floats++;      /* Look for integer, enumeral, boolean, char, or pointer argument.  */      else if (mode == QImode || mode == Pmode)	cum->ints++;    }  else if (! TARGET_MEMPARM && ! type)    {      /* Handle libcall arguments.  */      if (mode == QFmode || mode == HFmode)	cum->floats++;      else if (mode == QImode || mode == Pmode)	cum->ints++;    }  return;}/* Define where to put the arguments to a function.  Value is zero to   push the argument on the stack, or a hard register in which to   store the argument.   MODE is the argument's machine mode.   TYPE is the data type of the argument (as a tree).   This is null for libcalls where that information may   not be available.   CUM is a variable of type CUMULATIVE_ARGS which gives info about   the preceding args and about the function being called.   NAMED is nonzero if this argument is a named parameter   (otherwise it is an extra parameter matching an ellipsis).  */struct rtx_def *c4x_function_arg (cum, mode, type, named)     CUMULATIVE_ARGS *cum;	/* current arg information */     enum machine_mode mode;	/* current arg mode */     tree type;			/* type of the argument or 0 if lib support */     int named;			/* != 0 for normal args, == 0 for ... args */{  int reg = 0;			/* default to passing argument on stack */  if (! cum->init)    {      /* We can handle at most 2 floats in R2, R3 */      cum->maxfloats = (cum->floats > 2) ? 2 : cum->floats;      /* We can handle at most 6 integers minus number of floats passed 	 in registers.  */      cum->maxints = (cum->ints > 6 - cum->maxfloats) ? 	6 - cum->maxfloats : cum->ints;      /* If there is no prototype, assume all the arguments are integers.  */      if (! cum->prototype)	cum->maxints = 6;

⌨️ 快捷键说明

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