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

📄 alpha.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Subroutines used for code generation on the DEC Alpha.   Copyright (C) 1992 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 "reload.h"#include "expr.h"#include "obstack.h"#include "tree.h"/* Save information from a "cmpxx" operation until the branch or scc is   emitted.  */rtx alpha_compare_op0, alpha_compare_op1;int alpha_compare_fp_p;/* Save the name of the current function as used by the assembler.  This   is used by the epilogue.  */char *alpha_function_name;/* Nonzero if the current function needs gp.  */int alpha_function_needs_gp;/* Returns 1 if VALUE is a mask that contains full bytes of zero or ones.  */intzap_mask (value)     HOST_WIDE_INT value;{  int i;  for (i = 0; i < HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR;       i++, value >>= 8)    if ((value & 0xff) != 0 && (value & 0xff) != 0xff)      return 0;  return 1;}/* Returns 1 if OP is either the constant zero or a register.  If a   register, it must be in the proper mode unless MODE is VOIDmode.  */intreg_or_0_operand (op, mode)      register rtx op;      enum machine_mode mode;{  return op == const0_rtx || register_operand (op, mode);}/* Return 1 if OP is an 8-bit constant or any register.  */intreg_or_8bit_operand (op, mode)     register rtx op;     enum machine_mode mode;{  return ((GET_CODE (op) == CONST_INT	   && (unsigned HOST_WIDE_INT) INTVAL (op) < 0x100)	  || register_operand (op, mode));}/* Return 1 if the operand is a valid second operand to an add insn.  */intadd_operand (op, mode)     register rtx op;     enum machine_mode mode;{  if (GET_CODE (op) == CONST_INT)    return ((unsigned HOST_WIDE_INT) (INTVAL (op) + 0x8000) < 0x10000	    || ((INTVAL (op) & 0xffff) == 0		&& (INTVAL (op) >> 31 == -1		    || INTVAL (op) >> 31 == 0)));  return register_operand (op, mode);}/* Return 1 if the operand is a valid second operand to a sign-extending   add insn.  */intsext_add_operand (op, mode)     register rtx op;     enum machine_mode mode;{  if (GET_CODE (op) == CONST_INT)    return ((unsigned HOST_WIDE_INT) INTVAL (op) < 255	    || (unsigned HOST_WIDE_INT) (- INTVAL (op)) < 255);  return register_operand (op, mode);}/* Return 1 if OP is the constant 4 or 8.  */intconst48_operand (op, mode)     register rtx op;     enum machine_mode mode;{  return (GET_CODE (op) == CONST_INT	  && (INTVAL (op) == 4 || INTVAL (op) == 8));}/* Return 1 if OP is a valid first operand to an AND insn.  */intand_operand (op, mode)     register rtx op;     enum machine_mode mode;{  if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode)    return (zap_mask (CONST_DOUBLE_LOW (op))	    && zap_mask (CONST_DOUBLE_HIGH (op)));  if (GET_CODE (op) == CONST_INT)    return ((unsigned HOST_WIDE_INT) INTVAL (op) < 0x100	    || (unsigned HOST_WIDE_INT) ~ INTVAL (op) < 0x100	    || zap_mask (INTVAL (op)));  return register_operand (op, mode);}/* Return 1 if OP is a constant that is the width, in bits, of an integral   mode smaller than DImode.  */intmode_width_operand (op, mode)     register rtx op;     enum machine_mode mode;{  return (GET_CODE (op) == CONST_INT	  && (INTVAL (op) == 8 || INTVAL (op) == 16 || INTVAL (op) == 32));}/* Return 1 if OP is a constant that is the width of an integral machine mode   smaller than an integer.  */intmode_mask_operand (op, mode)     register rtx op;     enum machine_mode mode;{#if HOST_BITS_PER_WIDE_INT == 32  if (GET_CODE (op) == CONST_DOUBLE)    return CONST_DOUBLE_HIGH (op) == 0 && CONST_DOUBLE_LOW (op) == -1;#endif  if (GET_CODE (op) == CONST_INT)    return (INTVAL (op) == 0xff	    || INTVAL (op) == 0xffff#if HOST_BITS_PER_WIDE_INT == 64	    || INTVAL (op) == 0xffffffff#endif	    );}/* Return 1 if OP is a multiple of 8 less than 64.  */intmul8_operand (op, mode)     register rtx op;     enum machine_mode mode;{  return (GET_CODE (op) == CONST_INT	  && (unsigned HOST_WIDE_INT) INTVAL (op) < 64	  && (INTVAL (op) & 7) == 0);}/* Return 1 if OP is the constant zero in floating-point.  */intfp0_operand (op, mode)     register rtx op;     enum machine_mode mode;{  return (GET_MODE (op) == mode	  && GET_MODE_CLASS (mode) == MODE_FLOAT && op == CONST0_RTX (mode));}/* Return 1 if OP is the floating-point constant zero or a register.  */intreg_or_fp0_operand (op, mode)     register rtx op;     enum machine_mode mode;{  return fp0_operand (op, mode) || register_operand (op, mode);}/* Return 1 if OP is a register or a constant integer.  */intreg_or_cint_operand (op, mode)    register rtx op;    enum machine_mode mode;{     return GET_CODE (op) == CONST_INT || register_operand (op, mode);}/* Return 1 if OP is a valid operand for the source of a move insn.  */intinput_operand (op, mode)     register rtx op;     enum machine_mode mode;{  if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))    return 0;  if (GET_MODE_CLASS (mode) == MODE_FLOAT && GET_MODE (op) != mode)    return 0;  switch (GET_CODE (op))    {    case LABEL_REF:    case SYMBOL_REF:    case CONST:      return mode == DImode;    case REG:      return 1;    case SUBREG:      if (register_operand (op, mode))	return 1;      /* ... fall through ... */    case MEM:      return mode != HImode && mode != QImode && general_operand (op, mode);    case CONST_DOUBLE:      return GET_MODE_CLASS (mode) == MODE_FLOAT && op == CONST0_RTX (mode);    case CONST_INT:      return mode == QImode || mode == HImode || add_operand (op, mode);    }  return 0;}/* Return 1 if OP is a SYMBOL_REF for the current function.  */intcurrent_function_operand (op, mode)     rtx op;     enum machine_mode mode;{  return (GET_CODE (op) == SYMBOL_REF	  && ! strcmp (XSTR (op, 0), current_function_name));}/* Return 1 if OP is a valid Alpha comparison operator.  Here we know which   comparisons are valid in which insn.  */intalpha_comparison_operator (op, mode)     register rtx op;     enum machine_mode mode;{  enum rtx_code code = GET_CODE (op);  if (mode != GET_MODE (op) || GET_RTX_CLASS (code) != '<')    return 0;  return (code == EQ || code == LE || code == LT	  || (mode == DImode && (code == LEU || code == LTU)));}/* Return 1 if OP is a signed comparison operation.  */intsigned_comparison_operator (op, mode)     register rtx op;     enum machine_mode mode;{  switch (GET_CODE (op))    {    case EQ:  case NE:  case LE:  case LT:  case GE:   case GT:      return 1;    }  return 0;}/* Return 1 if this is a divide or modulus operator.  */intdivmod_operator (op, mode)     register rtx op;     enum machine_mode mode;{  switch (GET_CODE (op))    {    case DIV:  case MOD:  case UDIV:  case UMOD:      return 1;    }  return 0;}/* Return 1 if this memory address is a known aligned register plus   a constant.  It must be a valid address.  This means that we can do   this as an aligned reference plus some offset.   Take into account what reload will do.   We could say that out-of-range stack slots are alignable, but that would   complicate get_aligned_mem and it isn't worth the trouble since few   functions have large stack space.  */intaligned_memory_operand (op, mode)     register rtx op;     enum machine_mode mode;{  if (GET_CODE (op) == SUBREG)    {      if (GET_MODE (op) != mode)	return 0;      op = SUBREG_REG (op);      mode = GET_MODE (op);    }  if (reload_in_progress && GET_CODE (op) == REG      && REGNO (op) >= FIRST_PSEUDO_REGISTER)    op = reg_equiv_mem[REGNO (op)];  if (GET_CODE (op) != MEM || GET_MODE (op) != mode      || ! memory_address_p (mode, XEXP (op, 0)))    return 0;  op = XEXP (op, 0);  if (GET_CODE (op) == PLUS)    op = XEXP (op, 0);  return (GET_CODE (op) == REG	  && (REGNO (op) == STACK_POINTER_REGNUM || op == frame_pointer_rtx	      || (REGNO (op) >= FIRST_VIRTUAL_REGISTER		  && REGNO (op) <= LAST_VIRTUAL_REGISTER)));}/* Similar, but return 1 if OP is a MEM which is not alignable.  */intunaligned_memory_operand (op, mode)     register rtx op;     enum machine_mode mode;{  if (GET_CODE (op) == SUBREG)    {      if (GET_MODE (op) != mode)	return 0;      op = SUBREG_REG (op);      mode = GET_MODE (op);    }  if (reload_in_progress && GET_CODE (op) == REG      && REGNO (op) >= FIRST_PSEUDO_REGISTER)    op = reg_equiv_mem[REGNO (op)];  if (GET_CODE (op) != MEM || GET_MODE (op) != mode)    return 0;  op = XEXP (op, 0);  if (! memory_address_p (mode, op))    return 1;  if (GET_CODE (op) == PLUS)    op = XEXP (op, 0);  return (GET_CODE (op) != REG	  || (REGNO (op) != STACK_POINTER_REGNUM && op != frame_pointer_rtx	      && (REGNO (op) < FIRST_VIRTUAL_REGISTER		  || REGNO (op) > LAST_VIRTUAL_REGISTER)));}/* Return 1 if OP is any memory location.  During reload a pseudo matches.  */intany_memory_operand (op, mode)     register rtx op;     enum machine_mode mode;{  return (GET_CODE (op) == MEM	  || (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG)	  || (reload_in_progress && GET_CODE (op) == REG	      && REGNO (op) >= FIRST_PSEUDO_REGISTER)	  || (reload_in_progress && GET_CODE (op) == SUBREG	      && GET_CODE (SUBREG_REG (op)) == REG	      && REGNO (SUBREG_REG (op)) >= FIRST_PSEUDO_REGISTER));}/* REF is an alignable memory location.  Place an aligned SImode   reference into *PALIGNED_MEM and the number of bits to shift into   *PBITNUM.  */voidget_aligned_mem (ref, paligned_mem, pbitnum)     rtx ref;     rtx *paligned_mem, *pbitnum;{  rtx base;  HOST_WIDE_INT offset = 0;  if (GET_CODE (ref) == SUBREG)    {      offset = SUBREG_WORD (ref) * UNITS_PER_WORD;      if (BYTES_BIG_ENDIAN)	offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (ref)))		   - MIN (UNITS_PER_WORD,			  GET_MODE_SIZE (GET_MODE (SUBREG_REG (ref)))));      ref = SUBREG_REG (ref);    }  if (GET_CODE (ref) == REG)    ref = reg_equiv_mem[REGNO (ref)];  if (reload_in_progress)    base = find_replacement (&XEXP (ref, 0));  else    base = XEXP (ref, 0);  if (GET_CODE (base) == PLUS)    offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0);  *paligned_mem = gen_rtx (MEM, SImode,			   plus_constant (base, offset & ~3));  MEM_IN_STRUCT_P (*paligned_mem) = MEM_IN_STRUCT_P (ref);  MEM_VOLATILE_P (*paligned_mem) = MEM_VOLATILE_P (ref);  RTX_UNCHANGING_P (*paligned_mem) = RTX_UNCHANGING_P (ref);  *pbitnum = GEN_INT ((offset & 3) * 8);}/* Similar, but just get the address.  Handle the two reload cases.  */rtxget_unaligned_address (ref)     rtx ref;{  rtx base;  HOST_WIDE_INT offset = 0;  if (GET_CODE (ref) == SUBREG)    {      offset = SUBREG_WORD (ref) * UNITS_PER_WORD;      if (BYTES_BIG_ENDIAN)	offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (ref)))		   - MIN (UNITS_PER_WORD,			  GET_MODE_SIZE (GET_MODE (SUBREG_REG (ref)))));      ref = SUBREG_REG (ref);    }  if (GET_CODE (ref) == REG)    ref = reg_equiv_mem[REGNO (ref)];  if (reload_in_progress)    base = find_replacement (&XEXP (ref, 0));  else    base = XEXP (ref, 0);  if (GET_CODE (base) == PLUS)    offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0);  return plus_constant (base, offset);}/* Subfunction of the following function.  Update the flags of any MEM   found in part of X.  */static voidalpha_set_memflags_1 (x, in_struct_p, volatile_p, unchanging_p)

⌨️ 快捷键说明

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