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

📄 mcore.c

📁 Mac OS X 10.4.9 for x86 Source Code gcc 实现源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Output routines for Motorola MCore processor   Copyright (C) 1993, 1999, 2000, 2001, 2002, 2003, 2004   Free Software Foundation, Inc.   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 "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           (int, int);static int        calc_live_regs                (int *);static int        const_ok_for_mcore            (int);static int        try_constant_tricks           (long, int *, int *);static const char *     output_inline_const     (enum machine_mode, rtx *);static void       layout_mcore_frame            (struct mcore_frame *);static void       mcore_setup_incoming_varargs	(CUMULATIVE_ARGS *, enum machine_mode, tree, int *, int);static cond_type  is_cond_candidate             (rtx);static rtx        emit_new_cond_insn            (rtx, int);static rtx        conditionalize_block          (rtx);static void       conditionalize_optimization   (void);static void       mcore_reorg                   (void);static rtx        handle_structs_in_regs        (enum machine_mode, tree, int);static void       mcore_mark_dllexport          (tree);static void       mcore_mark_dllimport          (tree);static int        mcore_dllexport_p             (tree);static int        mcore_dllimport_p             (tree);const struct attribute_spec mcore_attribute_table[];static tree       mcore_handle_naked_attribute  (tree *, tree, tree, int, bool *);#ifdef OBJECT_FORMAT_ELFstatic void	  mcore_asm_named_section       (const char *,						 unsigned int, tree);#endifstatic void       mcore_unique_section	        (tree, int);static void mcore_encode_section_info		(tree, rtx, int);static const char *mcore_strip_name_encoding	(const char *);static int        mcore_const_costs            	(rtx, RTX_CODE);static int        mcore_and_cost               	(rtx);static int        mcore_ior_cost               	(rtx);static bool       mcore_rtx_costs		(rtx, int, int, int *);static void       mcore_external_libcall	(rtx);static bool       mcore_return_in_memory	(tree, tree);static int        mcore_arg_partial_bytes       (CUMULATIVE_ARGS *,						 enum machine_mode,						 tree, bool);/* Initialize the GCC target structure.  */#undef  TARGET_ASM_EXTERNAL_LIBCALL#define TARGET_ASM_EXTERNAL_LIBCALL	mcore_external_libcall#if 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_ASM_FUNCTION_RODATA_SECTION#define TARGET_ASM_FUNCTION_RODATA_SECTION default_no_function_rodata_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_encoding#undef  TARGET_RTX_COSTS#define TARGET_RTX_COSTS 		mcore_rtx_costs#undef  TARGET_ADDRESS_COST#define TARGET_ADDRESS_COST 		hook_int_rtx_0#undef  TARGET_MACHINE_DEPENDENT_REORG#define TARGET_MACHINE_DEPENDENT_REORG	mcore_reorg#undef  TARGET_PROMOTE_FUNCTION_ARGS#define TARGET_PROMOTE_FUNCTION_ARGS	hook_bool_tree_true#undef  TARGET_PROMOTE_FUNCTION_RETURN#define TARGET_PROMOTE_FUNCTION_RETURN	hook_bool_tree_true#undef  TARGET_PROMOTE_PROTOTYPES#define TARGET_PROMOTE_PROTOTYPES	hook_bool_tree_true#undef  TARGET_RETURN_IN_MEMORY#define TARGET_RETURN_IN_MEMORY		mcore_return_in_memory#undef  TARGET_MUST_PASS_IN_STACK#define TARGET_MUST_PASS_IN_STACK	must_pass_in_stack_var_size#undef  TARGET_PASS_BY_REFERENCE#define TARGET_PASS_BY_REFERENCE  hook_pass_by_reference_must_pass_in_stack#undef  TARGET_ARG_PARTIAL_BYTES#define TARGET_ARG_PARTIAL_BYTES	mcore_arg_partial_bytes#undef  TARGET_SETUP_INCOMING_VARARGS#define TARGET_SETUP_INCOMING_VARARGS	mcore_setup_incoming_varargsstruct gcc_target targetm = TARGET_INITIALIZER;/* Adjust the stack and return the number of bytes taken to do it.  */static voidoutput_stack_adjust (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 (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 (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," HOST_WIDE_INT_PRINT_DEC ")",		     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, i.e. 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 (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, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));      break;    case 'M':      fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, - 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, HOST_WIDE_INT_PRINT_HEX, INTVAL (x));      break;    case 'X':      fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, 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 ?  */static intmcore_const_costs (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).  */static intmcore_and_cost (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().  */static intmcore_ior_cost (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;}static boolmcore_rtx_costs (rtx x, int code, int outer_code, int * total){  switch (code)    {    case CONST_INT:      *total = mcore_const_costs (x, outer_code);      return true;    case CONST:    case LABEL_REF:    case SYMBOL_REF:      *total = 5;      return true;    case CONST_DOUBLE:      *total = 10;      return true;    case AND:      *total = COSTS_N_INSNS (mcore_and_cost (x));      return true;

⌨️ 快捷键说明

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