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

📄 mn10300.c

📁 GCC编译器源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Subroutines for insn-output.c for Matsushita MN10300 series   Copyright (C) 1996, 1997 Free Software Foundation, Inc.   Contributed by Jeff Law (law@cygnus.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 <stdio.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 "tree.h"#include "obstack.h"/* Global registers known to hold the value zero.   Normally we'd depend on CSE and combine to put zero into a   register and re-use it.   However, on the mn10x00 processors we implicitly use the constant   zero in tst instructions, so we might be able to do better by   loading the value into a register in the prologue, then re-useing   that register throughout the function.   We could perform similar optimizations for other constants, but with   gcse due soon, it doesn't seem worth the effort.   These variables hold a rtx for a register known to hold the value   zero throughout the entire function, or NULL if no register of   the appropriate class has such a value throughout the life of the   function.  */rtx zero_dreg;rtx zero_areg;voidasm_file_start (file)     FILE *file;{  fprintf (file, "#\tGCC For the Matsushita MN10300\n");  if (optimize)    fprintf (file, "# -O%d\n", optimize);  else    fprintf (file, "\n\n");  output_file_directive (file, main_input_filename);}/* Print operand X using operand code CODE to assembly language output file   FILE.  */voidprint_operand (file, x, code)     FILE *file;     rtx x;     int code;{  switch (code)    {      case 'b':      case 'B':	/* These are normal and reversed branches.  */	switch (code == 'b' ? GET_CODE (x) : reverse_condition (GET_CODE (x)))	  {	  case NE:	    fprintf (file, "ne");	    break;	  case EQ:	    fprintf (file, "eq");	    break;	  case GE:	    fprintf (file, "ge");	    break;	  case GT:	    fprintf (file, "gt");	    break;	  case LE:	    fprintf (file, "le");	    break;	  case LT:	    fprintf (file, "lt");	    break;	  case GEU:	    fprintf (file, "cc");	    break;	  case GTU:	    fprintf (file, "hi");	    break;	  case LEU:	    fprintf (file, "ls");	    break;	  case LTU:	    fprintf (file, "cs");	    break;	  default:	    abort ();	  }	break;      case 'C':	/* This is used for the operand to a call instruction;	   if it's a REG, enclose it in parens, else output	   the operand normally.  */	if (GET_CODE (x) == REG)	  {	    fputc ('(', file);	    print_operand (file, x, 0);	    fputc (')', file);	  }	else	  print_operand (file, x, 0);	break;           /* These are the least significant word in a 64bit value.  */      case 'L':	switch (GET_CODE (x))	  {	  case MEM:	    fputc ('(', file);	    output_address (XEXP (x, 0));	    fputc (')', file);	    break;	  case REG:	    fprintf (file, "%s", reg_names[REGNO (x)]);	    break;	  case SUBREG:	    fprintf (file, "%s",		     reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)]);	    break;	  case CONST_DOUBLE:	      {		long val[2];		REAL_VALUE_TYPE rv;		switch (GET_MODE (x))		  {		    case DFmode:		      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);		      REAL_VALUE_TO_TARGET_DOUBLE (rv, val);		      print_operand_address (file, GEN_INT (val[0]));		      break;;		    case SFmode:		      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);		      REAL_VALUE_TO_TARGET_SINGLE (rv, val[0]);		      print_operand_address (file, GEN_INT (val[0]));		      break;;		    case VOIDmode:		    case DImode:		      print_operand_address (file,					     GEN_INT (CONST_DOUBLE_LOW (x)));		      break;		  }		break;	      }	  case CONST_INT:	    print_operand_address (file, x);	    break;	  default:	    abort ();	  }	break;      /* Similarly, but for the most significant word.  */      case 'H':	switch (GET_CODE (x))	  {	  case MEM:	    fputc ('(', file);	    x = adj_offsettable_operand (x, 4);	    output_address (XEXP (x, 0));	    fputc (')', file);	    break;	  case REG:	    fprintf (file, "%s", reg_names[REGNO (x) + 1]);	    break;	  case SUBREG:	    fprintf (file, "%s",		     reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)] + 1);	    break;	  case CONST_DOUBLE:	      {		long val[2];		REAL_VALUE_TYPE rv;		switch (GET_MODE (x))		  {		    case DFmode:		      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);		      REAL_VALUE_TO_TARGET_DOUBLE (rv, val);		      print_operand_address (file, GEN_INT (val[1]));		      break;;		    case SFmode:		      abort ();		    case VOIDmode:		    case DImode:		      print_operand_address (file, 					     GEN_INT (CONST_DOUBLE_HIGH (x)));		      break;		  }		break;	      }	  case CONST_INT:	    if (INTVAL (x) < 0)	      print_operand_address (file, GEN_INT (-1)); 	    else	      print_operand_address (file, GEN_INT (0));	    break;	  default:	    abort ();	  }	break;      case 'A':	fputc ('(', file);	if (GET_CODE (XEXP (x, 0)) == REG)	  output_address (gen_rtx (PLUS, SImode, XEXP (x, 0), GEN_INT (0)));	else	  output_address (XEXP (x, 0));	fputc (')', file);	break;      case 'N':	output_address (GEN_INT ((~INTVAL (x)) & 0xff));	break;      /* For shift counts.  The hardware ignores the upper bits of	 any immediate, but the assembler will flag an out of range	 shift count as an error.  So we mask off the high bits	 of the immediate here.  */      case 'S':	if (GET_CODE (x) == CONST_INT)	  {	    fprintf (file, "%d", INTVAL (x) & 0x1f);	    break;	  }	/* FALL THROUGH */      default:	switch (GET_CODE (x))	  {	  case MEM:	    fputc ('(', file);	    output_address (XEXP (x, 0));	    fputc (')', file);	    break;	  case PLUS:	    output_address (x);	    break;	  case REG:	    fprintf (file, "%s", reg_names[REGNO (x)]);	    break;	  case SUBREG:	    fprintf (file, "%s",		     reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)]);	    break;	  /* This will only be single precision....  */	  case CONST_DOUBLE:	    {	      unsigned long val;	      REAL_VALUE_TYPE rv;	      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);	      REAL_VALUE_TO_TARGET_SINGLE (rv, val);	      print_operand_address (file, GEN_INT (val));	      break;	    }	  case CONST_INT:	  case SYMBOL_REF:	  case CONST:	  case LABEL_REF:	  case CODE_LABEL:	    print_operand_address (file, x);	    break;	  default:	    abort ();	  }	break;   }}/* Output assembly language output for the address ADDR to FILE.  */voidprint_operand_address (file, addr)     FILE *file;     rtx addr;{  switch (GET_CODE (addr))    {    case REG:      if (addr == stack_pointer_rtx)	print_operand_address (file, gen_rtx (PLUS, SImode,					      stack_pointer_rtx,					      GEN_INT (0)));      else	print_operand (file, addr, 0);      break;    case PLUS:      {	rtx base, index;	if (REG_P (XEXP (addr, 0))	    && REG_OK_FOR_BASE_P (XEXP (addr, 0)))	  base = XEXP (addr, 0), index = XEXP (addr, 1);	else if (REG_P (XEXP (addr, 1))	    && REG_OK_FOR_BASE_P (XEXP (addr, 1)))	  base = XEXP (addr, 1), index = XEXP (addr, 0);      	else	  abort ();	print_operand (file, index, 0);	fputc (',', file);	print_operand (file, base, 0);;	break;      }    case SYMBOL_REF:      output_addr_const (file, addr);      break;    default:      output_addr_const (file, addr);      break;    }}intcan_use_return_insn (){  /* size includes the fixed stack space needed for function calls.  */  int size = get_frame_size () + current_function_outgoing_args_size;  /* And space for the return pointer.  */  size += current_function_outgoing_args_size ? 4 : 0;  return (reload_completed	  && size == 0	  && !regs_ever_live[2]	  && !regs_ever_live[3]	  && !regs_ever_live[6]	  && !regs_ever_live[7]	  && !frame_pointer_needed);}/* Count the number of tst insns which compare a data or address   register with zero.  */static void count_tst_insns (dreg_countp, areg_countp)     int *dreg_countp;     int *areg_countp;{  rtx insn;  /* Assume no tst insns exist.  */  *dreg_countp = 0;  *areg_countp = 0;  /* If not optimizing, then quit now.  */  if (!optimize)    return;  /* Walk through all the insns.  */  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))    {      rtx pat;      /* Ignore anything that is not a normal INSN.  */      if (GET_CODE (insn) != INSN)	continue;      /* Ignore anything that isn't a SET.  */      pat = PATTERN (insn);      if (GET_CODE (pat) != SET)	continue;      /* Check for a tst insn.  */      if (SET_DEST (pat) == cc0_rtx	  && GET_CODE (SET_SRC (pat)) == REG)	{	  if (REGNO_REG_CLASS (REGNO (SET_SRC (pat))) == DATA_REGS)	    (*dreg_countp)++;    	  if (REGNO_REG_CLASS (REGNO (SET_SRC (pat))) == ADDRESS_REGS)	    (*areg_countp)++;	}      /* Setting an address register to zero can also be optimized,	 so count it just like a tst insn.  */      if (GET_CODE (SET_DEST (pat)) == REG	  && GET_CODE (SET_SRC (pat)) == CONST_INT	  && INTVAL (SET_SRC (pat)) == 0	  && REGNO_REG_CLASS (REGNO (SET_DEST (pat))) == ADDRESS_REGS)	(*areg_countp)++;    }}voidexpand_prologue (){  unsigned int size;  /* We need to end the current sequence so that count_tst_insns can     look at all the insns in this function.  Normally this would be     unsafe, but it's OK in the prologue/epilogue expanders.  */  end_sequence ();  /* Determine if it is profitable to put the value zero into a register     for the entire function.  If so, set ZERO_DREG and ZERO_AREG.  */  if (regs_ever_live[2] || regs_ever_live[3]       || regs_ever_live[6] || regs_ever_live[7]       || frame_pointer_needed)    {      int dreg_count, areg_count;      /* Get a count of the number of tst insns which use address and	 data registers.  */      count_tst_insns (&dreg_count, &areg_count);      /* If there's more than one tst insn using a data register, then	 this optimization is a win.  */      if (dreg_count > 1	  && (!regs_ever_live[2] || !regs_ever_live[3]))	{ 	  if (!regs_ever_live[2])	    {	      regs_ever_live[2] = 1;	      zero_dreg = gen_rtx (REG, SImode, 2);	    }	  else	    {	      regs_ever_live[3] = 1;	      zero_dreg = gen_rtx (REG, SImode, 3);	    }	}      else	zero_dreg = NULL_RTX;      /* If there's more than two tst insns using an address register,	 then this optimization is a win.  */      if (areg_count > 2	  && (!regs_ever_live[6] || !regs_ever_live[7]))	{ 	  if (!regs_ever_live[6])	    {	      regs_ever_live[6] = 1;	      zero_areg = gen_rtx (REG, SImode, 6);	    }	  else	    {	      regs_ever_live[7] = 1;	      zero_areg = gen_rtx (REG, SImode, 7);	    }	}      else	zero_areg = NULL_RTX;    }  else    {      zero_dreg = NULL_RTX;      zero_areg = NULL_RTX;    }  /* Start a new sequence.  */  start_sequence ();  /* SIZE includes the fixed stack space needed for function calls.  */  size = get_frame_size () + current_function_outgoing_args_size;  size += (current_function_outgoing_args_size ? 4 : 0);  /* If this is an old-style varargs function, then its arguments     need to be flushed back to the stack.  */  if (current_function_varargs)    {      emit_move_insn (gen_rtx (MEM, SImode,			       gen_rtx (PLUS, Pmode, stack_pointer_rtx,					GEN_INT (4))),		      gen_rtx (REG, SImode, 0));      emit_move_insn (gen_rtx (MEM, SImode,			       gen_rtx (PLUS, Pmode, stack_pointer_rtx,					GEN_INT (8))),		      gen_rtx (REG, SImode, 1));    }  /* And now store all the registers onto the stack with a     single two byte instruction.  */  if (regs_ever_live[2] || regs_ever_live[3]      || regs_ever_live[6] || regs_ever_live[7]      || frame_pointer_needed)    emit_insn (gen_store_movm ());  /* Now put the frame pointer into the frame pointer register.  */  if (frame_pointer_needed)    emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);  /* Allocate stack for this frame.  */  if (size)    emit_insn (gen_addsi3 (stack_pointer_rtx,			   stack_pointer_rtx,			   GEN_INT (-size)));  /* Load zeros into registers as needed.  */

⌨️ 快捷键说明

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