m32r.md

来自「GCC编译器源代码」· Markdown 代码 · 共 1,470 行 · 第 1/3 页

MD
1,470
字号
;; Machine description of the Mitsubishi M32R cpu for GNU C compiler;; Copyright (C) 1996, 1997 Free Software Foundation, Inc.;; This file is part of GNU CC.;; GNU CC is free software; you can redistribute it and/or modify;; it under the terms of the GNU General Public License as published by;; the 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 of;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the;; GNU General Public License for more details.;; You should have received a copy of the GNU General Public License;; along with GNU CC; see the file COPYING.  If not, write to;; the Free Software Foundation, 59 Temple Place - Suite 330,;; Boston, MA 02111-1307, USA.;; See file "rtl.def" for documentation on define_insn, match_*, et. al.;; unspec usage;; 0 - blockage;; 1 - flush_icache;; 2 - load_sda_base;; Insn type.  Used to default other attribute values.;; move4 = 4 byte move(define_attr "type"  "move,move4,load,store,unary,binary,compare,shift,mul,div,uncond_branch,branch,call,multi,misc"  (const_string "misc"));; Length in bytes.(define_attr "length" ""  (cond [(eq_attr "type" "move,unary,shift,mul,div")	 (const_int 2)	 (eq_attr "type" "binary")	 (if_then_else (match_operand 2 "register_operand" "")		       (const_int 2) (const_int 4))	 (eq_attr "type" "compare")	 (if_then_else (match_operand 1 "register_operand" "")		       (const_int 2) (const_int 4))	 (eq_attr "type" "load")	 (if_then_else (match_operand 1 "memreg_operand" "")		       (const_int 2) (const_int 4))	 (eq_attr "type" "store")	 (if_then_else (match_operand 0 "memreg_operand" "")		       (const_int 2) (const_int 4))	 (eq_attr "type" "multi")	 (const_int 8)	 (eq_attr "type" "uncond_branch,branch,call")	 (const_int 4)]	 (const_int 4)));; The length here is the length of a single asm.  Unfortunately it might be;; 2 or 4 so we must allow for 4.  That's ok though.(define_asm_attributes  [(set_attr "length" "4")   (set_attr "type" "multi")]);; Function units of the M32R;; Units that take one cycle do not need to be specified.;; (define_function_unit {name} {num-units} {n-users} {test};;                       {ready-delay} {issue-delay} [{conflict-list}]);; References to loaded registers should wait a cycle.;; Memory with load-delay of 1 (i.e. 2 cycle load).(define_function_unit "memory" 1 1 (eq_attr "type" "load") 2 0);; Hack to get GCC to better pack the instructions.;; We pretend there is a separate long function unit that conflicts with;; both the left and right 16 bit insn slots.(define_function_unit "left" 1 1  (eq_attr "length" "2")  1 0  [(not (eq_attr "length" "2"))])(define_function_unit "right" 1 1  (eq_attr "length" "1")  1 0  [(not (eq_attr "length" "2"))])(define_function_unit "long" 1 1  (not (eq_attr "length" "2"))  1 0  [(eq_attr "length" "2")]);; Expand prologue as RTL;; ??? Unfinished.;(define_expand "prologue";  [(const_int 1)];  "";  ";{;}");; Move instructions.;;;; For QI and HI moves, the register must contain the full properly;; sign-extended value.  nonzero_bits assumes this [otherwise;; SHORT_IMMEDIATES_SIGN_EXTEND must be used, but the comment for it;; says it's a kludge and the .md files should be fixed instead].(define_expand "movqi"  [(set (match_operand:QI 0 "general_operand" "")	(match_operand:QI 1 "general_operand" ""))]  ""  "{  /* Everything except mem = const or mem = mem can be done easily.     Objects in the small data area are handled too.  */  if (GET_CODE (operands[0]) == MEM)    operands[1] = force_reg (QImode, operands[1]);}")(define_insn "*movqi_insn"  [(set (match_operand:QI 0 "move_dest_operand" "=r,r,r,r,m")	(match_operand:QI 1 "move_src_operand" "r,I,JQR,m,r"))]  "register_operand (operands[0], QImode) || register_operand (operands[1], QImode)"  "@   mv %0,%1   ldi %0,%#%1   ldi %0,%#%1   ldub %0,%1   stb %1,%0"  [(set_attr "type" "move,move,move4,load,store")])(define_expand "movhi"  [(set (match_operand:HI 0 "general_operand" "")	(match_operand:HI 1 "general_operand" ""))]  ""  "{  /* Everything except mem = const or mem = mem can be done easily.  */  if (GET_CODE (operands[0]) == MEM)    operands[1] = force_reg (HImode, operands[1]);}")(define_insn "*movhi_insn"  [(set (match_operand:HI 0 "move_dest_operand" "=r,r,r,r,r,m")	(match_operand:HI 1 "move_src_operand" "r,I,JQR,K,m,r"))]  "register_operand (operands[0], HImode) || register_operand (operands[1], HImode)"  "@   mv %0,%1   ldi %0,%#%1   ldi %0,%#%1   ld24 %0,%#%1   lduh %0,%1   sth %1,%0"  [(set_attr "type" "move,move,move4,move4,load,store")])(define_expand "movsi"  [(set (match_operand:SI 0 "general_operand" "")	(match_operand:SI 1 "general_operand" ""))]  ""  "{  /* Everything except mem = const or mem = mem can be done easily.  */  if (GET_CODE (operands[0]) == MEM)    operands[1] = force_reg (SImode, operands[1]);  /* Small Data Area reference?  */  if (small_data_operand (operands[1], SImode))    {      emit_insn (gen_movsi_sda (operands[0], operands[1]));      DONE;    }  /* If medium or large code model, symbols have to be loaded with     seth/add3.  */  if (addr32_operand (operands[1], SImode))    {      emit_insn (gen_movsi_addr32 (operands[0], operands[1]));      DONE;    }}")(define_insn "*movsi_insn"  [(set (match_operand:SI 0 "move_dest_operand" "=r,r,r,r,r,r,r,m");; ??? Do we need a const_double constraint here for large unsigned values?	(match_operand:SI 1 "move_src_operand" "r,I,J,MQ,L,N,m,r"))]  "register_operand (operands[0], SImode) || register_operand (operands[1], SImode)"  "@   mv %0,%1   ldi %0,%#%1 ; %X1   ldi %0,%#%1 ; %X1   ld24 %0,%#%1 ; %X1   seth %0,%#%T1   seth %0,%#%T1\;or3 %0,%0,%#%B1   ld %0,%1   st %1,%0"  [(set_attr "type" "move,move,move4,move4,move4,multi,load,store")]); Try to use a four byte / two byte pair for constants not loadable with; ldi, ld24, seth.(define_split [(set (match_operand:SI 0 "register_operand" "")       (match_operand:SI 1 "two_insn_const_operand" ""))]  ""  [(set (match_dup 0) (match_dup 2))   (set (match_dup 0) (ior:SI (match_dup 0) (match_dup 3)))]  "{  unsigned HOST_WIDE_INT val = INTVAL (operands[1]);  unsigned HOST_WIDE_INT tmp;  int shift;  /* In all cases we will emit two instructions.  However we try to     use 2 byte instructions wherever possible.  We can assume the     constant isn't loadable with any of ldi, ld24, or seth.  */  /* See if we can load a 24 bit unsigned value and invert it.  */  if (UINT24_P (~ val))    {      emit_insn (gen_movsi (operands[0], GEN_INT (~ val)));      emit_insn (gen_one_cmplsi2 (operands[0], operands[0]));      DONE;    }  /* See if we can load a 24 bit unsigned value and shift it into place.     0x01fffffe is just beyond ld24's range.  */  for (shift = 1, tmp = 0x01fffffe;       shift < 8;       ++shift, tmp <<= 1)    {      if ((val & ~tmp) == 0)	{	  emit_insn (gen_movsi (operands[0], GEN_INT (val >> shift)));	  emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (shift)));	  DONE;	}    }  /* Can't use any two byte insn, fall back to seth/or3.  */  operands[2] = GEN_INT ((val) & 0xffff0000);  operands[3] = GEN_INT ((val) & 0xffff);}");; Small data area support.;; The address of _SDA_BASE_ is loaded into a register and all objects in;; the small data area are indexed off that.  This is done for each reference;; but cse will clean things up for us.  We let the compiler choose the;; register to use so we needn't allocate (and maybe even fix) a special;; register to use.  Since the load and store insns have a 16 bit offset the;; total size of the data area can be 64K.  However, if the data area lives;; above 16M (24 bits), _SDA_BASE_ will have to be loaded with seth/add3 which;; would then yield 3 instructions to reference an object [though there would;; be no net loss if two or more objects were referenced].  The 3 insns can be;; reduced back to 2 if the size of the small data area were reduced to 32K;; [then seth + ld/st would work for any object in the area].  Doing this;; would require special handling of _SDA_BASE_ (its value would be;; (.sdata + 32K) & 0xffff0000) and reloc computations would be different;; [I think].  What to do about this is deferred until later and for now we;; require .sdata to be in the first 16M.(define_expand "movsi_sda"  [(set (match_dup 2)	(unspec [(const_int 0)] 2))   (set (match_operand:SI 0 "register_operand" "")	(lo_sum:SI (match_dup 2)		   (match_operand:SI 1 "small_data_operand" "")))]  ""  "{  if (reload_in_progress || reload_completed)    operands[2] = operands[0];  else    operands[2] = gen_reg_rtx (SImode);}")(define_insn "*load_sda_base"  [(set (match_operand:SI 0 "register_operand" "=r")	(unspec [(const_int 0)] 2))]  ""  "ld24 %0,#_SDA_BASE_"  [(set_attr "type" "move4")]);; 32 bit address support.(define_expand "movsi_addr32"  [(set (match_dup 2)	; addr32_operand isn't used because it's too restrictive,	; seth_add3_operand is more general and thus safer.	(high:SI (match_operand:SI 1 "seth_add3_operand" "")))   (set (match_operand:SI 0 "register_operand" "")	(lo_sum:SI (match_dup 2) (match_dup 1)))]  ""  "{  if (reload_in_progress || reload_completed)    operands[2] = operands[0];  else    operands[2] = gen_reg_rtx (SImode);}")(define_insn "set_hi_si"  [(set (match_operand:SI 0 "register_operand" "=r")	(high:SI (match_operand 1 "symbolic_operand" "")))]  ""  "seth %0,%#shigh(%1)"  [(set_attr "type" "move4")])(define_insn "lo_sum_si"  [(set (match_operand:SI 0 "register_operand" "=r")	(lo_sum:SI (match_operand:SI 1 "register_operand" "r")		   (match_operand:SI 2 "immediate_operand" "in")))]  ""  "add3 %0,%1,%#%B2"  [(set_attr "length" "4")])(define_expand "movdi"  [(set (match_operand:DI 0 "general_operand" "")	(match_operand:DI 1 "general_operand" ""))]  ""  "{  /* Everything except mem = const or mem = mem can be done easily.  */  if (GET_CODE (operands[0]) == MEM)    operands[1] = force_reg (DImode, operands[1]);  if (CONSTANT_P (operands[1])      && ! easy_di_const (operands[1]))    {      rtx mem = force_const_mem (DImode, operands[1]);      rtx reg = ((reload_in_progress || reload_completed)		 ? copy_to_suggested_reg (XEXP (mem, 0),					  gen_rtx (REG, Pmode, REGNO (operands[0])),					  Pmode)		 : force_reg (Pmode, XEXP (mem, 0)));      operands[1] = change_address (mem, DImode, reg);    }}")(define_insn "*movdi_insn"  [(set (match_operand:DI 0 "move_dest_operand" "=r,r,r,m")	(match_operand:DI 1 "move_double_src_operand" "r,nG,m,r"))]  "register_operand (operands[0], DImode) || register_operand (operands[1], DImode)"  "*{  switch (which_alternative)    {    case 0 :      /* We normally copy the low-numbered register first.  However, if	 the first register operand 0 is the same as the second register of	 operand 1, we must copy in the opposite order.  */      if (REGNO (operands[0]) == REGNO (operands[1]) + 1)	return \"mv %R0,%R1\;mv %0,%1\";      else	return \"mv %0,%1\;mv %R0,%R1\";    case 1 :      return \"#\";    case 2 :      /* If the low-address word is used in the address, we must load it	 last.  Otherwise, load it first.  Note that we cannot have	 auto-increment in that case since the address register is known to be	 dead.  */      if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1,			     operands [1], 0))	{	  return \"ld %R0,%R1\;ld %0,%1\";	}      else	{	  /* Try to use auto-inc addressing if we can.  */	  if (GET_CODE (XEXP (operands[1], 0)) == REG	      && dead_or_set_p (insn, XEXP (operands[1], 0)))	    {	      operands[1] = XEXP (operands[1], 0);	      return \"ld %0,@%1+\;ld %R0,@%1\";	    }	  return \"ld %0,%1\;ld %R0,%R1\";	}    case 3 :      /* Try to use auto-inc addressing if we can.  */      if (GET_CODE (XEXP (operands[0], 0)) == REG	  && dead_or_set_p (insn, XEXP (operands[0], 0)))	{	  operands[0] = XEXP (operands[0], 0);	  return \"st %1,@%0\;st %R1,@+%0\";	}      return \"st %1,%0\;st %R1,%R0\";    }}"  [(set_attr "type" "multi,multi,multi,multi")   (set_attr "length" "4,4,6,6")])(define_split  [(set (match_operand:DI 0 "register_operand" "")	(match_operand:DI 1 "const_double_operand" ""))]  "reload_completed"  [(set (match_dup 2) (match_dup 4))   (set (match_dup 3) (match_dup 5))]  "{  operands[2] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0);  operands[3] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0);  split_double (operands[1], operands + 4, operands + 5);}");; Floating point move insns.(define_expand "movsf"  [(set (match_operand:SF 0 "general_operand" "")	(match_operand:SF 1 "general_operand" ""))]  ""  "{  /* Everything except mem = const or mem = mem can be done easily.  */  if (GET_CODE (operands[0]) == MEM)    operands[1] = force_reg (SFmode, operands[1]);}")(define_insn "*movsf_insn"  [(set (match_operand:SF 0 "move_dest_operand" "=r,r,r,m")	(match_operand:SF 1 "move_src_operand" "r,F,m,r"))]  "register_operand (operands[0], SFmode) || register_operand (operands[1], SFmode)"  "*{  switch (which_alternative)    {    case 0 :      return \"mv %0,%1\";    case 1 :      {	REAL_VALUE_TYPE r;	long l;	REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);	REAL_VALUE_TO_TARGET_SINGLE (r, l);	operands[1] = GEN_INT (l);	if (l == 0)	  return \"ldi %0,%#0\";	if ((l & 0xffff) == 0)	  return \"seth %0,%#%T1\";	else	  return \"seth %0,%#%T1\;or3 %0,%0,%#%B1\";      }    case 2 :      return \"ld %0,%1\";    case 3 :      return \"st %1,%0\";    }}"  ;; ??? Length of alternative 1 is either 2, 4 or 8.  [(set_attr "type" "move,multi,load,store")])(define_expand "movdf"  [(set (match_operand:DF 0 "general_operand" "")	(match_operand:DF 1 "general_operand" ""))]  ""  "{  /* Everything except mem = const or mem = mem can be done easily.  */  if (GET_CODE (operands[0]) == MEM)    operands[1] = force_reg (DFmode, operands[1]);  if (GET_CODE (operands[1]) == CONST_DOUBLE      && ! easy_df_const (operands[1]))    {      rtx mem = force_const_mem (DFmode, operands[1]);      rtx reg = ((reload_in_progress || reload_completed)		 ? copy_to_suggested_reg (XEXP (mem, 0),					  gen_rtx (REG, Pmode, REGNO (operands[0])),					  Pmode)		 : force_reg (Pmode, XEXP (mem, 0)));      operands[1] = change_address (mem, DFmode, reg);    }}")(define_insn "*movdf_insn"  [(set (match_operand:DF 0 "move_dest_operand" "=r,r,r,m")	(match_operand:DF 1 "move_double_src_operand" "r,H,m,r"))]  "register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode)"

⌨️ 快捷键说明

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