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

📄 ns32k.c

📁 gcc-2.95.3 Linux下最常用的C编译器
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Subroutines for assembler code output on the NS32000.   Copyright (C) 1988, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.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.  *//* Some output-actions in ns32k.md need these.  */#include "config.h"#include "system.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 "tree.h"#include "expr.h"#include "flags.h"#ifdef OSF_OSint ns32k_num_files = 0;#endif/* This duplicates reg_class_contens 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 */unsigned int ns32k_reg_class_contents[N_REG_CLASSES] = REG_CLASS_CONTENTS;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,  FP_REGS, FP_REGS, FP_REGS, FP_REGS,  FP_REGS, FP_REGS, FP_REGS, FP_REGS,  FRAME_POINTER_REG, STACK_POINTER_REG};char *ns32k_out_reg_names[] = OUTPUT_REGISTER_NAMES;voidtrace (s, s1, s2)     char *s, *s1, *s2;{  fprintf (stderr, s, s1, s2);}/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */ inthard_regno_mode_ok (regno, mode)     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;}int register_move_cost(CLASS1, CLASS2)     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. */int secondary_memory_needed(CLASS1, CLASS2, M)     enum reg_class CLASS1;     enum reg_class CLASS2;     enum machine_mode M;{  int ret = ((SUBSET_P(CLASS1, FP_REGS) && !SUBSET_P(CLASS2, FP_REGS))   || (!SUBSET_P(CLASS1, FP_REGS) && SUBSET_P(CLASS2, FP_REGS)));  return ret;}#endif    /* ADDRESS_COST calls this.  This function is not optimal   for the 32032 & 32332, but it probably is better than   the default. */intcalc_address_cost (operand)     rtx operand;{  int i;  int cost = 0;    if (GET_CODE (operand) == MEM)    cost += 3;  if (GET_CODE (operand) == MULT)    cost += 2;#if 0  if (GET_CODE (operand) == REG)    cost += 1;			/* not really, but the documentation				   says different amount of registers				   shouldn't return the same costs */#endif  switch (GET_CODE (operand))    {    case REG:    case CONST:    case CONST_INT:    case CONST_DOUBLE:    case SYMBOL_REF:    case LABEL_REF:    case POST_DEC:    case PRE_DEC:      break;    case MEM:      cost += calc_address_cost (XEXP (operand, 0));      break;    case MULT:    case PLUS:      for (i = 0; i < GET_RTX_LENGTH (GET_CODE (operand)); i++)	{	  cost += calc_address_cost (XEXP (operand, i));	}    default:      break;    }  return cost;}/* Return the register class of a scratch register needed to copy IN into   or out of a register in CLASS in MODE.  If it can be done directly,   NO_REGS is returned.  */enum reg_classsecondary_reload_class (class, mode, in)     enum reg_class class;     enum machine_mode mode;     rtx in;{  int regno = true_regnum (in);  if (regno >= FIRST_PSEUDO_REGISTER)    regno = -1;  if ((class == FRAME_POINTER_REG && regno == STACK_POINTER_REGNUM)      || ( class == STACK_POINTER_REG && regno == FRAME_POINTER_REGNUM))    return GENERAL_REGS;  else    return NO_REGS;}/* Generate the rtx that comes from an address expression in the md file *//* The expression to be build is BASE[INDEX:SCALE].  To recognize this,   scale must be converted from an exponent (from ASHIFT) to a   multiplier (for MULT). */static rtxgen_indexed_expr (base, index, scale)     rtx base, index, scale;{  rtx addr;  /* This generates an invalid addressing mode, if BASE is     fp or sp.  This is handled by PRINT_OPERAND_ADDRESS.  */  if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT)    base = gen_rtx (MEM, SImode, base);  addr = gen_rtx (MULT, SImode, index,		  GEN_INT (1 << INTVAL (scale)));  addr = gen_rtx (PLUS, SImode, base, addr);  return addr;}/* Return 1 if OP is a valid operand of mode MODE.  This   predicate rejects operands which do not have a mode   (such as CONST_INT which are VOIDmode).  */intreg_or_mem_operand (op, mode)     register rtx op;     enum machine_mode mode;{  return (GET_MODE (op) == mode	  && (GET_CODE (op) == REG	      || GET_CODE (op) == SUBREG	      || GET_CODE (op) == MEM));}/* Split one or more DImode RTL references into pairs of SImode   references.  The RTL can be REG, offsettable MEM, integer constant, or   CONST_DOUBLE.  "operands" is a pointer to an array of DImode RTL to   split and "num" is its length.  lo_half and hi_half are output arrays   that parallel "operands". */voidsplit_di (operands, num, lo_half, hi_half)     rtx operands[];     int num;     rtx lo_half[], hi_half[];{  while (num--)    {      if (GET_CODE (operands[num]) == REG)	{	  lo_half[num] = gen_rtx (REG, SImode, REGNO (operands[num]));	  hi_half[num] = gen_rtx (REG, SImode, REGNO (operands[num]) + 1);	}      else if (CONSTANT_P (operands[num]))	{	  split_double (operands[num], &lo_half[num], &hi_half[num]);	}      else if (offsettable_memref_p (operands[num]))	{	  lo_half[num] = operands[num];	  hi_half[num] = adj_offsettable_operand (operands[num], 4);	}      else	abort();    }}/* Return the best assembler insn template   for moving operands[1] into operands[0] as a fullword.  */static char *singlemove_string (operands)     rtx *operands;{  if (GET_CODE (operands[1]) == CONST_INT      && INTVAL (operands[1]) <= 7      && INTVAL (operands[1]) >= -8)    return "movqd %1,%0";  return "movd %1,%0";}char *output_move_double (operands)     rtx *operands;{  enum anon1 { REGOP, OFFSOP, PUSHOP, CNSTOP, RNDOP } optype0, optype1;  rtx latehalf[2];  /* First classify both operands.  */  if (REG_P (operands[0]))    optype0 = REGOP;  else if (offsettable_memref_p (operands[0]))    optype0 = OFFSOP;  else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)    optype0 = PUSHOP;  else    optype0 = RNDOP;  if (REG_P (operands[1]))    optype1 = REGOP;  else if (CONSTANT_P (operands[1])	   || GET_CODE (operands[1]) == CONST_DOUBLE)    optype1 = CNSTOP;  else if (offsettable_memref_p (operands[1]))    optype1 = OFFSOP;  else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)    optype1 = PUSHOP;  else    optype1 = RNDOP;  /* Check for the cases that the operand constraints are not     supposed to allow to happen.  Abort if we get one,     because generating code for these cases is painful.  */  if (optype0 == RNDOP || optype1 == RNDOP)    abort ();  /* Ok, we can do one word at a time.     Normally we do the low-numbered word first,     but if either operand is autodecrementing then we     do the high-numbered word first.     In either case, set up in LATEHALF the operands to use     for the high-numbered word and in some cases alter the     operands in OPERANDS to be suitable for the low-numbered word.  */  if (optype0 == REGOP)    latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);  else if (optype0 == OFFSOP)    latehalf[0] = adj_offsettable_operand (operands[0], 4);  else    latehalf[0] = operands[0];  if (optype1 == REGOP)    latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);  else if (optype1 == OFFSOP)    latehalf[1] = adj_offsettable_operand (operands[1], 4);  else if (optype1 == CNSTOP)    split_double (operands[1], &operands[1], &latehalf[1]);  else    latehalf[1] = operands[1];  /* If insn is effectively movd N(sp),tos then we will do the     high word first.  We should use the adjusted operand 1 (which is N+4(sp))     for the low word as well, to compensate for the first decrement of sp.     Given this, it doesn't matter which half we do "first".  */  if (optype0 == PUSHOP      && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM      && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))    operands[1] = latehalf[1];  /* If one or both operands autodecrementing,     do the two words, high-numbered first.  */  else if (optype0 == PUSHOP || optype1 == PUSHOP)    {      output_asm_insn (singlemove_string (latehalf), latehalf);      return singlemove_string (operands);    }  /* If the first move would clobber the source of the second one,     do them in the other order.  */  /* Overlapping registers.  */  if (optype0 == REGOP && optype1 == REGOP      && REGNO (operands[0]) == REGNO (latehalf[1]))    {      /* Do that word.  */      output_asm_insn (singlemove_string (latehalf), latehalf);      /* Do low-numbered word.  */      return singlemove_string (operands);    }  /* Loading into a register which overlaps a register used in the address.  */  else if (optype0 == REGOP && optype1 != REGOP	   && reg_overlap_mentioned_p (operands[0], operands[1]))    {      if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))	  && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))	{	  /* If both halves of dest are used in the src memory address,	     load the destination address into the low reg (operands[0]).	     Then it works to load latehalf first.  */	  rtx xops[2];	  xops[0] = XEXP (operands[1], 0);	  xops[1] = operands[0];	  output_asm_insn ("addr %a0,%1", xops);	  operands[1] = gen_rtx (MEM, DImode, operands[0]);	  latehalf[1] = adj_offsettable_operand (operands[1], 4);	  /* The first half has the overlap, Do the late half first.  */	  output_asm_insn (singlemove_string (latehalf), latehalf);	  /* Then clobber.  */	  return singlemove_string (operands);	}      if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)))	{	  /* The first half has the overlap, Do the late half first.  */	  output_asm_insn (singlemove_string (latehalf), latehalf);	  /* Then clobber.  */	  return singlemove_string (operands);	}    }

⌨️ 快捷键说明

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