📄 arc.md
字号:
;; Machine description of the Argonaut ARC cpu for GNU C compiler;; Copyright (C) 1994, 1997, 1998, 1999, 2000 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.;; ??? This is an old port, and is undoubtedly suffering from bit rot.;; Insn type. Used to default other attribute values.(define_attr "type" "move,load,store,cmove,unary,binary,compare,shift,mul,uncond_branch,branch,call,call_no_delay_slot,multi,misc" (const_string "binary"));; Length (in # of insns, long immediate constants counted too).;; ??? There's a nasty interaction between the conditional execution fsm;; and insn lengths: insns with shimm values cannot be conditionally executed.(define_attr "length" "" (cond [(eq_attr "type" "load") (if_then_else (match_operand 1 "long_immediate_loadstore_operand" "") (const_int 2) (const_int 1)) (eq_attr "type" "store") (if_then_else (match_operand 0 "long_immediate_loadstore_operand" "") (const_int 2) (const_int 1)) (eq_attr "type" "move,unary,compare") (if_then_else (match_operand 1 "long_immediate_operand" "") (const_int 2) (const_int 1)) (eq_attr "type" "binary,mul") (if_then_else (match_operand 2 "long_immediate_operand" "") (const_int 2) (const_int 1)) (eq_attr "type" "cmove") (if_then_else (match_operand 2 "register_operand" "") (const_int 1) (const_int 2)) (eq_attr "type" "multi") (const_int 2) ] (const_int 1)));; The length here is the length of a single asm. Unfortunately it might be;; 1 or 2 so we must allow for 2. That's ok though. How often will users;; lament asm's not being put in delay slots?(define_asm_attributes [(set_attr "length" "2") (set_attr "type" "multi")]);; Condition codes: this one is used by final_prescan_insn to speed up;; conditionalizing instructions. It saves having to scan the rtl to see if;; it uses or alters the condition codes.;; USE: This insn uses the condition codes (eg: a conditional branch).;; CANUSE: This insn can use the condition codes (for conditional execution).;; SET: All condition codes are set by this insn.;; SET_ZN: the Z and N flags are set by this insn.;; SET_ZNC: the Z, N, and C flags are set by this insn.;; CLOB: The condition codes are set to unknown values by this insn.;; NOCOND: This insn can't use and doesn't affect the condition codes.(define_attr "cond" "use,canuse,set,set_zn,set_znc,clob,nocond" (cond [(and (eq_attr "type" "unary,binary,move") (eq_attr "length" "1")) (const_string "canuse") (eq_attr "type" "compare") (const_string "set") (eq_attr "type" "cmove,branch") (const_string "use") (eq_attr "type" "multi,misc") (const_string "clob") ] (const_string "nocond")));; Delay slots.(define_attr "in_delay_slot" "false,true" (cond [(eq_attr "type" "uncond_branch,branch,call,call_no_delay_slot,multi") (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_delay_slot" "true") (eq_attr "in_delay_slot" "true") (eq_attr "in_delay_slot" "true")])(define_delay (eq_attr "type" "branch,uncond_branch") [(eq_attr "in_delay_slot" "true") (eq_attr "in_delay_slot" "true") (eq_attr "in_delay_slot" "true")]) ;; Function units of the ARC;; (define_function_unit {name} {num-units} {n-users} {test};; {ready-delay} {issue-delay} [{conflict-list}]);; 1) A conditional jump cannot immediately follow the insn setting the flags.;; This isn't a complete solution as it doesn't come with guarantees. That;; is done in the branch patterns and in arc_print_operand. This exists to;; avoid inserting a nop when we can.(define_function_unit "compare" 1 0 (eq_attr "type" "compare") 2 2 [(eq_attr "type" "branch")]);; 2) 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);; Units that take one cycle do not need to be specified.;; Move instructions.(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. */ 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,m") (match_operand:QI 1 "move_src_operand" "rI,Ji,m,r"))];; ??? Needed? "register_operand (operands[0], QImode) || register_operand (operands[1], QImode)" "@ mov%? %0,%1 mov%? %0,%1 ldb%U1%V1 %0,%1 stb%U0%V0 %1,%0" [(set_attr "type" "move,move,load,store")]);; ??? This may never match since there's no cmpqi insn.(define_insn "*movqi_set_cc_insn" [(set (reg:CCZN 61) (compare:CCZN (sign_extend:SI (match_operand:QI 1 "move_src_operand" "rIJi")) (const_int 0))) (set (match_operand:QI 0 "move_dest_operand" "=r") (match_dup 1))] "" "mov%?.f %0,%1" [(set_attr "type" "move") (set_attr "cond" "set_zn")])(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,m") (match_operand:HI 1 "move_src_operand" "rI,Ji,m,r"))] "register_operand (operands[0], HImode) || register_operand (operands[1], HImode)" "@ mov%? %0,%1 mov%? %0,%1 ldw%U1%V1 %0,%1 stw%U0%V0 %1,%0" [(set_attr "type" "move,move,load,store")]);; ??? Will this ever match?(define_insn "*movhi_set_cc_insn" [(set (reg:CCZN 61) (compare:CCZN (sign_extend:SI (match_operand:HI 1 "move_src_operand" "rIJi")) (const_int 0))) (set (match_operand:HI 0 "move_dest_operand" "=r") (match_dup 1))];; ??? Needed? "register_operand (operands[0], HImode) || register_operand (operands[1], HImode)" "mov%?.f %0,%1" [(set_attr "type" "move") (set_attr "cond" "set_zn")])(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]);}")(define_insn "*movsi_insn" [(set (match_operand:SI 0 "move_dest_operand" "=r,r,r,m") (match_operand:SI 1 "move_src_operand" "rI,GJi,m,r"))] "register_operand (operands[0], SImode) || register_operand (operands[1], SImode)" "@ mov%? %0,%1 mov%? %0,%S1 ld%U1%V1 %0,%1 st%U0%V0 %1,%0" [(set_attr "type" "move,move,load,store")])(define_insn "*movsi_set_cc_insn" [(set (reg:CCZN 61) (compare:CCZN (match_operand:SI 1 "move_src_operand" "rIJi") (const_int 0))) (set (match_operand:SI 0 "move_dest_operand" "=r") (match_dup 1))] "register_operand (operands[0], SImode) || register_operand (operands[1], SImode)" "mov%?.f %0,%S1" [(set_attr "type" "move") (set_attr "cond" "set_zn")])(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]);}")(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,HK,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 \"mov %R0,%R1\;mov %0,%1\"; else return \"mov %0,%1\;mov %R0,%R1\"; case 1 : return \"mov %0,%L1\;mov %R0,%H1\"; 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%V1 %R0,%R1\;ld%V1 %0,%1\"; else return \"ld%V1 %0,%1\;ld%V1 %R0,%R1\"; case 3 : return \"st%V0 %1,%0\;st%V0 %R1,%R0\"; default: abort(); }}" [(set_attr "type" "move,move,load,store") ;; ??? The ld/st values could be 4 if it's [reg,bignum]. (set_attr "length" "2,4,2,2")]);(define_expand "movdi"; [(set (match_operand:DI 0 "general_operand" ""); (match_operand:DI 1 "general_operand" ""))]; ""; ";{; /* Flow doesn't understand that this is effectively a DFmode move.; It doesn't know that all of `operands[0]' is set. */; emit_insn (gen_rtx_CLOBBER (VOIDmode, operands[0]));;; /* Emit insns that movsi_insn can handle. */; emit_insn (gen_movsi (operand_subword (operands[0], 0, 0, DImode),; operand_subword (operands[1], 0, 0, DImode)));; emit_insn (gen_movsi (operand_subword (operands[0], 1, 0, DImode),; operand_subword (operands[1], 1, 0, DImode)));; DONE;;}");; 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,E,m,r"))] "register_operand (operands[0], SFmode) || register_operand (operands[1], SFmode)" "@ mov%? %0,%1 mov%? %0,%1 ; %A1 ld%U1%V1 %0,%1 st%U0%V0 %1,%0" [(set_attr "type" "move,move,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]);}")(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,E,m,r"))] "register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode)" "*{ 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 \"mov %R0,%R1\;mov %0,%1\"; else return \"mov %0,%1\;mov %R0,%R1\"; case 1 : return \"mov %0,%L1\;mov %R0,%H1 ; %A1\"; 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%V1 %R0,%R1\;ld%V1 %0,%1\"; else return \"ld%V1 %0,%1\;ld%V1 %R0,%R1\"; case 3 : return \"st%V0 %1,%0\;st%V0 %R1,%R0\"; default: abort(); }}" [(set_attr "type" "move,move,load,store") ;; ??? The ld/st values could be 4 if it's [reg,bignum]. (set_attr "length" "2,4,2,2")]);(define_expand "movdf"; [(set (match_operand:DF 0 "general_operand" ""); (match_operand:DF 1 "general_operand" ""))]; ""; ";{; /* Flow doesn't understand that this is effectively a DFmode move.; It doesn't know that all of `operands[0]' is set. */; emit_insn (gen_rtx_CLOBBER (VOIDmode, operands[0]));;; /* Emit insns that movsi_insn can handle. */; emit_insn (gen_movsi (operand_subword (operands[0], 0, 0, DFmode),; operand_subword (operands[1], 0, 0, DFmode)));; emit_insn (gen_movsi (operand_subword (operands[0], 1, 0, DFmode),; operand_subword (operands[1], 1, 0, DFmode)));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -