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

📄 sparc.md

📁 早期freebsd实现
💻 MD
📖 第 1 页 / 共 5 页
字号:
;;- Machine description for SPARC chip for GNU C compiler;;   Copyright (C) 1987, 1988, 1989, 1992 Free Software Foundation, Inc.;;   Contributed by Michael Tiemann (tiemann@cygnus.com);; 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, 675 Mass Ave, Cambridge, MA 02139, USA.;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.;; Insn type.  Used to default other attribute values.;; type "unary" insns have one input operand (1) and one output operand (0);; type "binary" insns have two input operands (1,2) and one output (0);; type "compare" insns have one or two input operands (0,1) and no output;; type "call_no_delay_slot" is a call followed by an unimp instruction.(define_attr "type"  "move,unary,binary,compare,load,store,uncond_branch,branch,call,call_no_delay_slot,address,fpload,fpstore,fp,fpcmp,fpmul,fpdiv,fpsqrt,multi,misc"  (const_string "binary"));; Set true if insn uses call-clobbered intermediate register.(define_attr "use_clobbered" "false,true"  (if_then_else (and (eq_attr "type" "address")		     (match_operand 0 "clobbered_register" ""))	 	(const_string "true")		(const_string "false")));; Length (in # of insns).(define_attr "length" ""  (cond [(eq_attr "type" "load,fpload")	 (if_then_else (match_operand 1 "symbolic_memory_operand" "")		       (const_int 2) (const_int 1))	 (eq_attr "type" "store,fpstore")	 (if_then_else (match_operand 0 "symbolic_memory_operand" "")		       (const_int 2) (const_int 1))	 (eq_attr "type" "address") (const_int 2)	 (eq_attr "type" "binary")	 (if_then_else (ior (match_operand 2 "arith_operand" "")			    (match_operand 2 "arith_double_operand" ""))		       (const_int 1) (const_int 3))	 (eq_attr "type" "multi") (const_int 2)	 (eq_attr "type" "move,unary")	 (if_then_else (ior (match_operand 1 "arith_operand" "")			    (match_operand 1 "arith_double_operand" ""))		       (const_int 1) (const_int 2))]	(const_int 1)))(define_asm_attributes  [(set_attr "length" "1")   (set_attr "type" "multi")]);; Attributes for instruction and branch scheduling(define_attr "in_call_delay" "false,true"  (cond [(eq_attr "type" "uncond_branch,branch,call,call_no_delay_slot,multi")	 	(const_string "false")	 (eq_attr "type" "load,fpload,store,fpstore")	 	(if_then_else (eq_attr "length" "1")			      (const_string "true")			      (const_string "false"))	 (eq_attr "type" "address")	 	(if_then_else (eq_attr "use_clobbered" "false")			      (const_string "true")			      (const_string "false"))]	(if_then_else (eq_attr "length" "1")		      (const_string "true")		      (const_string "false"))))(define_delay (eq_attr "type" "call")  [(eq_attr "in_call_delay" "true") (nil) (nil)]);; ??? Should implement the notion of predelay slots for floating point;; branches.  This would allow us to remove the nop always inserted before;; a floating point branch.;; ??? It is OK for fill_simple_delay_slots to put load/store instructions;; in a delay slot, but it is not OK for fill_eager_delay_slots to do so.;; This is because doing so will add several pipeline stalls to the path;; that the load/store did not come from.  Unfortunately, there is no way;; to prevent fill_eager_delay_slots from using load/store without completely;; disabling them.  For the SPEC benchmark set, this is a serious lose,;; because it prevents us from moving back the final store of inner loops.(define_attr "in_branch_delay" "false,true"  (if_then_else (and (eq_attr "type" "!uncond_branch,branch,call,call_no_delay_slot,multi")		     (eq_attr "length" "1"))		(const_string "true")		(const_string "false")))(define_attr "in_uncond_branch_delay" "false,true"  (if_then_else (and (eq_attr "type" "!uncond_branch,branch,call,call_no_delay_slot,multi")		     (eq_attr "length" "1"))		(const_string "true")		(const_string "false")))(define_attr "in_annul_branch_delay" "false,true"  (if_then_else (and (eq_attr "type" "!uncond_branch,branch,call,call_no_delay_slot,multi")		     (eq_attr "length" "1"))		(const_string "true")		(const_string "false")))(define_delay (eq_attr "type" "branch")  [(eq_attr "in_branch_delay" "true")   (nil) (eq_attr "in_annul_branch_delay" "true")])(define_delay (eq_attr "type" "uncond_branch")  [(eq_attr "in_uncond_branch_delay" "true")   (nil) (nil)])   ;; Function units of the SPARC;; (define_function_unit {name} {num-units} {n-users} {test};;                       {ready-delay} {issue-delay} [{conflict-list}]);; The integer ALU.;; (Noted only for documentation; units that take one cycle do not need to;; be specified.);; (define_function_unit "alu" 1 0;;  (eq_attr "type" "unary,binary,move,address") 1 0);; Memory with load-delay of 1 (i.e., 2 cycle load).(define_function_unit "memory" 1 1 (eq_attr "type" "load,fpload") 2 0);; SPARC has two floating-point units: the FP ALU,;; and the FP MUL/DIV/SQRT unit.;; Instruction timings on the CY7C602 are as follows;; FABSs	4;; FADDs/d	5/5;; FCMPs/d	4/4;; FDIVs/d	23/37;; FMOVs	4;; FMULs/d	5/7;; FNEGs	4;; FSQRTs/d	34/63;; FSUBs/d	5/5;; FdTOi/s	5/5;; FsTOi/d	5/5;; FiTOs/d	9/5;; The CY7C602 can only support 2 fp isnsn simultaneously.;; More insns cause the chip to stall.(define_function_unit "fp_alu" 1 1 (eq_attr "type" "fp") 5 0)(define_function_unit "fp_mds" 1 1 (eq_attr "type" "fpmul") 7 0)(define_function_unit "fp_mds" 1 1 (eq_attr "type" "fpdiv") 37 0)(define_function_unit "fp_mds" 1 1 (eq_attr "type" "fpsqrt") 63 0);; Compare instructions.;; This controls RTL generation and register allocation.;; We generate RTL for comparisons and branches by having the cmpxx ;; patterns store away the operands.  Then, the scc and bcc patterns;; emit RTL for both the compare and the branch.;;;; We do this because we want to generate different code for an sne and;; seq insn.  In those cases, if the second operand of the compare is not;; const0_rtx, we want to compute the xor of the two operands and test;; it against zero.;;;; We start with the DEFINE_EXPANDs, then then DEFINE_INSNs to match;; the patterns.  Finally, we have the DEFINE_SPLITs for some of the scc;; insns that actually require more than one machine instruction.;; Put cmpsi first among compare insns so it matches two CONST_INT operands.(define_expand "cmpsi"  [(set (reg:CC 0)	(compare:CC (match_operand:SI 0 "register_operand" "")		    (match_operand:SI 1 "arith_operand" "")))]  ""  "{  sparc_compare_op0 = operands[0];  sparc_compare_op1 = operands[1];  DONE;}")(define_expand "cmpsf"  [(set (reg:CCFP 0)	(compare:CCFP (match_operand:SF 0 "register_operand" "")		      (match_operand:SF 1 "register_operand" "")))]  ""  "{  sparc_compare_op0 = operands[0];  sparc_compare_op1 = operands[1];  DONE;}")(define_expand "cmpdf"  [(set (reg:CCFP 0)	(compare:CCFP (match_operand:DF 0 "register_operand" "")		      (match_operand:DF 1 "register_operand" "")))]  ""  "{  sparc_compare_op0 = operands[0];  sparc_compare_op1 = operands[1];  DONE;}")(define_expand "cmptf"  [(set (reg:CCFP 0)	(compare:CCFP (match_operand:TF 0 "register_operand" "")		      (match_operand:TF 1 "register_operand" "")))]  ""  "{  sparc_compare_op0 = operands[0];  sparc_compare_op1 = operands[1];  DONE;}");; Next come the scc insns.  For seq, sne, sgeu, and sltu, we can do this;; without jumps using the addx/subx instructions.  For the rest, we do;; branches.  Seq_special and sne_special clobber the CC reg, because they;; generate addcc/subcc instructions.(define_expand "seq_special"  [(set (match_dup 3) (xor:SI (match_operand:SI 1 "register_operand" "")			      (match_operand:SI 2 "register_operand" "")))   (parallel [(set (match_operand:SI 0 "register_operand" "")		   (eq:SI (match_dup 3) (const_int 0)))	      (clobber (reg:CC 0))])]	       ""  "{ operands[3] = gen_reg_rtx (SImode); }")(define_expand "sne_special"  [(set (match_dup 3) (xor:SI (match_operand:SI 1 "register_operand" "")			      (match_operand:SI 2 "register_operand" "")))   (parallel [(set (match_operand:SI 0 "register_operand" "")		   (ne:SI (match_dup 3) (const_int 0)))	      (clobber (reg:CC 0))])]  ""  "{ operands[3] = gen_reg_rtx (SImode); }")(define_expand "seq"  [(set (match_operand:SI 0 "register_operand" "")	(eq:SI (match_dup 1) (const_int 0)))]  ""  "{ if (GET_MODE (sparc_compare_op0) == SImode)    {      emit_insn (gen_seq_special (operands[0], sparc_compare_op0,				  sparc_compare_op1));      DONE;    }  else    operands[1] = gen_compare_reg (EQ, sparc_compare_op0, sparc_compare_op1);}")(define_expand "sne"  [(set (match_operand:SI 0 "register_operand" "")	(ne:SI (match_dup 1) (const_int 0)))]  ""  "{ if (GET_MODE (sparc_compare_op0) == SImode)    {      emit_insn (gen_sne_special (operands[0], sparc_compare_op0,				  sparc_compare_op1));      DONE;    }  else    operands[1] = gen_compare_reg (NE, sparc_compare_op0, sparc_compare_op1);}")(define_expand "sgt"  [(set (match_operand:SI 0 "register_operand" "")	(gt:SI (match_dup 1) (const_int 0)))]  ""  "{ operands[1] = gen_compare_reg (GT, sparc_compare_op0, sparc_compare_op1); }")(define_expand "slt"  [(set (match_operand:SI 0 "register_operand" "")	(lt:SI (match_dup 1) (const_int 0)))]  ""  "{ operands[1] = gen_compare_reg (LT, sparc_compare_op0, sparc_compare_op1); }")(define_expand "sge"  [(set (match_operand:SI 0 "register_operand" "")	(ge:SI (match_dup 1) (const_int 0)))]  ""  "{ operands[1] = gen_compare_reg (GE, sparc_compare_op0, sparc_compare_op1); }")(define_expand "sle"  [(set (match_operand:SI 0 "register_operand" "")	(le:SI (match_dup 1) (const_int 0)))]  ""  "{ operands[1] = gen_compare_reg (LE, sparc_compare_op0, sparc_compare_op1); }")(define_expand "sgtu"  [(set (match_operand:SI 0 "register_operand" "")	(gtu:SI (match_dup 1) (const_int 0)))]  ""  "{  rtx tem;  /* We can do ltu easily, so if both operands are registers, swap them and     do a LTU.  */  if ((GET_CODE (sparc_compare_op0) == REG       || GET_CODE (sparc_compare_op0) == SUBREG)      && (GET_CODE (sparc_compare_op1) == REG	  || GET_CODE (sparc_compare_op1) == SUBREG))    {      tem = sparc_compare_op0;      sparc_compare_op0 = sparc_compare_op1;      sparc_compare_op1 = tem;      emit_insn (gen_sltu (operands[0]));      DONE;    }  operands[1] = gen_compare_reg (LEU, sparc_compare_op0, sparc_compare_op1);}")(define_expand "sltu"  [(set (match_operand:SI 0 "register_operand" "")	(ltu:SI (match_dup 1) (const_int 0)))]  ""  "{ operands[1] = gen_compare_reg (LTU, sparc_compare_op0, sparc_compare_op1);}")(define_expand "sgeu"  [(set (match_operand:SI 0 "register_operand" "")	(geu:SI (match_dup 1) (const_int 0)))]  ""  "{ operands[1] = gen_compare_reg (GEU, sparc_compare_op0, sparc_compare_op1);}")(define_expand "sleu"  [(set (match_operand:SI 0 "register_operand" "")	(leu:SI (match_dup 1) (const_int 0)))]  ""  "{  rtx tem;  /* We can do geu easily, so if both operands are registers, swap them and     do a GEU.  */  if ((GET_CODE (sparc_compare_op0) == REG       || GET_CODE (sparc_compare_op0) == SUBREG)      && (GET_CODE (sparc_compare_op1) == REG	  || GET_CODE (sparc_compare_op1) == SUBREG))    {      tem = sparc_compare_op0;      sparc_compare_op0 = sparc_compare_op1;      sparc_compare_op1 = tem;      emit_insn (gen_sgeu (operands[0]));      DONE;    }  operands[1] = gen_compare_reg (LEU, sparc_compare_op0, sparc_compare_op1);}");; Now the DEFINE_INSNs for the compare and scc cases.  First the compares.(define_insn ""  [(set (reg:CC 0)	(compare:CC (match_operand:SI 0 "register_operand" "r")		    (match_operand:SI 1 "arith_operand" "rI")))]  ""  "cmp %r0,%1"  [(set_attr "type" "compare")])(define_insn ""  [(set (reg:CCFPE 0)	(compare:CCFPE (match_operand:DF 0 "register_operand" "f")		       (match_operand:DF 1 "register_operand" "f")))]  ""  "fcmped %0,%1"  [(set_attr "type" "fpcmp")])(define_insn ""  [(set (reg:CCFPE 0)	(compare:CCFPE (match_operand:SF 0 "register_operand" "f")		       (match_operand:SF 1 "register_operand" "f")))]  ""  "fcmpes %0,%1"  [(set_attr "type" "fpcmp")])(define_insn ""  [(set (reg:CCFPE 0)	(compare:CCFPE (match_operand:TF 0 "register_operand" "f")		       (match_operand:TF 1 "register_operand" "f")))]  ""  "fcmpeq %0,%1"  [(set_attr "type" "fpcmp")])(define_insn ""  [(set (reg:CCFP 0)	(compare:CCFP (match_operand:DF 0 "register_operand" "f")		      (match_operand:DF 1 "register_operand" "f")))]  ""  "fcmpd %0,%1"  [(set_attr "type" "fpcmp")])(define_insn ""  [(set (reg:CCFP 0)	(compare:CCFP (match_operand:SF 0 "register_operand" "f")		      (match_operand:SF 1 "register_operand" "f")))]  ""  "fcmps %0,%1"  [(set_attr "type" "fpcmp")])(define_insn ""  [(set (reg:CCFP 0)	(compare:CCFP (match_operand:TF 0 "register_operand" "f")		      (match_operand:TF 1 "register_operand" "f")))]  ""  "fcmpq %0,%1"  [(set_attr "type" "fpcmp")]);; The SEQ and SNE patterns are special because they can be done;; without any branching and do not involve a COMPARE.(define_insn ""  [(set (match_operand:SI 0 "register_operand" "=r")

⌨️ 快捷键说明

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