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

📄 sparc.c

📁 gcc库的原代码,对编程有很大帮助.
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Subroutines for insn-output.c for Sun SPARC.   Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.   Contributed by Michael Tiemann (tiemann@cygnus.com)   64 bit SPARC V9 support by Michael Tiemann, Jim Wilson, and Doug Evans,   at Cygnus Support.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 <stdio.h>#include "config.h"#include "tree.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 "expr.h"#include "recog.h"/* 1 if the caller has placed an "unimp" insn immediately after the call.   This is used in v8 code when calling a function that returns a structure.   v9 doesn't have this.  */#define SKIP_CALLERS_UNIMP_P (!TARGET_V9 && current_function_returns_struct)/* Global variables for machine-dependent things.  *//* Says what architecture we're compiling for.  */enum arch_type sparc_arch_type;/* Size of frame.  Need to know this to emit return insns from leaf procedures.   ACTUAL_FSIZE is set by compute_frame_size() which is called during the   reload pass.  This is important as the value is later used in insn   scheduling (to see what can go in a delay slot).   APPARENT_FSIZE is the size of the stack less the register save area and less   the outgoing argument area.  It is used when saving call preserved regs.  */static int apparent_fsize;static int actual_fsize;/* Save the operands last given to a compare for use when we   generate a scc or bcc insn.  */rtx sparc_compare_op0, sparc_compare_op1;/* Count of named arguments (v9 only).   ??? INIT_CUMULATIVE_ARGS initializes these, and FUNCTION_ARG_ADVANCE   increments SPARC_ARG_COUNT. They are then used by   FUNCTION_ARG_CALLEE_COPIES to determine if the argument is really a named   argument or not.  This hack is necessary because the NAMED argument to the   FUNCTION_ARG_XXX macros is not what it says it is: it does not include the   last named argument.  */int sparc_arg_count;int sparc_n_named_args;/* We may need an epilogue if we spill too many registers.   If this is non-zero, then we branch here for the epilogue.  */static rtx leaf_label;#ifdef LEAF_REGISTERS/* Vector to say how input registers are mapped to output   registers.  FRAME_POINTER_REGNUM cannot be remapped by   this function to eliminate it.  You must use -fomit-frame-pointer   to get that.  */char leaf_reg_remap[] ={ 0, 1, 2, 3, 4, 5, 6, 7,  -1, -1, -1, -1, -1, -1, 14, -1,  -1, -1, -1, -1, -1, -1, -1, -1,  8, 9, 10, 11, 12, 13, -1, 15,  32, 33, 34, 35, 36, 37, 38, 39,  40, 41, 42, 43, 44, 45, 46, 47,  48, 49, 50, 51, 52, 53, 54, 55,  56, 57, 58, 59, 60, 61, 62, 63,  64, 65, 66, 67, 68, 69, 70, 71,  72, 73, 74, 75, 76, 77, 78, 79,  80, 81, 82, 83, 84, 85, 86, 87,  88, 89, 90, 91, 92, 93, 94, 95,  96, 97, 98, 99};#endif/* Name of where we pretend to think the frame pointer points.   Normally, this is "%fp", but if we are in a leaf procedure,   this is "%sp+something".  We record "something" separately as it may be   too big for reg+constant addressing.  */static char *frame_base_name;static int frame_base_offset;static rtx find_addr_reg ();static void sparc_init_modes ();/* Option handling.  *//* Validate and override various options, and do some machine dependent   initialization.  */voidsparc_override_options (){  /* Check for any conflicts in the choice of options.  */  /* ??? This stuff isn't really usable yet.  */  if (! TARGET_V9)    {      if (target_flags & MASK_CODE_MODEL)	error ("code model support is only available with -mv9");      if (TARGET_INT64)	error ("-mint64 is only available with -mv9");      if (TARGET_LONG64)	error ("-mlong64 is only available with -mv9");      if (TARGET_PTR64)	error ("-mptr64 is only available with -mv9");      if (TARGET_ENV32)	error ("-menv32 is only available with -mv9");      if (TARGET_STACK_BIAS)	error ("-mstack-bias is only available with -mv9");    }  else    {      /* ??? Are there any options that aren't usable with v9.	 -munaligned-doubles?  */    }  /* Check for conflicts in cpu specification.     If we use -mcpu=xxx, this can be removed.  */  if ((TARGET_V8 != 0) + (TARGET_SPARCLITE != 0) + (TARGET_V9 != 0) > 1)    error ("conflicting architectures defined");  /* Do various machine dependent initializations.  */  sparc_init_modes ();}/* Float conversions (v9 only).   The floating point registers cannot hold DImode values because SUBREG's   on them get the wrong register.   "(subreg:SI (reg:DI M int-reg) 0)" is the   same as "(subreg:SI (reg:DI N float-reg) 1)", but gcc doesn't know how to   turn the "0" to a "1".  Therefore, we must explicitly do the conversions   to/from int/fp regs.  `sparc64_fpconv_stack_slot' is the address of an   8 byte stack slot used during the transfer.   ??? I could have used [%fp-16] but I didn't want to add yet another   dependence on this.  *//* ??? Can we use assign_stack_temp here?  */static rtx fpconv_stack_temp;/* Called once for each function.  */voidsparc64_init_expanders (){  fpconv_stack_temp = NULL_RTX;}/* Assign a stack temp for fp/int DImode conversions.  */rtxsparc64_fpconv_stack_temp (){  if (fpconv_stack_temp == NULL_RTX)      fpconv_stack_temp =	assign_stack_local (DImode, GET_MODE_SIZE (DImode), 0);    return fpconv_stack_temp;}/* Miscellaneous utilities.  *//* Nonzero if CODE, a comparison, is suitable for use in v9 conditional move   or branch on register contents instructions.  */intv9_regcmp_p (code)     enum rtx_code code;{  return (code == EQ || code == NE || code == GE || code == LT	  || code == LE || code == GT);}/* Operand constraints.  *//* Return non-zero only if OP is a register of mode MODE,   or const0_rtx.  */intreg_or_0_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (op == const0_rtx || register_operand (op, mode))    return 1;  if (GET_MODE (op) == VOIDmode && GET_CODE (op) == CONST_DOUBLE      && CONST_DOUBLE_HIGH (op) == 0      && CONST_DOUBLE_LOW (op) == 0)    return 1;  if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT      && GET_CODE (op) == CONST_DOUBLE      && fp_zero_operand (op))    return 1;  return 0;}/* Nonzero if OP is a floating point value with value 0.0.  */intfp_zero_operand (op)     rtx op;{  REAL_VALUE_TYPE r;  REAL_VALUE_FROM_CONST_DOUBLE (r, op);  return REAL_VALUES_EQUAL (r, dconst0);}/* Nonzero if OP is an integer register.  */intintreg_operand (op, mode)     rtx op;     enum machine_mode mode;{  return (register_operand (op, SImode)	  || (TARGET_V9 && register_operand (op, DImode)));}/* Nonzero if OP is a floating point condition code register.  */intccfp_reg_operand (op, mode)     rtx op;     enum machine_mode mode;{  /* This can happen when recog is called from combine.  Op may be a MEM.     Fail instead of calling abort in this case.  */  if (GET_CODE (op) != REG || REGNO (op) == 0)    return 0;  if (GET_MODE (op) != mode)    return 0;#if 0	/* ??? ==> 1 when %fcc1-3 are pseudos first.  See gen_compare_reg().  */  if (reg_renumber == 0)    return REGNO (op) >= FIRST_PSEUDO_REGISTER;  return REGNO_OK_FOR_CCFP_P (REGNO (op));#else  return (unsigned) REGNO (op) - 96 < 4;#endif}/* Nonzero if OP can appear as the dest of a RESTORE insn.  */intrestore_operand (op, mode)     rtx op;     enum machine_mode mode;{  return (GET_CODE (op) == REG && GET_MODE (op) == mode	  && (REGNO (op) < 8 || (REGNO (op) >= 24 && REGNO (op) < 32)));}/* Call insn on SPARC can take a PC-relative constant address, or any regular   memory address.  */intcall_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (GET_CODE (op) != MEM)    abort ();  op = XEXP (op, 0);  return (symbolic_operand (op, mode) || memory_address_p (Pmode, op));}intcall_operand_address (op, mode)     rtx op;     enum machine_mode mode;{  return (symbolic_operand (op, mode) || memory_address_p (Pmode, op));}/* Returns 1 if OP is either a symbol reference or a sum of a symbol   reference and a constant.  */intsymbolic_operand (op, mode)     register rtx op;     enum machine_mode mode;{  switch (GET_CODE (op))    {    case SYMBOL_REF:    case LABEL_REF:      return 1;    case CONST:      op = XEXP (op, 0);      return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF	       || GET_CODE (XEXP (op, 0)) == LABEL_REF)	      && GET_CODE (XEXP (op, 1)) == CONST_INT);      /* ??? This clause seems to be irrelevant.  */    case CONST_DOUBLE:      return GET_MODE (op) == mode;    default:      return 0;    }}/* Return truth value of statement that OP is a symbolic memory   operand of mode MODE.  */intsymbolic_memory_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (GET_CODE (op) == SUBREG)    op = SUBREG_REG (op);  if (GET_CODE (op) != MEM)    return 0;  op = XEXP (op, 0);  return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST	  || GET_CODE (op) == HIGH || GET_CODE (op) == LABEL_REF);}/* Return 1 if the operand is a data segment reference.  This includes   the readonly data segment, or in other words anything but the text segment.   This is needed in the medium/anywhere code model on v9.  These values   are accessed with MEDANY_BASE_REG.  */intdata_segment_operand (op, mode)     rtx op;     enum machine_mode mode;{  switch (GET_CODE (op))    {    case SYMBOL_REF :      return ! SYMBOL_REF_FLAG (op);    case PLUS :      /* Assume canonical format of symbol + constant.  */    case CONST :      return data_segment_operand (XEXP (op, 0));    default :      return 0;    }}/* Return 1 if the operand is a text segment reference.   This is needed in the medium/anywhere code model on v9.  */inttext_segment_operand (op, mode)     rtx op;     enum machine_mode mode;{  switch (GET_CODE (op))    {    case LABEL_REF :      return 1;    case SYMBOL_REF :      return SYMBOL_REF_FLAG (op);    case PLUS :      /* Assume canonical format of symbol + constant.  */    case CONST :      return text_segment_operand (XEXP (op, 0));    default :      return 0;    }}/* Return 1 if the operand is either a register or a memory operand that is   not symbolic.  */intreg_or_nonsymb_mem_operand (op, mode)    register rtx op;    enum machine_mode mode;{  if (register_operand (op, mode))    return 1;  if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode))    return 1;  return 0;}intsparc_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (register_operand (op, mode))    return 1;  if (GET_CODE (op) == CONST_INT)    return SMALL_INT (op);  if (GET_MODE (op) != mode)    return 0;  if (GET_CODE (op) == SUBREG)    op = SUBREG_REG (op);  if (GET_CODE (op) != MEM)    return 0;  op = XEXP (op, 0);  if (GET_CODE (op) == LO_SUM)    return (GET_CODE (XEXP (op, 0)) == REG	    && symbolic_operand (XEXP (op, 1), Pmode));  return memory_address_p (mode, op);}intmove_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (mode == DImode && arith_double_operand (op, mode))    return 1;  if (register_operand (op, mode))    return 1;  if (GET_CODE (op) == CONST_INT)    return (SMALL_INT (op) || (INTVAL (op) & 0x3ff) == 0);  if (GET_MODE (op) != mode)    return 0;  if (GET_CODE (op) == SUBREG)    op = SUBREG_REG (op);  if (GET_CODE (op) != MEM)    return 0;  op = XEXP (op, 0);  if (GET_CODE (op) == LO_SUM)    return (register_operand (XEXP (op, 0), Pmode)	    && CONSTANT_P (XEXP (op, 1)));  return memory_address_p (mode, op);}

⌨️ 快捷键说明

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