m68hc11.c

来自「gcc3.2.1源代码」· C语言 代码 · 共 2,530 行 · 第 1/5 页

C
2,530
字号
      return x;    }  abort ();}/* Obscure register manipulation.  *//* Finds backward in the instructions to see if register 'reg' is   dead.  This is used when generating code to see if we can use 'reg'   as a scratch register.  This allows us to choose a better generation   of code when we know that some register dies or can be clobbered.  */intdead_register_here (x, reg)     rtx x;     rtx reg;{  rtx x_reg;  rtx p;  if (D_REG_P (reg))    x_reg = gen_rtx (REG, SImode, HARD_X_REGNUM);  else    x_reg = 0;  for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))    if (GET_RTX_CLASS (GET_CODE (p)) == 'i')      {	rtx body;	body = PATTERN (p);	if (GET_CODE (body) == CALL_INSN)	  break;	if (GET_CODE (body) == JUMP_INSN)	  break;	if (GET_CODE (body) == SET)	  {	    rtx dst = XEXP (body, 0);	    if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg))	      break;	    if (x_reg && rtx_equal_p (dst, x_reg))	      break;	    if (find_regno_note (p, REG_DEAD, REGNO (reg)))	      return 1;	  }	else if (reg_mentioned_p (reg, p)		 || (x_reg && reg_mentioned_p (x_reg, p)))	  break;      }  /* Scan forward to see if the register is set in some insns and never     used since then.  */  for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p))    {      rtx body;      if (GET_CODE (p) == CODE_LABEL	  || GET_CODE (p) == JUMP_INSN	  || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER)	break;      if (GET_CODE (p) != INSN)	continue;      body = PATTERN (p);      if (GET_CODE (body) == SET)	{	  rtx src = XEXP (body, 1);	  rtx dst = XEXP (body, 0);	  if (GET_CODE (dst) == REG	      && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src))	    return 1;	}      /* Register is used (may be in source or in dest).  */      if (reg_mentioned_p (reg, p)	  || (x_reg != 0 && GET_MODE (p) == SImode	      && reg_mentioned_p (x_reg, p)))	break;    }  return p == 0 ? 1 : 0;}/* Code generation operations called from machine description file.  *//* Print the name of register 'regno' in the assembly file.  */static voidasm_print_register (file, regno)     FILE *file;     int regno;{  const char *name = reg_names[regno];  if (TARGET_NO_DIRECT_MODE && name[0] == '*')    name++;  asm_fprintf (file, "%s", name);}/* A C compound statement to output to stdio stream STREAM the   assembler syntax for an instruction operand X.  X is an RTL   expression.   CODE is a value that can be used to specify one of several ways   of printing the operand.  It is used when identical operands   must be printed differently depending on the context.  CODE   comes from the `%' specification that was used to request   printing of the operand.  If the specification was just `%DIGIT'   then CODE is 0; if the specification was `%LTR DIGIT' then CODE   is the ASCII code for LTR.   If X is a register, this macro should print the register's name.   The names can be found in an array `reg_names' whose type is   `char *[]'.  `reg_names' is initialized from `REGISTER_NAMES'.   When the machine description has a specification `%PUNCT' (a `%'   followed by a punctuation character), this macro is called with   a null pointer for X and the punctuation character for CODE.   The M68HC11 specific codes are:   'b' for the low part of the operand.   'h' for the high part of the operand       The 'b' or 'h' modifiers have no effect if the operand has       the QImode and is not a S_REG_P (soft register).  If the       operand is a hard register, these two modifiers have no effect.   't' generate the temporary scratch register.  The operand is       ignored.   'T' generate the low-part temporary scratch register.  The operand is       ignored.  */voidprint_operand (file, op, letter)     FILE *file;     rtx op;     int letter;{  if (letter == 't')    {      asm_print_register (file, SOFT_TMP_REGNUM);      return;    }  else if (letter == 'T')    {      asm_print_register (file, SOFT_TMP_REGNUM);      asm_fprintf (file, "+1");      return;    }  else if (letter == '#')    {      asm_fprintf (file, "%0I");    }  if (GET_CODE (op) == REG)    {      if (letter == 'b' && S_REG_P (op))	{	  asm_print_register (file, REGNO (op));	  asm_fprintf (file, "+1");	}      else	{	  asm_print_register (file, REGNO (op));	}      return;    }  if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))    {      if (letter == 'b')	asm_fprintf (file, "%0I%%lo(");      else	asm_fprintf (file, "%0I%%hi(");      output_addr_const (file, op);      asm_fprintf (file, ")");      return;    }  /* Get the low or high part of the operand when 'b' or 'h' modifiers     are specified.  If we already have a QImode, there is nothing to do.  */  if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode)    {      if (letter == 'b')	{	  op = m68hc11_gen_lowpart (QImode, op);	}      else if (letter == 'h')	{	  op = m68hc11_gen_highpart (QImode, op);	}    }  if (GET_CODE (op) == MEM)    {      rtx base = XEXP (op, 0);      switch (GET_CODE (base))	{	case PRE_DEC:	  if (TARGET_M6812)	    {	      asm_fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));	      asm_print_register (file, REGNO (XEXP (base, 0)));	    }	  else	    abort ();	  break;	case POST_DEC:	  if (TARGET_M6812)	    {	      asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));	      asm_print_register (file, REGNO (XEXP (base, 0)));	      asm_fprintf (file, "-");	    }	  else	    abort ();	  break;	case POST_INC:	  if (TARGET_M6812)	    {	      asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));	      asm_print_register (file, REGNO (XEXP (base, 0)));	      asm_fprintf (file, "+");	    }	  else	    abort ();	  break;	case PRE_INC:	  if (TARGET_M6812)	    {	      asm_fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));	      asm_print_register (file, REGNO (XEXP (base, 0)));	    }	  else	    abort ();	  break;	default:	  output_address (base);	  break;	}    }  else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)    {      REAL_VALUE_TYPE r;      long l;      REAL_VALUE_FROM_CONST_DOUBLE (r, op);      REAL_VALUE_TO_TARGET_SINGLE (r, l);      asm_fprintf (file, "%I0x%lx", l);    }  else if (GET_CODE (op) == CONST_DOUBLE	   && (GET_MODE (op) == DFmode || GET_MODE (op) == XFmode))    {      REAL_VALUE_TYPE r;      char dstr[30];      REAL_VALUE_FROM_CONST_DOUBLE (r, op);      REAL_VALUE_TO_DECIMAL (r, "%.20g", dstr);      asm_fprintf (file, "%I0r%s", dstr);    }  else    {      int need_parenthesize = 0;      if (letter != 'i')	asm_fprintf (file, "%0I");      else        need_parenthesize = must_parenthesize (op);      if (need_parenthesize)        asm_fprintf (file, "(");      output_addr_const (file, op);      if (need_parenthesize)        asm_fprintf (file, ")");    }}/* Returns true if the operand 'op' must be printed with parenthesis   arround it.  This must be done only if there is a symbol whose name   is a processor register.  */static intmust_parenthesize (op)     rtx op;{  const char *name;  switch (GET_CODE (op))    {    case SYMBOL_REF:      name = XSTR (op, 0);      /* Avoid a conflict between symbol name and a possible         register.  */      return (strcasecmp (name, "a") == 0	      || strcasecmp (name, "b") == 0	      || strcasecmp (name, "d") == 0	      || strcasecmp (name, "x") == 0	      || strcasecmp (name, "y") == 0	      || strcasecmp (name, "ix") == 0	      || strcasecmp (name, "iy") == 0	      || strcasecmp (name, "pc") == 0	      || strcasecmp (name, "sp") == 0	      || strcasecmp (name, "ccr") == 0) ? 1 : 0;    case PLUS:    case MINUS:      return must_parenthesize (XEXP (op, 0))	|| must_parenthesize (XEXP (op, 1));    case MEM:    case CONST:    case ZERO_EXTEND:    case SIGN_EXTEND:      return must_parenthesize (XEXP (op, 0));    case CONST_DOUBLE:    case CONST_INT:    case LABEL_REF:    case CODE_LABEL:    default:      return 0;    }}/* A C compound statement to output to stdio stream STREAM the   assembler syntax for an instruction operand that is a memory   reference whose address is ADDR.  ADDR is an RTL expression.  */voidprint_operand_address (file, addr)     FILE *file;     rtx addr;{  rtx base;  rtx offset;  int need_parenthesis = 0;  switch (GET_CODE (addr))    {    case REG:      if (!REG_P (addr) || !REG_OK_FOR_BASE_STRICT_P (addr))	abort ();      asm_fprintf (file, "0,");      asm_print_register (file, REGNO (addr));      break;    case MEM:      base = XEXP (addr, 0);      switch (GET_CODE (base))	{	case PRE_DEC:	  if (TARGET_M6812)	    {	      asm_fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));	      asm_print_register (file, REGNO (XEXP (base, 0)));	    }	  else	    abort ();	  break;	case POST_DEC:	  if (TARGET_M6812)	    {	      asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));	      asm_print_register (file, REGNO (XEXP (base, 0)));	      asm_fprintf (file, "-");	    }	  else	    abort ();	  break;	case POST_INC:	  if (TARGET_M6812)	    {	      asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));	      asm_print_register (file, REGNO (XEXP (base, 0)));	      asm_fprintf (file, "+");	    }	  else	    abort ();	  break;	case PRE_INC:	  if (TARGET_M6812)	    {	      asm_fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));	      asm_print_register (file, REGNO (XEXP (base, 0)));	    }	  else	    abort ();	  break;	default:	  need_parenthesis = must_parenthesize (base);	  if (need_parenthesis)	    asm_fprintf (file, "(");	  output_addr_const (file, base);	  if (need_parenthesis)	    asm_fprintf (file, ")");	  break;	}      break;    case PLUS:      base = XEXP (addr, 0);      offset = XEXP (addr, 1);      if (!G_REG_P (base) && G_REG_P (offset))	{	  base = XEXP (addr, 1);	  offset = XEXP (addr, 0);	}      if ((CONSTANT_ADDRESS_P (base)) && (CONSTANT_ADDRESS_P (offset)))	{	  need_parenthesis = must_parenthesize (addr);	  if (need_parenthesis)	    asm_fprintf (file, "(");	  output_addr_const (file, base);	  asm_fprintf (file, "+");	  output_addr_const (file, offset);	  if (need_parenthesis)	    asm_fprintf (file, ")");	}      else if (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base))	{	  if (REG_P (offset))	    {	      if (TARGET_M6812)		{		  asm_print_register (file, REGNO (offset));		  asm_fprintf (file, ",");		  asm_print_register (file, REGNO (base));		}	      else		abort ();	    }	  else	    {              need_parenthesis = must_parenthesize (offset);              if (need_parenthesis)                asm_fprintf (file, "(");	      output_addr_const (file, offset);              if (need_parenthesis)                asm_fprintf (file, ")");	      asm_fprintf (file, ",");	      asm_print_register (file, REGNO (base));	    }	}      else	{	  abort ();	}      break;    default:      if (GET_CODE (addr) == CONST_INT	  && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000)	{	  asm_fprintf (file, "%d", INTVAL (addr));	}      else	{	  need_parenthesis = must_parenthesize (addr);	  if (need_parenthesis)	    asm_fprintf (file, "(");	  output_addr_const (file, addr);	  if (need_parenthesis)	    asm_fprintf (file, ")");	}      break;    }}/* Splitting of some instructions.  */static rtxm68hc11_expand_compare (code, op0, op1)     enum rtx_code code;     rtx op0, op1;{  rtx ret = 0;  if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)    abort ();  else    {      emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,			      gen_rtx_COMPARE (VOIDmode, op0, op1)));   

⌨️ 快捷键说明

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