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

📄 s390.c

📁 gcc3.2.1源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Subroutines used for code generation on IBM S/390 and zSeries   Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.   Contributed by Hartmut Penner (hpenner@de.ibm.com) and                  Ulrich Weigand (uweigand@de.ibm.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 "tm_p.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 "except.h"#include "function.h"#include "recog.h"#include "expr.h"#include "reload.h"#include "toplev.h"#include "basic-block.h"#include "integrate.h"#include "ggc.h"#include "target.h"#include "target-def.h"#include "debug.h"static bool s390_assemble_integer PARAMS ((rtx, unsigned int, int));static int s390_adjust_cost PARAMS ((rtx, rtx, rtx, int));static int s390_adjust_priority PARAMS ((rtx, int));#undef  TARGET_ASM_ALIGNED_HI_OP#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"#undef  TARGET_ASM_ALIGNED_DI_OP#define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"#undef  TARGET_ASM_INTEGER#define TARGET_ASM_INTEGER s390_assemble_integer#undef  TARGET_ASM_FUNCTION_PROLOGUE #define TARGET_ASM_FUNCTION_PROLOGUE s390_function_prologue#undef  TARGET_ASM_FUNCTION_EPILOGUE #define TARGET_ASM_FUNCTION_EPILOGUE s390_function_epilogue#undef  TARGET_ASM_OPEN_PAREN#define TARGET_ASM_OPEN_PAREN ""#undef  TARGET_ASM_CLOSE_PAREN#define TARGET_ASM_CLOSE_PAREN ""#undef  TARGET_SCHED_ADJUST_COST#define TARGET_SCHED_ADJUST_COST s390_adjust_cost#undef  TARGET_SCHED_ADJUST_PRIORITY#define TARGET_SCHED_ADJUST_PRIORITY s390_adjust_prioritystruct gcc_target targetm = TARGET_INITIALIZER;extern int reload_completed;/* The alias set for prologue/epilogue register save/restore.  */static int s390_sr_alias_set = 0;/* Function count for creating unique internal labels in a compile unit.  */int  s390_function_count = 0;/* Save information from a "cmpxx" operation until the branch or scc is   emitted.  */rtx s390_compare_op0, s390_compare_op1;/* Structure used to hold the components of a S/390 memory   address.  A legitimate address on S/390 is of the general   form          base + index + displacement   where any of the components is optional.   base and index are registers of the class ADDR_REGS,   displacement is an unsigned 12-bit immediate constant.  */struct s390_address{  rtx base;  rtx indx;  rtx disp;  int pointer;};/* Structure containing information for prologue and epilogue.  */ struct s390_frame{  int frame_pointer_p;  int return_reg_saved_p;  int save_fprs_p;  int first_save_gpr;  int first_restore_gpr;  int last_save_gpr;  int arg_frame_offset;  HOST_WIDE_INT frame_size;};static int s390_match_ccmode_set PARAMS ((rtx, enum machine_mode));static int s390_branch_condition_mask PARAMS ((rtx));static const char *s390_branch_condition_mnemonic PARAMS ((rtx, int));static int check_mode PARAMS ((rtx, enum machine_mode *));static int general_s_operand PARAMS ((rtx, enum machine_mode, int));static int s390_decompose_address PARAMS ((rtx, struct s390_address *, int));static int reg_used_in_mem_p PARAMS ((int, rtx));static int addr_generation_dependency_p PARAMS ((rtx, rtx));static void s390_split_branches PARAMS ((void));static void find_constant_pool_ref PARAMS ((rtx, rtx *));static void replace_constant_pool_ref PARAMS ((rtx *, rtx, rtx));static void s390_chunkify_pool PARAMS ((void));static int save_fprs_p PARAMS ((void));static int find_unused_clobbered_reg PARAMS ((void));static void s390_frame_info PARAMS ((struct s390_frame *));static rtx save_fpr PARAMS ((rtx, int, int));static rtx restore_fpr PARAMS ((rtx, int, int));static int s390_function_arg_size PARAMS ((enum machine_mode, tree)); /* Return true if SET either doesn't set the CC register, or else   the source and destination have matching CC modes and that    CC mode is at least as constrained as REQ_MODE.  */ static ints390_match_ccmode_set (set, req_mode)     rtx set;     enum machine_mode req_mode;{  enum machine_mode set_mode;  if (GET_CODE (set) != SET)    abort ();  if (GET_CODE (SET_DEST (set)) != REG || !CC_REGNO_P (REGNO (SET_DEST (set))))    return 1;  set_mode = GET_MODE (SET_DEST (set));  switch (set_mode)    {    case CCSmode:      if (req_mode != CCSmode)        return 0;      break;    case CCUmode:      if (req_mode != CCUmode)        return 0;      break;    case CCLmode:      if (req_mode != CCLmode)        return 0;      break;    case CCZmode:      if (req_mode != CCSmode && req_mode != CCUmode && req_mode != CCTmode)        return 0;      break;     default:      abort ();    }   return (GET_MODE (SET_SRC (set)) == set_mode);}/* Return true if every SET in INSN that sets the CC register    has source and destination with matching CC modes and that    CC mode is at least as constrained as REQ_MODE.  */ ints390_match_ccmode (insn, req_mode)     rtx insn;     enum machine_mode req_mode;{  int i;  if (GET_CODE (PATTERN (insn)) == SET)    return s390_match_ccmode_set (PATTERN (insn), req_mode);  if (GET_CODE (PATTERN (insn)) == PARALLEL)      for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)        {          rtx set = XVECEXP (PATTERN (insn), 0, i);          if (GET_CODE (set) == SET)            if (!s390_match_ccmode_set (set, req_mode))              return 0;        }  return 1;}/* Given a comparison code OP (EQ, NE, etc.) and the operands    OP0 and OP1 of a COMPARE, return the mode to be used for the    comparison.  */enum machine_modes390_select_ccmode (code, op0, op1)      enum rtx_code code;     rtx op0;     rtx op1;{  switch (code)    {      case EQ:      case NE:	if (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS	    || GET_CODE (op1) == NEG)	  return CCLmode;	return CCZmode;      case LE:      case LT:      case GE:      case GT:      case UNORDERED:      case ORDERED:      case UNEQ:      case UNLE:      case UNLT:      case UNGE:      case UNGT:      case LTGT:	return CCSmode;      case LEU:      case LTU:      case GEU:      case GTU:	return CCUmode;      default:	abort ();    }}/* Return branch condition mask to implement a branch    specified by CODE.  */static ints390_branch_condition_mask (code)    rtx code;{   const int CC0 = 1 << 3;  const int CC1 = 1 << 2;  const int CC2 = 1 << 1;  const int CC3 = 1 << 0;  if (GET_CODE (XEXP (code, 0)) != REG      || REGNO (XEXP (code, 0)) != CC_REGNUM      || XEXP (code, 1) != const0_rtx)    abort ();  switch (GET_MODE (XEXP (code, 0)))    {    case CCZmode:      switch (GET_CODE (code))        {        case EQ:	return CC0;	case NE:	return CC1 | CC2 | CC3;	default:	  abort ();        }      break;    case CCLmode:      switch (GET_CODE (code))        {        case EQ:	return CC0 | CC2;	case NE:	return CC1 | CC3;	case UNORDERED:	return CC2 | CC3;  /* carry */	case ORDERED:	return CC0 | CC1;  /* no carry */	default:	  abort ();        }      break;    case CCUmode:      switch (GET_CODE (code))        {        case EQ:	return CC0;        case NE:	return CC1 | CC2 | CC3;        case LTU:	return CC1;        case GTU:	return CC2;        case LEU:	return CC0 | CC1;        case GEU:	return CC0 | CC2;	default:	  abort ();        }      break;    case CCSmode:      switch (GET_CODE (code))        {        case EQ:	return CC0;        case NE:	return CC1 | CC2 | CC3;        case LT:	return CC1;        case GT:	return CC2;        case LE:	return CC0 | CC1;        case GE:	return CC0 | CC2;	case UNORDERED:	return CC3;	case ORDERED:	return CC0 | CC1 | CC2;	case UNEQ:	return CC0 | CC3;        case UNLT:	return CC1 | CC3;        case UNGT:	return CC2 | CC3;        case UNLE:	return CC0 | CC1 | CC3;        case UNGE:	return CC0 | CC2 | CC3;	case LTGT:	return CC1 | CC2;	default:	  abort ();        }    default:      abort ();    }}/* If INV is false, return assembler mnemonic string to implement    a branch specified by CODE.  If INV is true, return mnemonic    for the corresponding inverted branch.  */static const char *s390_branch_condition_mnemonic (code, inv)     rtx code;     int inv;{  static const char *mnemonic[16] =    {      NULL, "o", "h", "nle",      "l", "nhe", "lh", "ne",      "e", "nlh", "he", "nl",      "le", "nh", "no", NULL    };  int mask = s390_branch_condition_mask (code);  if (inv)    mask ^= 15;  if (mask < 1 || mask > 14)    abort ();  return mnemonic[mask];}/* If OP is an integer constant of mode MODE with exactly one   HImode subpart unequal to DEF, return the number of that    subpart.  As a special case, all HImode subparts of OP are   equal to DEF, return zero.  Otherwise, return -1.  */ints390_single_hi (op, mode, def)     rtx op;     enum machine_mode mode;     int def;{  if (GET_CODE (op) == CONST_INT)    {      unsigned HOST_WIDE_INT value;      int n_parts = GET_MODE_SIZE (mode) / 2;      int i, part = -1;      for (i = 0; i < n_parts; i++)        {          if (i == 0)            value = (unsigned HOST_WIDE_INT) INTVAL (op);          else            value >>= 16;          if ((value & 0xffff) != (unsigned)(def & 0xffff))            {              if (part != -1)                return -1;              else                part = i;            }        }      return part == -1 ? 0 : (n_parts - 1 - part);    }  else if (GET_CODE (op) == CONST_DOUBLE           && GET_MODE (op) == VOIDmode)    {      unsigned HOST_WIDE_INT value;      int n_parts = GET_MODE_SIZE (mode) / 2;      int i, part = -1;      for (i = 0; i < n_parts; i++)        {          if (i == 0)            value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op);          else if (i == HOST_BITS_PER_WIDE_INT / 16)            value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (op);          else            value >>= 16;          if ((value & 0xffff) != (unsigned)(def & 0xffff))            {              if (part != -1)                return -1;              else                part = i;            }        }      return part == -1 ? 0 : (n_parts - 1 - part);    }  return -1;      }/* Extract the HImode part number PART from integer    constant OP of mode MODE.  */ints390_extract_hi (op, mode, part)    rtx op;    enum machine_mode mode;    int part;{  int n_parts = GET_MODE_SIZE (mode) / 2;  if (part < 0 || part >= n_parts)    abort();  else    part = n_parts - 1 - part;  if (GET_CODE (op) == CONST_INT)    {      unsigned HOST_WIDE_INT value = (unsigned HOST_WIDE_INT) INTVAL (op);      return ((value >> (16 * part)) & 0xffff);    }  else if (GET_CODE (op) == CONST_DOUBLE           && GET_MODE (op) == VOIDmode)    {      unsigned HOST_WIDE_INT value;      if (part < HOST_BITS_PER_WIDE_INT / 16)        value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op);      else        value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (op),        part -= HOST_BITS_PER_WIDE_INT / 16;      return ((value >> (16 * part)) & 0xffff);     }  abort ();}/* If OP is an integer constant of mode MODE with exactly one   QImode subpart unequal to DEF, return the number of that    subpart.  As a special case, all QImode subparts of OP are   equal to DEF, return zero.  Otherwise, return -1.  */ints390_single_qi (op, mode, def)     rtx op;     enum machine_mode mode;     int def;{  if (GET_CODE (op) == CONST_INT)    {      unsigned HOST_WIDE_INT value;      int n_parts = GET_MODE_SIZE (mode);      int i, part = -1;      for (i = 0; i < n_parts; i++)        {          if (i == 0)            value = (unsigned HOST_WIDE_INT) INTVAL (op);          else

⌨️ 快捷键说明

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