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 + -
显示快捷键?