h8300.c

来自「gcc3.2.1源代码」· C语言 代码 · 共 2,420 行 · 第 1/5 页

C
2,420
字号
/* Subroutines for insn-output.c for Hitachi H8/300.   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,   2001, 2002 Free Software Foundation, Inc.   Contributed by Steve Chamberlain (sac@cygnus.com),   Jim Wilson (wilson@cygnus.com), and Doug Evans (dje@cygnus.com).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 "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 "recog.h"#include "expr.h"#include "function.h"#include "toplev.h"#include "c-pragma.h"#include "tm_p.h"#include "ggc.h"#include "target.h"#include "target-def.h"/* Forward declarations.  */static const char *byte_reg PARAMS ((rtx, int));static int h8300_interrupt_function_p PARAMS ((tree));static int h8300_monitor_function_p PARAMS ((tree));static int h8300_os_task_function_p PARAMS ((tree));static void dosize PARAMS ((FILE *, const char *, unsigned int));static int round_frame_size PARAMS ((int));static unsigned int compute_saved_regs PARAMS ((void));static void push PARAMS ((FILE *, int));static void pop PARAMS ((FILE *, int));static const char *cond_string PARAMS ((enum rtx_code));const struct attribute_spec h8300_attribute_table[];static tree h8300_handle_fndecl_attribute PARAMS ((tree *, tree, tree, int, bool *));static tree h8300_handle_eightbit_data_attribute PARAMS ((tree *, tree, tree, int, bool *));static tree h8300_handle_tiny_data_attribute PARAMS ((tree *, tree, tree, int, bool *));static void h8300_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));static void h8300_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));#ifndef OBJECT_FORMAT_ELFstatic void h8300_asm_named_section PARAMS ((const char *, unsigned int));#endif/* CPU_TYPE, says what cpu we're compiling for.  */int cpu_type;/* True if the current function is an interrupt handler   (either via #pragma or an attribute specification).  */static int interrupt_handler;/* True if the current function is an OS Task   (via an attribute specification).  */static int os_task;/* True if the current function is a monitor   (via an attribute specification).  */static int monitor;/* True if a #pragma saveall has been seen for the current function.  */static int pragma_saveall;static const char *const names_big[] ={ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" };static const char *const names_extended[] ={ "er0", "er1", "er2", "er3", "er4", "er5", "er6", "er7" };static const char *const names_upper_extended[] ={ "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7" };/* Points to one of the above.  *//* ??? The above could be put in an array indexed by CPU_TYPE.  */const char * const *h8_reg_names;/* Various operations needed by the following, indexed by CPU_TYPE.  */const char *h8_push_op, *h8_pop_op, *h8_mov_op;/* Initialize the GCC target structure.  */#undef TARGET_ATTRIBUTE_TABLE#define TARGET_ATTRIBUTE_TABLE h8300_attribute_table#undef TARGET_ASM_ALIGNED_HI_OP#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"#undef TARGET_ASM_FUNCTION_PROLOGUE#define TARGET_ASM_FUNCTION_PROLOGUE h8300_output_function_prologue#undef TARGET_ASM_FUNCTION_EPILOGUE#define TARGET_ASM_FUNCTION_EPILOGUE h8300_output_function_epiloguestruct gcc_target targetm = TARGET_INITIALIZER;/* Initialize various cpu specific globals at start up.  */voidh8300_init_once (){  static const char *const h8_push_ops[2] = { "push" , "push.l" };  static const char *const h8_pop_ops[2]  = { "pop"  , "pop.l"  };  static const char *const h8_mov_ops[2]  = { "mov.w", "mov.l"  };  if (TARGET_H8300)    {      cpu_type = (int) CPU_H8300;      h8_reg_names = names_big;    }  else    {      /* For this we treat the H8/300H and H8/S the same.  */      cpu_type = (int) CPU_H8300H;      h8_reg_names = names_extended;    }  h8_push_op = h8_push_ops[cpu_type];  h8_pop_op = h8_pop_ops[cpu_type];  h8_mov_op = h8_mov_ops[cpu_type];  if (!TARGET_H8300S && TARGET_MAC)    {      error ("-ms2600 is used without -ms");      target_flags |= 1;    }}static const char *byte_reg (x, b)     rtx x;     int b;{  static const char *const names_small[] = {    "r0l", "r0h", "r1l", "r1h", "r2l", "r2h", "r3l", "r3h",    "r4l", "r4h", "r5l", "r5h", "r6l", "r6h", "r7l", "r7h"  };  return names_small[REGNO (x) * 2 + b];}/* REGNO must be saved/restored across calls if this macro is true.  */#define WORD_REG_USED(regno)						\  (regno < 7								\   /* No need to save registers if this function will not return.  */	\   && ! TREE_THIS_VOLATILE (current_function_decl)			\   && (pragma_saveall							\       /* Save any call saved register that was used.  */		\       || (regs_ever_live[regno] && !call_used_regs[regno])		\       /* Save the frame pointer if it was used.  */			\       || (regno == FRAME_POINTER_REGNUM && regs_ever_live[regno])	\       /* Save any register used in an interrupt handler.  */		\       || (interrupt_handler && regs_ever_live[regno])			\       /* Save call clobbered registers in non-leaf interrupt		\	  handlers.  */							\       || (interrupt_handler						\	   && call_used_regs[regno]					\	   && !current_function_is_leaf)))/* Output assembly language to FILE for the operation OP with operand size   SIZE to adjust the stack pointer.  */static voiddosize (file, op, size)     FILE *file;     const char *op;     unsigned int size;{  /* On the H8/300H and H8/S, for sizes <= 8 bytes, it is as good or     better to use adds/subs insns rather than add.l/sub.l with an     immediate value.     Also, on the H8/300, if we don't have a temporary to hold the     size of the frame in the prologue, we simply emit a sequence of     subs since this shouldn't happen often.  */  if ((TARGET_H8300 && size <= 4)      || ((TARGET_H8300H || TARGET_H8300S) && size <= 8)      || (TARGET_H8300 && interrupt_handler)      || (TARGET_H8300 && current_function_needs_context	  && ! strcmp (op, "sub")))    {      unsigned HOST_WIDE_INT amount;      /* Try different amounts in descending order.  */      for (amount = (TARGET_H8300H || TARGET_H8300S) ? 4 : 2;	   amount > 0;	   amount /= 2)	{	  for (; size >= amount; size -= amount)	    fprintf (file, "\t%ss\t#%d,sp\n", op, amount);	}    }  else    {      if (TARGET_H8300)	fprintf (file, "\tmov.w\t#%d,r3\n\t%s.w\tr3,sp\n", size, op);      else	fprintf (file, "\t%s.l\t#%d,sp\n", op, size);    }}/* Round up frame size SIZE.  */static intround_frame_size (size)     int size;{  return (size + STACK_BOUNDARY / 8 - 1) & -STACK_BOUNDARY / 8;}/* Compute which registers to push/pop.   Return a bit vector of registers.  */static unsigned intcompute_saved_regs (){  unsigned int saved_regs = 0;  int regno;  /* Construct a bit vector of registers to be pushed/popped.  */  for (regno = 0; regno <= 6; regno++)    {      if (WORD_REG_USED (regno))	saved_regs |= 1 << regno;    }  /* Don't push/pop the frame pointer as it is treated separately.  */  if (frame_pointer_needed)    saved_regs &= ~(1 << FRAME_POINTER_REGNUM);  return saved_regs;}/* Output assembly language code to push register RN.  */static voidpush (file, rn)     FILE *file;     int rn;{  fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[rn]);}/* Output assembly language code to pop register RN.  */static voidpop (file, rn)     FILE *file;     int rn;{  fprintf (file, "\t%s\t%s\n", h8_pop_op, h8_reg_names[rn]);}/* This is what the stack looks like after the prolog of    a function with a frame has been set up:   <args>   PC   FP			<- fp   <locals>   <saved registers> 	<- sp   This is what the stack looks like after the prolog of   a function which doesn't have a frame:   <args>   PC   <locals>   <saved registers>   	<- sp*//* Output assembly language code for the function prologue.  */static voidh8300_output_function_prologue (file, size)     FILE *file;     HOST_WIDE_INT size;{  int fsize = round_frame_size (size);  int idx;  int saved_regs;  int n_regs;  /* Note a function with the interrupt attribute and set interrupt_handler     accordingly.  */  if (h8300_interrupt_function_p (current_function_decl))    interrupt_handler = 1;  /* If the current function has the OS_Task attribute set, then     we have a naked prologue.  */  if (h8300_os_task_function_p (current_function_decl))    {      fprintf (file, ";OS_Task prologue\n");      os_task = 1;      return;    }  if (h8300_monitor_function_p (current_function_decl))    {      /* My understanding of monitor functions is they act just	 like interrupt functions, except the prologue must	 mask interrupts.  */      fprintf (file, ";monitor prologue\n");      interrupt_handler = 1;      monitor = 1;      if (TARGET_H8300)	{	  fprintf (file, "\tsubs\t#2,sp\n");	  push (file, 0);	  fprintf (file, "\tstc\tccr,r0l\n");	  fprintf (file, "\tmov.b\tr0l,@(2,sp)\n");	  pop (file, 0);	  fprintf (file, "\torc\t#128,ccr\n");	}      else if (TARGET_H8300H)	{	  push (file, 0);	  fprintf (file, "\tstc\tccr,r0l\n");	  fprintf (file, "\tmov.b\tr0l,@(4,sp)\n");	  pop (file, 0);	  fprintf (file, "\torc\t#128,ccr\n");	}      else if (TARGET_H8300S)	{	  fprintf (file, "\tstc\texr,@-sp\n");	  push (file, 0);	  fprintf (file, "\tstc\tccr,r0l\n");	  fprintf (file, "\tmov.b\tr0l,@(6,sp)\n");	  pop (file, 0);	  fprintf (file, "\torc\t#128,ccr\n");	}      else	abort ();    }  if (frame_pointer_needed)    {      /* Push fp.  */      push (file, FRAME_POINTER_REGNUM);      fprintf (file, "\t%s\t%s,%s\n", h8_mov_op,	       h8_reg_names[STACK_POINTER_REGNUM],	       h8_reg_names[FRAME_POINTER_REGNUM]);    }  /* Leave room for locals.  */  dosize (file, "sub", fsize);  /* Push the rest of the registers in ascending order.  */  saved_regs = compute_saved_regs ();  for (idx = 0; idx < FIRST_PSEUDO_REGISTER; idx += n_regs)    {      int regno = idx;      n_regs = 1;      if (saved_regs & (1 << regno))	{	  if (TARGET_H8300S)	    {	      /* See how many registers we can push at the same time.  */	      if ((regno == 0 || regno == 4)		  && ((saved_regs >> regno) & 0x0f) == 0x0f)		n_regs = 4;	      else if ((regno == 0 || regno == 4)		       && ((saved_regs >> regno) & 0x07) == 0x07)		n_regs = 3;	      else if ((regno == 0 || regno == 2 || regno == 4 || regno == 6)		       && ((saved_regs >> regno) & 0x03) == 0x03)		n_regs = 2;	    }	  if (n_regs == 1)	    push (file, regno);	  else	    fprintf (file, "\tstm.l\t%s-%s,@-sp\n",		     h8_reg_names[regno],		     h8_reg_names[regno + (n_regs - 1)]);	}    }}/* Output assembly language code for the function epilogue.  */static voidh8300_output_function_epilogue (file, size)     FILE *file;     HOST_WIDE_INT size;{  int fsize = round_frame_size (size);  int idx;  rtx insn = get_last_insn ();  int saved_regs;  int n_regs;  if (os_task)    {      /* OS_Task epilogues are nearly naked -- they just have an	 rts instruction.  */      fprintf (file, ";OS_task epilogue\n");      fprintf (file, "\trts\n");      goto out;    }  /* Monitor epilogues are the same as interrupt function epilogues.     Just make a note that we're in an monitor epilogue.  */  if (monitor)    fprintf (file, ";monitor epilogue\n");  /* If the last insn was a BARRIER, we don't have to write any code.  */  if (GET_CODE (insn) == NOTE)    insn = prev_nonnote_insn (insn);  if (insn && GET_CODE (insn) == BARRIER)    goto out;  /* Pop the saved registers in descending order.  */  saved_regs = compute_saved_regs ();  for (idx = 0; idx < FIRST_PSEUDO_REGISTER; idx += n_regs)    {      int regno = (FIRST_PSEUDO_REGISTER - 1) - idx;      n_regs = 1;      if (saved_regs & (1 << regno))	{	  if (TARGET_H8300S)	    {	      /* See how many registers we can pop at the same time.  */	      if ((regno == 7 || regno == 3)		  && ((saved_regs >> (regno - 3)) & 0x0f) == 0x0f)		n_regs = 4;	      else if ((regno == 6 || regno == 2)		       && ((saved_regs >> (regno - 2)) & 0x07) == 0x07)		n_regs = 3;	      else if ((regno == 7 || regno == 5 || regno == 3 || regno == 1)		       && ((saved_regs >> (regno - 1)) & 0x03) == 0x03)		n_regs = 2;	    }	  if (n_regs == 1)	    pop (file, regno);	  else	    fprintf (file, "\tldm.l\t@sp+,%s-%s\n",		     h8_reg_names[regno - (n_regs - 1)],		     h8_reg_names[regno]);	}    }  /* Deallocate locals.  */  dosize (file, "add", fsize);  /* Pop frame pointer if we had one.  */  if (frame_pointer_needed)    pop (file, FRAME_POINTER_REGNUM);  if (interrupt_handler)    fprintf (file, "\trte\n");  else    fprintf (file, "\trts\n"); out:  interrupt_handler = 0;  os_task = 0;  monitor = 0;

⌨️ 快捷键说明

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