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

📄 rs6000.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 4 页
字号:
/* Subroutines used for code generation on IBM RS/6000.   Copyright (C) 1991 Free Software Foundation, Inc.   Contributed by Richard Kenner (kenner@nyu.edu)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, 675 Mass Ave, Cambridge, MA 02139, USA.  */#include <stdio.h>#include "config.h"#include "rtl.h"#include "regs.h"#include "hard-reg-set.h"#include "real.h"#include "insn-config.h"#include "conditions.h"#include "insn-flags.h"#include "output.h"#include "insn-attr.h"#include "flags.h"#include "recog.h"#include "expr.h"#include "obstack.h"#include "tree.h"extern char *language_string;#define min(A,B)	((A) < (B) ? (A) : (B))#define max(A,B)	((A) > (B) ? (A) : (B))/* Set to non-zero by "fix" operation to indicate that itrunc and   uitrunc must be defined.  */int rs6000_trunc_used;/* Set to non-zero once they have been defined.  */static int trunc_defined;/* Save information from a "cmpxx" operation until the branch or scc is   emitted.  */rtx rs6000_compare_op0, rs6000_compare_op1;int rs6000_compare_fp_p;/* Return non-zero if this function is known to have a null epilogue.  */intdirect_return (){  return (reload_completed	  && first_reg_to_save () == 32	  && first_fp_reg_to_save () == 64	  && ! regs_ever_live[65]	  && ! rs6000_pushes_stack ());}/* Returns 1 always.  */intany_operand (op, mode)     register rtx op;     enum machine_mode mode;{  return 1;}/* Return 1 if OP is a constant that can fit in a D field.  */intshort_cint_operand (op, mode)     register rtx op;     enum machine_mode mode;{  return (GET_CODE (op) == CONST_INT	  && (unsigned) (INTVAL (op) + 0x8000) < 0x10000);}/* Similar for a unsigned D field.  */intu_short_cint_operand (op, mode)     register rtx op;     enum machine_mode mode;{  return (GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffff0000) == 0);}/* Return 1 if OP is a CONST_INT that cannot fit in a signed D field.  */intnon_short_cint_operand (op, mode)     register rtx op;     enum machine_mode mode;{  return (GET_CODE (op) == CONST_INT	  && (unsigned) (INTVAL (op) + 0x8000) >= 0x10000);}/* Returns 1 if OP is a register that is not special (i.e., not MQ,   ctr, or lr).  */intgpc_reg_operand (op, mode)     register rtx op;     enum machine_mode mode;{  return (register_operand (op, mode)	  && (GET_CODE (op) != REG || REGNO (op) >= 67 || REGNO (op) < 64));}/* Returns 1 if OP is either a pseudo-register or a register denoting a   CR field.  */intcc_reg_operand (op, mode)     register rtx op;     enum machine_mode mode;{  return (register_operand (op, mode)	  && (GET_CODE (op) != REG	      || REGNO (op) >= FIRST_PSEUDO_REGISTER	      || CR_REGNO_P (REGNO (op))));}/* Returns 1 if OP is either a constant integer valid for a D-field or a   non-special register.  If a register, it must be in the proper mode unless   MODE is VOIDmode.  */intreg_or_short_operand (op, mode)      register rtx op;      enum machine_mode mode;{  if (GET_CODE (op) == CONST_INT)    return short_cint_operand (op, mode);  return gpc_reg_operand (op, mode);}/* Similar, except check if the negation of the constant would be valid for   a D-field.  */intreg_or_neg_short_operand (op, mode)      register rtx op;      enum machine_mode mode;{  if (GET_CODE (op) == CONST_INT)    return CONST_OK_FOR_LETTER_P (INTVAL (op), 'P');  return gpc_reg_operand (op, mode);}/* Return 1 if the operand is either a register or an integer whose high-order   16 bits are zero.  */intreg_or_u_short_operand (op, mode)     register rtx op;     enum machine_mode mode;{  if (GET_CODE (op) == CONST_INT      && (INTVAL (op) & 0xffff0000) == 0)    return 1;  return gpc_reg_operand (op, mode);}/* Return 1 is the operand is either a non-special register or ANY   constant integer.  */intreg_or_cint_operand (op, mode)    register rtx op;    enum machine_mode mode;{     return GET_CODE (op) == CONST_INT || gpc_reg_operand (op, mode);}/* Return 1 if the operand is a CONST_DOUBLE and it can be put into a   register with one instruction per word.  For SFmode, this means  that   the low 16-bits are zero.  For DFmode, it means the low 16-bits of   the first word are zero and the high 16 bits of the second word   are zero (usually all bits in the low-order word will be zero).   We only do this if we can safely read CONST_DOUBLE_{LOW,HIGH}.  */inteasy_fp_constant (op, mode)     register rtx op;     register enum machine_mode mode;{  rtx low, high;  if (GET_CODE (op) != CONST_DOUBLE      || GET_MODE (op) != mode      || GET_MODE_CLASS (mode) != MODE_FLOAT)    return 0;  high = operand_subword (op, 0, 0, mode);  low = operand_subword (op, 1, 0, mode);  if (high == 0 || GET_CODE (high) != CONST_INT || (INTVAL (high) & 0xffff))    return 0;  return (mode == SFmode	  || (low != 0 && GET_CODE (low) == CONST_INT	      && (INTVAL (low) & 0xffff0000) == 0));}      /* Return 1 if the operand is either a floating-point register, a pseudo   register, or memory.  */intfp_reg_or_mem_operand (op, mode)     register rtx op;     enum machine_mode mode;{  return (memory_operand (op, mode)	  || (register_operand (op, mode)	      && (GET_CODE (op) != REG		  || REGNO (op) >= FIRST_PSEUDO_REGISTER		  || FP_REGNO_P (REGNO (op)))));}/* Return 1 if the operand is either an easy FP constant (see above) or   memory.  */intmem_or_easy_const_operand (op, mode)     register rtx op;     enum machine_mode mode;{  return memory_operand (op, mode) || easy_fp_constant (op, mode);}/* Return 1 if the operand is either a non-special register or an item   that can be used as the operand of an SI add insn.  */intadd_operand (op, mode)    register rtx op;    enum machine_mode mode;{  return (reg_or_short_operand (op, mode)	  || (GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffff) == 0));}/* Return 1 if OP is a constant but not a valid add_operand.  */intnon_add_cint_operand (op, mode)     register rtx op;     enum machine_mode mode;{  return (GET_CODE (op) == CONST_INT	  && (unsigned) (INTVAL (op) + 0x8000) >= 0x10000	  && (INTVAL (op) & 0xffff) != 0);}/* Return 1 if the operand is a non-special register or a constant that   can be used as the operand of an OR or XOR insn on the RS/6000.  */intlogical_operand (op, mode)     register rtx op;     enum machine_mode mode;{  return (gpc_reg_operand (op, mode)	  || (GET_CODE (op) == CONST_INT	      && ((INTVAL (op) & 0xffff0000) == 0		  || (INTVAL (op) & 0xffff) == 0)));}/* Return 1 if C is a constant that is not a logical operand (as   above).  */intnon_logical_cint_operand (op, mode)     register rtx op;     enum machine_mode mode;{  return (GET_CODE (op) == CONST_INT	  && (INTVAL (op) & 0xffff0000) != 0	  && (INTVAL (op) & 0xffff) != 0);}/* Return 1 if C is a constant that can be encoded in a mask on the   RS/6000.  It is if there are no more than two 1->0 or 0->1 transitions.   Reject all ones and all zeros, since these should have been optimized   away and confuse the making of MB and ME.  */intmask_constant (c)     register int c;{  int i;  int last_bit_value;  int transitions = 0;  if (c == 0 || c == ~0)    return 0;  last_bit_value = c & 1;  for (i = 1; i < 32; i++)    if (((c >>= 1) & 1) != last_bit_value)      last_bit_value ^= 1, transitions++;  return transitions <= 2;}/* Return 1 if the operand is a constant that is a mask on the RS/6000. */intmask_operand (op, mode)     register rtx op;     enum machine_mode mode;{  return GET_CODE (op) == CONST_INT && mask_constant (INTVAL (op));}/* Return 1 if the operand is either a non-special register or a   constant that can be used as the operand of an RS/6000 logical AND insn.  */intand_operand (op, mode)    register rtx op;    enum machine_mode mode;{  return (reg_or_short_operand (op, mode)	  || logical_operand (op, mode)	  || mask_operand (op, mode));}/* Return 1 if the operand is a constant but not a valid operand for an AND   insn.  */intnon_and_cint_operand (op, mode)     register rtx op;     enum machine_mode mode;{  return GET_CODE (op) == CONST_INT && ! and_operand (op, mode);}/* Return 1 if the operand is a general register or memory operand.  */intreg_or_mem_operand (op, mode)     register rtx op;     register enum machine_mode mode;{  return gpc_reg_operand (op, mode) || memory_operand (op, mode);}/* Return 1 if the operand, used inside a MEM, is a valid first argument   to CALL.  This is a SYMBOL_REF or a pseudo-register, which will be   forced to lr.  */intcall_operand (op, mode)     register rtx op;     enum machine_mode mode;{  if (mode != VOIDmode && GET_MODE (op) != mode)    return 0;  return (GET_CODE (op) == SYMBOL_REF	  || (GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER));}/* Return 1 if this operand is a valid input for a move insn.  */intinput_operand (op, mode)     register rtx op;     enum machine_mode mode;{  if (memory_operand (op, mode))    return 1;  /* For floating-point or multi-word mode, only register or memory     is valid.  */  if (GET_MODE_CLASS (mode) == MODE_FLOAT      || GET_MODE_SIZE (mode) > UNITS_PER_WORD)    return gpc_reg_operand (op, mode);  /* The only cases left are integral modes one word or smaller (we     do not get called for MODE_CC values).  These can be in any     register.  */  if (register_operand (op, mode))    return;  /* For HImode and QImode, any constant is valid. */  if ((mode == HImode || mode == QImode)      && GET_CODE (op) == CONST_INT)    return 1;  /* Otherwise, we will be doing this SET with an add, so anything valid     for an add will be valid.  */  return add_operand (op, mode);}/* Return 1 if OP is a load multiple operation.  It is known to be a   PARALLEL and the first section will be tested.  */intload_multiple_operation (op, mode)     rtx op;     enum machine_mode mode;{  int count = XVECLEN (op, 0);  int dest_regno;  rtx src_addr;  int i;  /* Perform a quick check so we don't blow up below.  */  if (count <= 1      || GET_CODE (XVECEXP (op, 0, 0)) != SET      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)    return 0;  dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));  src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);  for (i = 1; i < count; i++)    {      rtx elt = XVECEXP (op, 0, i);      if (GET_CODE (elt) != SET	  || GET_CODE (SET_DEST (elt)) != REG	  || GET_MODE (SET_DEST (elt)) != SImode	  || REGNO (SET_DEST (elt)) != dest_regno + i	  || GET_CODE (SET_SRC (elt)) != MEM	  || GET_MODE (SET_SRC (elt)) != SImode	  || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS	  || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)

⌨️ 快捷键说明

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