📄 romp.md
字号:
;;- Machine description for ROMP chip for GNU C compiler;; Copyright (C) 1988, 1991, 1993, 1994, 1995, 1998, 1999, 2000;; Free Software Foundation, Inc.;; Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu);; 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.;; Define the attributes for the ROMP.;; Insn type. Used to default other attribute values.(define_attr "type" "branch,ibranch,return,fp,load,loadz,store,call,address,arith,compare,multi,misc" (const_string "arith"));; Length in bytes.(define_attr "length" "" (cond [(eq_attr "type" "branch") (if_then_else (and (ge (minus (pc) (match_dup 0)) (const_int -256)) (le (minus (pc) (match_dup 0)) (const_int 254))) (const_int 2) (const_int 4)) (eq_attr "type" "return,ibranch") (const_int 2) (eq_attr "type" "fp") (const_int 10) (eq_attr "type" "call") (const_int 4) (eq_attr "type" "load") (cond [(match_operand 1 "short_memory_operand" "") (const_int 2) (match_operand 1 "symbolic_memory_operand" "") (const_int 8)] (const_int 4)) (eq_attr "type" "loadz") (cond [(match_operand 1 "zero_memory_operand" "") (const_int 2) (match_operand 1 "symbolic_memory_operand" "") (const_int 8)] (const_string "4")) (eq_attr "type" "store") (cond [(match_operand 0 "short_memory_operand" "") (const_int 2) (match_operand 0 "symbolic_memory_operand" "") (const_int 8)] (const_int 4))] (const_int 4)));; Whether insn can be placed in a delay slot.(define_attr "in_delay_slot" "yes,no" (cond [(eq_attr "length" "8,10,38") (const_string "no") (eq_attr "type" "branch,ibranch,return,call,multi") (const_string "no")] (const_string "yes")));; Whether insn needs a delay slot. We have to say that two-byte;; branches do not need a delay slot. Otherwise, branch shortening will;; try to do something with delay slot insns (we want it to on the PA).;; This is a kludge, which should be cleaned up at some point.(define_attr "needs_delay_slot" "yes,no" (if_then_else (ior (and (eq_attr "type" "branch") (eq_attr "length" "4")) (eq_attr "type" "ibranch,return,call")) (const_string "yes") (const_string "no")));; What insn does to the condition code.(define_attr "cc" "clobber,none,sets,change0,copy1to0,compare,tbit" (cond [(eq_attr "type" "load,loadz") (const_string "change0") (eq_attr "type" "store") (const_string "none") (eq_attr "type" "fp,call") (const_string "clobber") (eq_attr "type" "branch,ibranch,return") (const_string "none") (eq_attr "type" "address") (const_string "change0") (eq_attr "type" "compare") (const_string "compare") (eq_attr "type" "arith") (const_string "sets")] (const_string "clobber")));; Define attributes for `asm' insns.(define_asm_attributes [(set_attr "type" "misc") (set_attr "length" "8") (set_attr "in_delay_slot" "no") (set_attr "cc" "clobber")]);; Define the delay slot requirements for branches and calls. We don't have;; any annulled insns.;;(define_delay (eq_attr "needs_delay_slot" "yes") [(eq_attr "in_delay_slot" "yes") (nil) (nil)]);; We cannot give a floating-point comparison a delay slot, even though it;; could make use of it. This is because it would confuse next_cc0_user;; to do so. Other fp insns can't get a delay slow because they set their;; result and use their input after the delay slot insn is executed. This;; isn't what reorg.c expects. ;; Define load & store delays. These were obtained by measurements done by;; jfc@athena.mit.edu.;;;; In general, the memory unit can support at most two simultaneous operations.;;;; Loads take 5 cycles to return the data and can be pipelined up to the;; limit of two simultaneous operations.(define_function_unit "memory" 1 2 (eq_attr "type" "load,loadz") 5 0);; Stores do not return data, but tie up the memory unit for 2 cycles if the;; next insn is also a store.(define_function_unit "memory" 1 2 (eq_attr "type" "store") 1 2 [(eq_attr "type" "store")]);; Move word instructions.;;;; If destination is memory but source is not register, force source to;; register.;;;; If source is a constant that is too large to load in a single insn, build;; it in two pieces.;;;; If destination is memory and source is a register, a temporary register;; will be needed. In that case, make a PARALLEL of the SET and a;; CLOBBER of a SCRATCH to allocate the required temporary.;;;; This temporary is ACTUALLY only needed when the destination is a;; relocatable expression. For generating RTL, however, we always;; place the CLOBBER. In insns where it is not needed, the SCRATCH will;; not be allocated to a register.;;;; Also, avoid creating pseudo-registers or SCRATCH rtx's during reload as;; they will not be correctly handled. We never need pseudos for that;; case anyway.;;;; We do not use DEFINE_SPLIT for loading constants because the number;; of cases in the resulting unsplit insn would be too high to deal;; with practically.(define_expand "movsi" [(set (match_operand:SI 0 "general_operand" "") (match_operand:SI 1 "general_operand" ""))] "" "{ rtx op0 = operands[0]; rtx op1 = operands[1]; if (GET_CODE (op1) == REG && REGNO (op1) == 16) DONE; if (GET_CODE (op0) == REG && REGNO (op0) == 16) DONE; if (GET_CODE (op0) == MEM && ! reload_in_progress) { emit_insn (gen_storesi (operands[0], force_reg (SImode, operands[1]))); DONE; } else if (GET_CODE (op1) == CONST_INT) { int const_val = INTVAL (op1); /* Try a number of cases to see how to best load the constant. */ if ((const_val & 0xffff) == 0 || (const_val & 0xffff0000) == 0 || (unsigned) (const_val + 0x8000) < 0x10000) /* Can do this in one insn, so generate it. */ ; else if (((- const_val) & 0xffff) == 0 || ((- const_val) & 0xffff0000) == 0 || (unsigned) ((- const_val) + 0x8000) < 0x10000) { /* Can do this by loading the negative constant and then negating. */ emit_move_insn (operands[0], GEN_INT (- const_val)); emit_insn (gen_negsi2 (operands[0], operands[0])); DONE; } else /* Do this the long way. */ { unsigned int high_part = const_val & 0xffff0000; unsigned int low_part = const_val & 0xffff; int i; if (low_part >= 0x10 && exact_log2 (low_part) >= 0) i = high_part, high_part = low_part, low_part = i; emit_move_insn (operands[0], GEN_INT (low_part)); emit_insn (gen_iorsi3 (operands[0], operands[0], GEN_INT (high_part))); DONE; } }}");; Move from a symbolic memory location to a register is special. In this;; case, we know in advance that the register cannot be r0, so we can improve;; register allocation by treating it separately.(define_insn "" [(set (match_operand:SI 0 "register_operand" "=b") (match_operand:SI 1 "symbolic_memory_operand" "m"))] "" "load %0,%1" [(set_attr "type" "load")]);; Generic single-word move insn. We avoid the case where the destination is;; a symbolic address, as that needs a temporary register.(define_insn "" [(set (match_operand:SI 0 "reg_or_nonsymb_mem_operand" "=r,r,r,r,r,r,r,r,b,Q") (match_operand:SI 1 "romp_operand" "rR,I,K,L,M,S,s,Q,m,r"))] "register_operand (operands[0], SImode) || register_operand (operands[1], SImode)" "@ cas %0,%1,r0 lis %0,%1 cal %0,%1(r0) cal16 %0,%1(r0) cau %0,%H1(r0) ail %0,r14,%C1 get %0,$%1 l%M1 %0,%1 load %0,%1 st%M0 %1,%0" [(set_attr "type" "address,address,address,address,address,arith,misc,load,load,store") (set_attr "length" "2,2,4,4,4,4,8,*,*,*")])(define_insn "storesi" [(set (match_operand:SI 0 "memory_operand" "=Q,m") (match_operand:SI 1 "register_operand" "r,r")) (clobber (match_scratch:SI 2 "=X,&b"))] "" "@ st%M0 %1,%0 store %1,%0,%2" [(set_attr "type" "store")]);; This pattern is used by reload when we store into a symbolic address. It;; provides the temporary register required. This pattern is only used;; when SECONDARY_OUTPUT_RELOAD_CLASS returns something other than;; NO_REGS, so we need not have any predicates here.(define_expand "reload_outsi" [(parallel [(set (match_operand:SI 0 "symbolic_memory_operand" "=m") (match_operand:SI 1 "" "r")) (clobber (match_operand:SI 2 "" "=&b"))])] "" "");; Now do the same for the QI move instructions.(define_expand "movqi" [(set (match_operand:QI 0 "general_operand" "") (match_operand:QI 1 "general_operand" ""))] "" "{ rtx op0 = operands[0]; if (GET_CODE (op0) == MEM && ! reload_in_progress) { emit_insn (gen_storeqi (operands[0], force_reg (QImode, operands[1]))); DONE; }}")(define_insn "" [(set (match_operand:QI 0 "register_operand" "=b") (match_operand:QI 1 "symbolic_memory_operand" "m"))] "" "loadc %0,%1" [(set_attr "type" "load")])(define_insn "" [(set (match_operand:QI 0 "reg_or_nonsymb_mem_operand" "=r,r,r,r,r,b,Q") (match_operand:QI 1 "romp_operand" "r,I,n,s,Q,m,r"))] "register_operand (operands[0], QImode) || register_operand (operands[1], QImode)" "@ cas %0,%1,r0 lis %0,%1 cal %0,%L1(r0) get %0,$%1 lc%M1 %0,%1 loadc %0,%1 stc%M0 %1,%0" [(set_attr "type" "address,address,address,misc,load,load,store") (set_attr "length" "2,2,4,8,*,*,*")])(define_insn "storeqi" [(set (match_operand:QI 0 "memory_operand" "=Q,m") (match_operand:QI 1 "register_operand" "r,r")) (clobber (match_scratch:SI 2 "=X,&b"))] "" "@ stc%M0 %1,%0 storec %1,%0,%2" [(set_attr "type" "store")])(define_expand "reload_outqi" [(parallel [(set (match_operand:QI 0 "symbolic_memory_operand" "=m") (match_operand:QI 1 "" "r")) (clobber (match_operand:SI 2 "" "=&b"))])] "" "");; Finally, the HI instructions.(define_expand "movhi" [(set (match_operand:HI 0 "general_operand" "") (match_operand:HI 1 "general_operand" ""))] "" "{ rtx op0 = operands[0]; if (GET_CODE (op0) == MEM && ! reload_in_progress) { emit_insn (gen_storehi (operands[0], force_reg (HImode, operands[1]))); DONE; }}")(define_insn "" [(set (match_operand:HI 0 "register_operand" "=b") (match_operand:HI 1 "symbolic_memory_operand" "m"))] "" "loadha %0,%1" [(set_attr "type" "load")]);; use cal16 instead of cal for constant source because combine requires;; the high bits of the register to be 0 after a HImode load of a constant(define_insn "" [(set (match_operand:HI 0 "reg_or_nonsymb_mem_operand" "=r,r,r,r,r,b,Q") (match_operand:HI 1 "romp_operand" "r,I,n,s,Q,m,r"))] "register_operand (operands[0], HImode) || register_operand (operands[1], HImode)" "@ cas %0,%1,r0 lis %0,%1 cal16 %0,%L1(r0) get %0,$%1 lh%N1 %0,%1 loadh %0,%1 sth%M0 %1,%0" [(set_attr "type" "address,address,address,misc,loadz,loadz,store") (set_attr "length" "2,2,4,8,*,*,*")])(define_insn "storehi" [(set (match_operand:HI 0 "memory_operand" "=Q,m") (match_operand:HI 1 "register_operand" "r,r")) (clobber (match_scratch:SI 2 "=X,&b"))] "" "@ sth%M0 %1,%0 storeh %1,%0,%2" [(set_attr "type" "store")])(define_expand "reload_outhi" [(parallel [(set (match_operand:HI 0 "symbolic_memory_operand" "=m") (match_operand:HI 1 "" "r")) (clobber (match_operand:SI 2 "" "=&b"))])] "" "");; For DI move, if we have a constant, break the operation apart into;; two SImode moves because the optimizer may be able to do a better job;; with the resulting code.;;;; For memory stores, make the required pseudo for a temporary in case we;; are storing into an absolute address.;;;; We need to be careful about the cases where the output is a register that is;; the second register of the input.(define_expand "movdi" [(set (match_operand:DI 0 "general_operand" "") (match_operand:DI 1 "general_operand" ""))] "" "{ rtx op0 = operands[0]; rtx op1 = operands[1]; if (CONSTANT_P (op1)) { rtx insns; start_sequence (); emit_move_insn (operand_subword (op0, 0, 1, DImode), operand_subword (op1, 0, 1, DImode)); emit_move_insn (operand_subword (op0, 1, 1, DImode), operand_subword (op1, 1, 1, DImode)); insns = get_insns (); end_sequence (); emit_no_conflict_block (insns, op0, op1, 0, op1); DONE; } if (GET_CODE (op0) == MEM && ! reload_in_progress) { emit_insn (gen_storedi (operands[0], force_reg (DImode, operands[1]))); DONE; }}")(define_insn "" [(set (match_operand:DI 0 "reg_or_nonsymb_mem_operand" "=r,r,r,Q") (match_operand:DI 1 "reg_or_mem_operand" "r,Q,m,r"))] "register_operand (operands[0], DImode) || register_operand (operands[1], DImode)"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -