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

📄 mcore.c

📁 linux下的gcc编译器
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Output routines for Motorola MCore processor   Copyright (C) 1993, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.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 "tree.h"#include "tm_p.h"#include "assert.h"#include "mcore.h"#include "regs.h"#include "hard-reg-set.h"#include "real.h"#include "insn-config.h"#include "conditions.h"#include "output.h"#include "insn-attr.h"#include "flags.h"#include "obstack.h"#include "expr.h"#include "reload.h"#include "recog.h"#include "function.h"#include "ggc.h"#include "toplev.h"#include "target.h"#include "target-def.h"/* Maximum size we are allowed to grow the stack in a single operation.   If we want more, we must do it in increments of at most this size.   If this value is 0, we don't check at all.  */const char * mcore_stack_increment_string = 0;int          mcore_stack_increment = STACK_UNITS_MAXSTEP;/* For dumping information about frame sizes.  */char * mcore_current_function_name = 0;long   mcore_current_compilation_timestamp = 0;/* Global variables for machine-dependent things.  *//* Saved operands from the last compare to use when we generate an scc  or bcc insn.  */rtx arch_compare_op0;rtx arch_compare_op1;/* Provides the class number of the smallest class containing   reg number.  */const int regno_reg_class[FIRST_PSEUDO_REGISTER] ={  GENERAL_REGS,	ONLYR1_REGS,  LRW_REGS,	    LRW_REGS,  LRW_REGS,	LRW_REGS,     LRW_REGS,	    LRW_REGS,  LRW_REGS,	LRW_REGS,     LRW_REGS,	    LRW_REGS,  LRW_REGS,	LRW_REGS,     LRW_REGS,	    GENERAL_REGS,  GENERAL_REGS, C_REGS,       NO_REGS,      NO_REGS,};/* Provide reg_class from a letter such as appears in the machine   description.  */const enum reg_class reg_class_from_letter[] ={  /* a */ LRW_REGS, /* b */ ONLYR1_REGS, /* c */ C_REGS,  /* d */ NO_REGS,  /* e */ NO_REGS, /* f */ NO_REGS, /* g */ NO_REGS, /* h */ NO_REGS,  /* i */ NO_REGS, /* j */ NO_REGS, /* k */ NO_REGS, /* l */ NO_REGS,  /* m */ NO_REGS, /* n */ NO_REGS, /* o */ NO_REGS, /* p */ NO_REGS,  /* q */ NO_REGS, /* r */ GENERAL_REGS, /* s */ NO_REGS, /* t */ NO_REGS,  /* u */ NO_REGS, /* v */ NO_REGS, /* w */ NO_REGS, /* x */ ALL_REGS,  /* y */ NO_REGS, /* z */ NO_REGS};struct mcore_frame{  int arg_size;			/* stdarg spills (bytes) */  int reg_size;			/* non-volatile reg saves (bytes) */  int reg_mask;			/* non-volatile reg saves */  int local_size;		/* locals */  int outbound_size;		/* arg overflow on calls out */  int pad_outbound;  int pad_local;  int pad_reg;  /* Describe the steps we'll use to grow it.  */#define	MAX_STACK_GROWS	4	/* gives us some spare space */  int growth[MAX_STACK_GROWS];  int arg_offset;  int reg_offset;  int reg_growth;  int local_growth;};typedef enum{  COND_NO,  COND_MOV_INSN,  COND_CLR_INSN,  COND_INC_INSN,  COND_DEC_INSN,  COND_BRANCH_INSN}cond_type;static void       output_stack_adjust          PARAMS ((int, int));static int        calc_live_regs               PARAMS ((int *));static int        const_ok_for_mcore           PARAMS ((int));static int        try_constant_tricks          PARAMS ((long, int *, int *));static const char *     output_inline_const          PARAMS ((enum machine_mode, rtx *));static void       block_move_sequence          PARAMS ((rtx, rtx, rtx, rtx, int, int, int));static void       layout_mcore_frame           PARAMS ((struct mcore_frame *));static cond_type  is_cond_candidate            PARAMS ((rtx));static rtx        emit_new_cond_insn           PARAMS ((rtx, int));static rtx        conditionalize_block         PARAMS ((rtx));static void       conditionalize_optimization  PARAMS ((rtx));static rtx        handle_structs_in_regs       PARAMS ((enum machine_mode, tree, int));static void       mcore_mark_dllexport         PARAMS ((tree));static void       mcore_mark_dllimport         PARAMS ((tree));static int        mcore_dllexport_p            PARAMS ((tree));static int        mcore_dllimport_p            PARAMS ((tree));const struct attribute_spec mcore_attribute_table[];static tree       mcore_handle_naked_attribute PARAMS ((tree *, tree, tree, int, bool *));#ifdef OBJECT_FORMAT_ELFstatic void	  mcore_asm_named_section      PARAMS ((const char *,							unsigned int));#endifstatic void       mcore_unique_section	       PARAMS ((tree, int));static void mcore_encode_section_info		PARAMS ((tree, int));static const char *mcore_strip_name_encoding	PARAMS ((const char *));/* Initialize the GCC target structure.  */#ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES#undef TARGET_MERGE_DECL_ATTRIBUTES#define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes#endif#ifdef OBJECT_FORMAT_ELF#undef TARGET_ASM_UNALIGNED_HI_OP#define TARGET_ASM_UNALIGNED_HI_OP "\t.short\t"#undef TARGET_ASM_UNALIGNED_SI_OP#define TARGET_ASM_UNALIGNED_SI_OP "\t.long\t"#endif#undef TARGET_ATTRIBUTE_TABLE#define TARGET_ATTRIBUTE_TABLE mcore_attribute_table#undef TARGET_ASM_UNIQUE_SECTION#define TARGET_ASM_UNIQUE_SECTION mcore_unique_section#undef TARGET_ENCODE_SECTION_INFO#define TARGET_ENCODE_SECTION_INFO mcore_encode_section_info#undef TARGET_STRIP_NAME_ENCODING#define TARGET_STRIP_NAME_ENCODING mcore_strip_name_encodingstruct gcc_target targetm = TARGET_INITIALIZER;/* Adjust the stack and return the number of bytes taken to do it.  */static voidoutput_stack_adjust (direction, size)     int direction;     int size;{  /* If extending stack a lot, we do it incrementally.  */  if (direction < 0 && size > mcore_stack_increment && mcore_stack_increment > 0)    {      rtx tmp = gen_rtx (REG, SImode, 1);      rtx memref;      emit_insn (gen_movsi (tmp, GEN_INT (mcore_stack_increment)));      do	{	  emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, tmp));	  memref = gen_rtx (MEM, SImode, stack_pointer_rtx);	  MEM_VOLATILE_P (memref) = 1;	  emit_insn (gen_movsi (memref, stack_pointer_rtx));	  size -= mcore_stack_increment;	}      while (size > mcore_stack_increment);      /* SIZE is now the residual for the last adjustment,	 which doesn't require a probe.  */    }  if (size)    {      rtx insn;      rtx val = GEN_INT (size);      if (size > 32)	{	  rtx nval = gen_rtx (REG, SImode, 1);	  emit_insn (gen_movsi (nval, val));	  val = nval;	}            if (direction > 0)	insn = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, val);      else	insn = gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, val);            emit_insn (insn);    }}/* Work out the registers which need to be saved,   both as a mask and a count.  */static intcalc_live_regs (count)     int * count;{  int reg;  int live_regs_mask = 0;    * count = 0;  for (reg = 0; reg < FIRST_PSEUDO_REGISTER; reg++)    {      if (regs_ever_live[reg] && !call_used_regs[reg])	{	  (*count)++;	  live_regs_mask |= (1 << reg);	}    }  return live_regs_mask;}/* Print the operand address in x to the stream.  */voidmcore_print_operand_address (stream, x)     FILE * stream;     rtx x;{  switch (GET_CODE (x))    {    case REG:      fprintf (stream, "(%s)", reg_names[REGNO (x)]);      break;          case PLUS:      {	rtx base = XEXP (x, 0);	rtx index = XEXP (x, 1);	if (GET_CODE (base) != REG)	  {	    /* Ensure that BASE is a register (one of them must be).  */	    rtx temp = base;	    base = index;	    index = temp;	  }	switch (GET_CODE (index))	  {	  case CONST_INT:	    fprintf (stream, "(%s,%d)", reg_names[REGNO(base)],		     INTVAL (index));	    break;	  default:	    debug_rtx (x);	    abort ();	  }      }      break;    default:      output_addr_const (stream, x);      break;    }}/* Print operand x (an rtx) in assembler syntax to file stream   according to modifier code.   'R'  print the next register or memory location along, ie the lsw in        a double word value   'O'  print a constant without the #   'M'  print a constant as its negative   'P'  print log2 of a power of two   'Q'  print log2 of an inverse of a power of two   'U'  print register for ldm/stm instruction   'X'  print byte number for xtrbN instruction.  */voidmcore_print_operand (stream, x, code)     FILE * stream;     rtx x;     int code;{  switch (code)    {    case 'N':      if (INTVAL(x) == -1)	fprintf (asm_out_file, "32");      else	fprintf (asm_out_file, "%d", exact_log2 (INTVAL (x) + 1));      break;    case 'P':      fprintf (asm_out_file, "%d", exact_log2 (INTVAL (x)));      break;    case 'Q':      fprintf (asm_out_file, "%d", exact_log2 (~INTVAL (x)));      break;    case 'O':      fprintf (asm_out_file, "%d", INTVAL (x));      break;    case 'M':      fprintf (asm_out_file, "%d", - INTVAL (x));      break;    case 'R':      /* Next location along in memory or register.  */      switch (GET_CODE (x))	{	case REG:	  fputs (reg_names[REGNO (x) + 1], (stream));	  break;	case MEM:	  mcore_print_operand_address	    (stream, XEXP (adjust_address (x, SImode, 4), 0));	  break;	default:	  abort ();	}      break;    case 'U':      fprintf (asm_out_file, "%s-%s", reg_names[REGNO (x)],	       reg_names[REGNO (x) + 3]);      break;    case 'x':      fprintf (asm_out_file, "0x%x", INTVAL (x));      break;    case 'X':      fprintf (asm_out_file, "%d", 3 - INTVAL (x) / 8);      break;    default:      switch (GET_CODE (x))	{	case REG:	  fputs (reg_names[REGNO (x)], (stream));	  break;	case MEM:	  output_address (XEXP (x, 0));	  break;	default:	  output_addr_const (stream, x);	  break;	}      break;    }}/* What does a constant cost ?  */intmcore_const_costs (exp, code)     rtx exp;     enum rtx_code code;{  int val = INTVAL (exp);  /* Easy constants.  */  if (   CONST_OK_FOR_I (val)	      || CONST_OK_FOR_M (val)	      || CONST_OK_FOR_N (val)	      || (code == PLUS && CONST_OK_FOR_L (val)))    return 1;					  else if (code == AND	   && (   CONST_OK_FOR_M (~val)	       || CONST_OK_FOR_N (~val)))    return 2;  else if (code == PLUS				   && (   CONST_OK_FOR_I (-val)		       || CONST_OK_FOR_M (-val)		       || CONST_OK_FOR_N (-val)))	    return 2;						  return 5;					}/* What does an and instruction cost - we do this b/c immediates may    have been relaxed.   We want to ensure that cse will cse relaxed immeds   out.  Otherwise we'll get bad code (multiple reloads of the same const).  */intmcore_and_cost (x)     rtx x;{  int val;  if (GET_CODE (XEXP (x, 1)) != CONST_INT)    return 2;  val = INTVAL (XEXP (x, 1));     /* Do it directly.  */  if (CONST_OK_FOR_K (val) || CONST_OK_FOR_M (~val))    return 2;  /* Takes one instruction to load.  */  else if (const_ok_for_mcore (val))    return 3;  /* Takes two instructions to load.  */  else if (TARGET_HARDLIT && mcore_const_ok_for_inline (val))    return 4;  /* Takes a lrw to load.  */  return 5;}/* What does an or cost - see and_cost().  */intmcore_ior_cost (x)     rtx x;{  int val;  if (GET_CODE (XEXP (x, 1)) != CONST_INT)    return 2;  val = INTVAL (XEXP (x, 1));  /* Do it directly with bclri.  */  if (CONST_OK_FOR_M (val))    return 2;  /* Takes one instruction to load.  */  else if (const_ok_for_mcore (val))    return 3;  /* Takes two instructions to load.  */  else if (TARGET_HARDLIT && mcore_const_ok_for_inline (val))    return 4;    /* Takes a lrw to load.  */  return 5;}/* Check to see if a comparison against a constant can be made more efficient   by incrementing/decrementing the constant to get one that is more efficient   to load.  */intmcore_modify_comparison (code)     enum rtx_code code;{  rtx op1   = arch_compare_op1;    if (GET_CODE (op1) == CONST_INT)    {      int val = INTVAL (op1);            switch (code)	{	case LE:	  if (CONST_OK_FOR_J (val + 1))	    {	      arch_compare_op1 = GEN_INT (val + 1);	      return 1;	    }	  break;	  	default:	  break;	}    }    return 0;}/* Prepare the operands for a comparison.  */rtxmcore_gen_compare_reg (code)     enum rtx_code code;{  rtx op0 = arch_compare_op0;  rtx op1 = arch_compare_op1;  rtx cc_reg = gen_rtx (REG, CCmode, CC_REG);  if (CONSTANT_P (op1) && GET_CODE (op1) != CONST_INT)    op1 = force_reg (SImode, op1);  /* cmpnei: 0-31 (K immediate)     cmplti: 1-32 (J immediate, 0 using btsti x,31).  */  switch (code)    {    case EQ:	/* Use inverted condition, cmpne.  */      code = NE;      /* drop through */          case NE:	/* Use normal condition, cmpne.  */      if (GET_CODE (op1) == CONST_INT && ! CONST_OK_FOR_K (INTVAL (op1)))	op1 = force_reg (SImode, op1);      break;    case LE:	/* Use inverted condition, reversed cmplt.  */      code = GT;      /* drop through */          case GT:	/* Use normal condition, reversed cmplt.  */

⌨️ 快捷键说明

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