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

📄 ns32k.c

📁 Mac OS X 10.4.9 for x86 Source Code gcc 实现源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Subroutines for assembler code output on the NS32000.   Copyright (C) 1988, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2004   Free Software Foundation, Inc.This file is part of GCC.GCC 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.GCC 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 GCC; 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 "coretypes.h"#include "tm.h"#include "rtl.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 "tree.h"#include "function.h"#include "expr.h"#include "flags.h"#include "recog.h"#include "tm_p.h"#include "target.h"#include "target-def.h"#include "toplev.h"#ifdef OSF_OSint ns32k_num_files = 0;#endif/* This duplicates reg_class_contents in reg_class.c, but maybe that isn't   initialized in time. Also this is more convenient as an array of ints.   We know that HARD_REG_SET fits in an unsigned int */const unsigned int ns32k_reg_class_contents[N_REG_CLASSES][1] = REG_CLASS_CONTENTS;const enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] ={  GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,  GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,  FLOAT_REG0, LONG_FLOAT_REG0, FLOAT_REGS, FLOAT_REGS,  FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,  LONG_REGS, LONG_REGS, LONG_REGS, LONG_REGS,  LONG_REGS, LONG_REGS, LONG_REGS, LONG_REGS,  FRAME_POINTER_REG, STACK_POINTER_REG};static const char *const ns32k_out_reg_names[] = OUTPUT_REGISTER_NAMES;static rtx gen_indexed_expr (rtx, rtx, rtx);static const char *singlemove_string (rtx *);static void move_tail (rtx[], int, int);static tree ns32k_handle_fntype_attribute (tree *, tree, tree, int, bool *);const struct attribute_spec ns32k_attribute_table[];static void ns32k_output_function_prologue (FILE *, HOST_WIDE_INT);static void ns32k_output_function_epilogue (FILE *, HOST_WIDE_INT);static bool ns32k_rtx_costs (rtx, int, int, int *);static int ns32k_address_cost (rtx);static rtx ns32k_struct_value_rtx (tree, int);static int ns32k_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,				    tree, bool);/* Initialize the GCC target structure.  */#undef TARGET_ATTRIBUTE_TABLE#define TARGET_ATTRIBUTE_TABLE ns32k_attribute_table#undef TARGET_ASM_ALIGNED_HI_OP#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"#ifdef ENCORE_ASM#undef TARGET_ASM_ALIGNED_SI_OP#define TARGET_ASM_ALIGNED_SI_OP "\t.double\t"#endif#undef TARGET_ASM_FUNCTION_PROLOGUE#define TARGET_ASM_FUNCTION_PROLOGUE ns32k_output_function_prologue#undef TARGET_ASM_FUNCTION_EPILOGUE#define TARGET_ASM_FUNCTION_EPILOGUE ns32k_output_function_epilogue#undef TARGET_RTX_COSTS#define TARGET_RTX_COSTS ns32k_rtx_costs#undef TARGET_ADDRESS_COST#define TARGET_ADDRESS_COST ns32k_address_cost#undef TARGET_STRUCT_VALUE_RTX#define TARGET_STRUCT_VALUE_RTX ns32k_struct_value_rtx#undef TARGET_ARG_PARTIAL_BYTES#define TARGET_ARG_PARTIAL_BYTES ns32k_arg_partial_bytes#undef TARGET_ASM_FILE_START_APP_OFF#define TARGET_ASM_FILE_START_APP_OFF truestruct gcc_target targetm = TARGET_INITIALIZER;/* Generate the assembly code for function entry.  FILE is a stdio   stream to output the code to.  SIZE is an int: how many units of   temporary storage to allocate.   Refer to the array `regs_ever_live' to determine which registers to   save; `regs_ever_live[I]' is nonzero if register number I is ever   used in the function.  This function is responsible for knowing   which registers should not be saved even if used.  *//* * The function prologue for the ns32k is fairly simple. * If a frame pointer is needed (decided in reload.c ?) then * we need assembler of the form * *  # Save the oldframe pointer, set the new frame pointer, make space *  # on the stack and save any general purpose registers necessary * *  enter [<general purpose regs to save>], <local stack space> * *  movf  fn, tos    # Save any floating point registers necessary *  . *  . * * If a frame pointer is not needed we need assembler of the form * *  # Make space on the stack * *  adjspd <local stack space + 4> * *  # Save any general purpose registers necessary * *  save [<general purpose regs to save>] * *  movf  fn, tos    # Save any floating point registers necessary *  . *  . */#if !defined (MERLIN_TARGET) && !defined (UTEK_ASM)#if defined(IMMEDIATE_PREFIX) && IMMEDIATE_PREFIX#define ADJSP(FILE, N) \        fprintf (FILE, "\tadjspd %c" HOST_WIDE_INT_PRINT_DEC "\n", IMMEDIATE_PREFIX, (N))#else#define ADJSP(FILE, N) \        fprintf (FILE, "\tadjspd " HOST_WIDE_INT_PRINT_DEC "\n", (N))#endifstatic voidns32k_output_function_prologue (FILE *file, HOST_WIDE_INT size){  register int regno, g_regs_used = 0;  int used_regs_buf[8], *bufp = used_regs_buf;  int used_fregs_buf[17], *fbufp = used_fregs_buf;  for (regno = R0_REGNUM; regno < F0_REGNUM; regno++)    if (regs_ever_live[regno]	&& ! call_used_regs[regno])      {        *bufp++ = regno; g_regs_used++;      }  *bufp = -1;  for (; regno < FRAME_POINTER_REGNUM; regno++)    if (regs_ever_live[regno] && !call_used_regs[regno])      {        *fbufp++ = regno;      }  *fbufp = -1;  bufp = used_regs_buf;  if (frame_pointer_needed)    fprintf (file, "\tenter [");  else    {      if (size)        ADJSP (file, size + 4);      if (g_regs_used && g_regs_used > 4)        fprintf (file, "\tsave [");      else	{	  while (*bufp >= 0)            fprintf (file, "\tmovd r%d,tos\n", *bufp++);	  g_regs_used = 0;	}    }  while (*bufp >= 0)    {      fprintf (file, "r%d", *bufp++);      if (*bufp >= 0)	fputc (',', file);    }  if (frame_pointer_needed)    fprintf (file, "]," HOST_WIDE_INT_PRINT_DEC "\n", size);  else if (g_regs_used)    fprintf (file, "]\n");  fbufp = used_fregs_buf;  while (*fbufp >= 0)    {      if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1))	fprintf (file, "\tmovf %s,tos\n", ns32k_out_reg_names[*fbufp++]);      else	{	  fprintf (file, "\tmovl %s,tos\n",		   ns32k_out_reg_names[fbufp[0]]);	  fbufp += 2;	}    }  if (flag_pic && current_function_uses_pic_offset_table)    {      fprintf (file, "\tsprd sb,tos\n");      if (TARGET_REGPARM)	{	  fprintf (file, "\taddr __GLOBAL_OFFSET_TABLE_(pc),tos\n");	  fprintf (file, "\tlprd sb,tos\n");	}      else	{	  fprintf (file, "\taddr __GLOBAL_OFFSET_TABLE_(pc),r0\n");	  fprintf (file, "\tlprd sb,r0\n");	}    }}#else /* MERLIN_TARGET || UTEK_ASM  *//* This differs from the standard one above in printing a bitmask   rather than a register list in the enter or save instruction.  */static voidns32k_output_function_prologue (file, size)     FILE *file;     HOST_WIDE_INT size;{  register int regno, g_regs_used = 0;  int used_regs_buf[8], *bufp = used_regs_buf;  int used_fregs_buf[8], *fbufp = used_fregs_buf;  for (regno = 0; regno < 8; regno++)    if (regs_ever_live[regno]	&& ! call_used_regs[regno])      {	*bufp++ = regno; g_regs_used++;      }  *bufp = -1;  for (; regno < 16; regno++)    if (regs_ever_live[regno] && !call_used_regs[regno]) {      *fbufp++ = regno;    }  *fbufp = -1;  bufp = used_regs_buf;  if (frame_pointer_needed)    fprintf (file, "\tenter ");  else if (g_regs_used)    fprintf (file, "\tsave ");  if (frame_pointer_needed || g_regs_used)    {      char mask = 0;      while (*bufp >= 0)	mask |= 1 << *bufp++;      fprintf (file, "$0x%x", (int) mask & 0xff);    }  if (frame_pointer_needed)#ifdef UTEK_ASM    fprintf (file, ",$%d\n", size);#else    fprintf (file, ",%d\n", size);#endif  else if (g_regs_used)    fprintf (file, "\n");  fbufp = used_fregs_buf;  while (*fbufp >= 0)    {      if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1))	fprintf (file, "\tmovf f%d,tos\n", *fbufp++ - 8);      else	{	  fprintf (file, "\tmovl f%d,tos\n", fbufp[0] - 8);	  fbufp += 2;	}    }}#endif /* MERLIN_TARGET || UTEK_ASM  *//* This function generates the assembly code for function exit,   on machines that need it.   The function epilogue should not depend on the current stack pointer,   if EXIT_IGNORE_STACK is nonzero.  That doesn't apply here.   If a frame pointer is needed (decided in reload.c ?) then   we need assembler of the form    movf  tos, fn	# Restore any saved floating point registers    .    .    # Restore any saved general purpose registers, restore the stack    # pointer from the frame pointer, restore the old frame pointer.    exit [<general purpose regs to save>]   If a frame pointer is not needed we need assembler of the form    # Restore any general purpose registers saved    movf  tos, fn	# Restore any saved floating point registers    .    .    .    restore [<general purpose regs to save>]    # reclaim space allocated on stack    adjspd <-(local stack space + 4)> */#if !defined (MERLIN_TARGET) && !defined (UTEK_ASM)static voidns32k_output_function_epilogue (FILE *file, HOST_WIDE_INT size){  register int regno, g_regs_used = 0, f_regs_used = 0;  int used_regs_buf[8], *bufp = used_regs_buf;  int used_fregs_buf[17], *fbufp = used_fregs_buf;  if (flag_pic && current_function_uses_pic_offset_table)    fprintf (file, "\tlprd sb,tos\n");  *fbufp++ = -2;  for (regno = F0_REGNUM; regno < FRAME_POINTER_REGNUM; regno++)    if (regs_ever_live[regno] && !call_used_regs[regno])      {	*fbufp++ = regno; f_regs_used++;      }  fbufp--;  for (regno = 0; regno < F0_REGNUM; regno++)    if (regs_ever_live[regno]	&& ! call_used_regs[regno])      {        *bufp++ = regno; g_regs_used++;      }  while (fbufp > used_fregs_buf)    {      if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1)	{	  fprintf (file, "\tmovl tos,%s\n",		   ns32k_out_reg_names[fbufp[-1]]);	  fbufp -= 2;	}      else fprintf (file, "\tmovf tos,%s\n", ns32k_out_reg_names[*fbufp--]);    }  if (frame_pointer_needed)    fprintf (file, "\texit [");  else    {      if (g_regs_used && g_regs_used > 4)        fprintf (file, "\trestore [");      else        {	  while (bufp > used_regs_buf)            fprintf (file, "\tmovd tos,r%d\n", *--bufp);	  g_regs_used = 0;        }    }  while (bufp > used_regs_buf)    {      fprintf (file, "r%d", *--bufp);      if (bufp > used_regs_buf)	fputc (',', file);    }  if (g_regs_used || frame_pointer_needed)    fprintf (file, "]\n");  if (size && !frame_pointer_needed)    ADJSP (file, -(size + 4));  if (current_function_pops_args)    fprintf (file, "\tret %d\n", current_function_pops_args);  else    fprintf (file, "\tret 0\n");}#else /* MERLIN_TARGET || UTEK_ASM  *//* This differs from the standard one above in printing a bitmask   rather than a register list in the exit or restore instruction.  */static voidns32k_output_function_epilogue (file, size)     FILE *file;     HOST_WIDE_INT size ATTRIBUTE_UNUSED;{  register int regno, g_regs_used = 0, f_regs_used = 0;  int used_regs_buf[8], *bufp = used_regs_buf;  int used_fregs_buf[8], *fbufp = used_fregs_buf;  *fbufp++ = -2;  for (regno = 8; regno < 16; regno++)    if (regs_ever_live[regno] && !call_used_regs[regno]) {      *fbufp++ = regno; f_regs_used++;    }  fbufp--;  for (regno = 0; regno < 8; regno++)    if (regs_ever_live[regno]	&& ! call_used_regs[regno])      {	*bufp++ = regno; g_regs_used++;      }  while (fbufp > used_fregs_buf)    {      if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1)	{	  fprintf (file, "\tmovl tos,f%d\n", fbufp[-1] - 8);	  fbufp -= 2;	}      else fprintf (file, "\tmovf tos,f%d\n", *fbufp-- - 8);    }  if (frame_pointer_needed)    fprintf (file, "\texit ");  else if (g_regs_used)    fprintf (file, "\trestore ");  if (g_regs_used || frame_pointer_needed)    {      char mask = 0;      while (bufp > used_regs_buf)	{	  /* Utek assembler takes care of reversing this */	  mask |= 1 << *--bufp;	}      fprintf (file, "$0x%x\n", (int) mask & 0xff);    }#ifdef UTEK_ASM  if (current_function_pops_args)    fprintf (file, "\tret $%d\n", current_function_pops_args);  else    fprintf (file, "\tret $0\n");#else  if (current_function_pops_args)    fprintf (file, "\tret %d\n", current_function_pops_args);  else    fprintf (file, "\tret 0\n");#endif}#endif /* MERLIN_TARGET || UTEK_ASM  *//* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */ inthard_regno_mode_ok (int regno, enum machine_mode mode){  int size = GET_MODE_UNIT_SIZE (mode);  if (FLOAT_MODE_P (mode))    {      if (size == UNITS_PER_WORD && regno < L1_REGNUM)	return 1;      if (size == UNITS_PER_WORD * 2	  && (((regno & 1) == 0 && regno < FRAME_POINTER_REGNUM)))	return 1;      return 0;    }  if (size == UNITS_PER_WORD * 2      && (regno & 1) == 0 && regno < F0_REGNUM)    return 1;  if (size <= UNITS_PER_WORD      && (regno < F0_REGNUM || regno == FRAME_POINTER_REGNUM	  || regno == STACK_POINTER_REGNUM))    return 1;  return 0;}static boolns32k_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total){  switch (code)    {    case CONST_INT:      if (INTVAL (x) <= 7 && INTVAL (x) >= -8)	*total = 0;      else if (INTVAL (x) < 0x2000 && INTVAL (x) >= -0x2000)        *total = 1;      else	*total = 3;      return true;    case CONST:    case LABEL_REF:    case SYMBOL_REF:      *total = 3;      return true;    case CONST_DOUBLE:      *total = 5;      return true;    default:      return false;    }}intregister_move_cost (enum reg_class CLASS1, enum reg_class CLASS2){  if (CLASS1 == NO_REGS || CLASS2 == NO_REGS)    return 2;  if ((SUBSET_P (CLASS1, FP_REGS) && !SUBSET_P (CLASS2, FP_REGS))   || (!SUBSET_P (CLASS1, FP_REGS) && SUBSET_P (CLASS2, FP_REGS)))    return 8;  if (((CLASS1) == STACK_POINTER_REG && !SUBSET_P (CLASS2,GENERAL_REGS))      || ((CLASS2) == STACK_POINTER_REG && !SUBSET_P (CLASS1,GENERAL_REGS)))    return 6;  if (((CLASS1) == FRAME_POINTER_REG && !SUBSET_P (CLASS2,GENERAL_REGS))      || ((CLASS2) == FRAME_POINTER_REG && !SUBSET_P (CLASS1,GENERAL_REGS)))    return 6;  return 2;}#if 0/* We made the insn definitions copy from floating point to general  registers via the stack.  */intsecondary_memory_needed (enum reg_class CLASS1,			 enum reg_class CLASS2,			 enum machine_mode M){  int ret = ((SUBSET_P (CLASS1, FP_REGS) && !SUBSET_P (CLASS2, FP_REGS))

⌨️ 快捷键说明

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