📄 arm.md
字号:
;;- Machine description for ARM for GNU compiler;; Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000;; Free Software Foundation, Inc.;; Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl);; and Martin Simmons (@harleqn.co.uk).;; More major hacks by Richard Earnshaw (rearnsha@arm.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, 59 Temple Place - Suite 330,;; Boston, MA 02111-1307, USA.;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.;; There are patterns in this file to support XFmode arithmetic.;; Unfortunately RISC iX doesn't work well with these so they are disabled.;; (See arm.h);; UNSPEC Usage:;; 0 `sin' operation: operand 0 is the result, operand 1 the parameter,;; the mode is MODE_FLOAT;; 1 `cos' operation: operand 0 is the result, operand 1 the parameter,;; the mode is MODE_FLOAT;; 2 `push multiple' operation: operand 0 is the first register. Subsequent;; registers are in parallel (use...) expressions.;; 3 A symbol that has been treated properly for pic usage, that is, we;; will add the pic_register value to it before trying to dereference it.;; Note: sin and cos are no-longer used.;; Attributes; PROG_MODE attribute is used to determine whether condition codes are; clobbered by a call insn: they are if in prog32 mode. This is controlled; by the -mapcs-{32,26} flag, and possibly the -mcpu=... option.(define_attr "prog_mode" "prog26,prog32" (const (symbol_ref "arm_prog_mode")))(define_attr "is_strongarm" "no,yes" (const (symbol_ref "arm_is_strong"))); Floating Point Unit. If we only have floating point emulation, then there; is no point in scheduling the floating point insns. (Well, for best; performance we should try and group them together).(define_attr "fpu" "fpa,fpe2,fpe3" (const (symbol_ref "arm_fpu_attr"))); LENGTH of an instruction (in bytes)(define_attr "length" "" (const_int 4)); An assembler sequence may clobber the condition codes without us knowing(define_asm_attributes [(set_attr "conds" "clob") (set_attr "length" "4")]); TYPE attribute is used to detect floating point instructions which, if; running on a co-processor can run in parallel with other, basic instructions; If write-buffer scheduling is enabled then it can also be used in the; scheduling of writes.; Classification of each insn; normal any data instruction that doesn't hit memory or fp regs; mult a multiply instruction; block blockage insn, this blocks all functional units; float a floating point arithmetic operation (subject to expansion); fdivx XFmode floating point division; fdivd DFmode floating point division; fdivs SFmode floating point division; fmul Floating point multiply; ffmul Fast floating point multiply; farith Floating point arithmetic (4 cycle); ffarith Fast floating point arithmetic (2 cycle); float_em a floating point arithmetic operation that is normally emulated; even on a machine with an fpa.; f_load a floating point load from memory; f_store a floating point store to memory; f_mem_r a transfer of a floating point register to a real reg via mem; r_mem_f the reverse of f_mem_r; f_2_r fast transfer float to arm (no memory needed); r_2_f fast transfer arm to float; call a subroutine call; load any load from memory; store1 store 1 word to memory from arm registers; store2 store 2 words; store3 store 3 words; store4 store 4 words;(define_attr "type" "normal,mult,block,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith,float_em,f_load,f_store,f_mem_r,r_mem_f,f_2_r,r_2_f,call,load,store1,store2,store3,store4" (const_string "normal")); Load scheduling, set from the arm_ld_sched variable; initialised by arm_override_options() (define_attr "ldsched" "no,yes" (const (symbol_ref "arm_ld_sched"))); 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 means that the condition codes are used by the insn in the process of; outputting code, this means (at present) that we can't use the insn in; inlined branches; SET means that the purpose of the insn is to set the condition codes in a; well defined manner.; CLOB means that the condition codes are altered in an undefined manner, if; they are altered at all; JUMP_CLOB is used when the conditions are not defined if a branch is taken,; but are if the branch wasn't taken; the effect is to limit the branch; elimination scanning.; NOCOND means that the condition codes are neither altered nor affect the; output of this insn(define_attr "conds" "use,set,clob,jump_clob,nocond" (if_then_else (eq_attr "type" "call") (if_then_else (eq_attr "prog_mode" "prog32") (const_string "clob") (const_string "nocond")) (const_string "nocond"))); Only model the write buffer for ARM6 and ARM7. Earlier processors don't; have one. Later ones, such as StrongARM, have write-back caches, so don't; suffer blockages enough to warrent modelling this (and it can adversely; affect the schedule).(define_attr "model_wbuf" "no,yes" (const (symbol_ref "arm_is_6_or_7")))(define_attr "write_conflict" "no,yes" (if_then_else (eq_attr "type" "block,float_em,f_load,f_store,f_mem_r,r_mem_f,call,load") (const_string "yes") (const_string "no")))(define_attr "core_cycles" "single,multi" (if_then_else (eq_attr "type" "normal,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith") (const_string "single") (const_string "multi"))); The write buffer on some of the arm6 processors is hard to model exactly.; There is room in the buffer for up to two addresses and up to eight words; of memory, but the two needn't be split evenly. When writing the two; addresses are fully pipelined. However, a read from memory that is not; currently in the cache will block until the writes have completed.; It is normally the case that FCLK and MCLK will be in the ratio 2:1, so; writes will take 2 FCLK cycles per word, if FCLK and MCLK are asynchronous; (they aren't allowed to be at present) then there is a startup cost of 1MCLK; cycle to add as well.;; (define_function_unit {name} {num-units} {n-users} {test};; {ready-delay} {issue-delay} [{conflict-list}])(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") (eq_attr "type" "fdivx")) 71 69)(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") (eq_attr "type" "fdivd")) 59 57)(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") (eq_attr "type" "fdivs")) 31 29)(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") (eq_attr "type" "fmul")) 9 7)(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") (eq_attr "type" "ffmul")) 6 4)(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") (eq_attr "type" "farith")) 4 2)(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") (eq_attr "type" "ffarith")) 2 2)(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") (eq_attr "type" "r_2_f")) 5 3)(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") (eq_attr "type" "f_2_r")) 1 2);; The fpa10 doesn't really have a memory read unit, but it can start to;; speculatively execute the instruction in the pipeline, provided the data;; is already loaded, so pretend reads have a delay of 2 (and that the;; pipeline is infinite.(define_function_unit "fpa_mem" 1 0 (and (eq_attr "fpu" "fpa") (eq_attr "type" "f_load")) 3 1);;--------------------------------------------------------------------;; Write buffer;;--------------------------------------------------------------------;; Strictly we should model a 4-deep write buffer for ARM7xx based chips(define_function_unit "write_buf" 1 2 (and (eq_attr "model_wbuf" "yes") (eq_attr "type" "store1,r_mem_f")) 5 3)(define_function_unit "write_buf" 1 2 (and (eq_attr "model_wbuf" "yes") (eq_attr "type" "store2")) 7 4)(define_function_unit "write_buf" 1 2 (and (eq_attr "model_wbuf" "yes") (eq_attr "type" "store3")) 9 5)(define_function_unit "write_buf" 1 2 (and (eq_attr "model_wbuf" "yes") (eq_attr "type" "store4")) 11 6);;--------------------------------------------------------------------;; Write blockage unit;;--------------------------------------------------------------------;; The write_blockage unit models (partially), the fact that reads will stall;; until the write buffer empties.;; The f_mem_r and r_mem_f could also block, but they are to the stack,;; so we don't model them here(define_function_unit "write_blockage" 1 0 (and (eq_attr "model_wbuf" "yes") (eq_attr "type" "store1")) 5 5 [(eq_attr "write_conflict" "yes")])(define_function_unit "write_blockage" 1 0 (and (eq_attr "model_wbuf" "yes") (eq_attr "type" "store2")) 7 7 [(eq_attr "write_conflict" "yes")])(define_function_unit "write_blockage" 1 0 (and (eq_attr "model_wbuf" "yes") (eq_attr "type" "store3")) 9 9 [(eq_attr "write_conflict" "yes")])(define_function_unit "write_blockage" 1 0 (and (eq_attr "model_wbuf" "yes") (eq_attr "type" "store4")) 11 11 [(eq_attr "write_conflict" "yes")])(define_function_unit "write_blockage" 1 0 (and (eq_attr "model_wbuf" "yes") (eq_attr "write_conflict" "yes")) 1 1);;--------------------------------------------------------------------;; Core unit;;--------------------------------------------------------------------;; Everything must spend at least one cycle in the core unit(define_function_unit "core" 1 0 (and (eq_attr "ldsched" "yes") (eq_attr "type" "store1")) 1 1)(define_function_unit "core" 1 0 (and (eq_attr "ldsched" "yes") (eq_attr "type" "load")) 2 1)(define_function_unit "core" 1 0 (and (eq_attr "ldsched" "!yes") (eq_attr "type" "load,store1")) 2 2)(define_function_unit "core" 1 0 (and (eq_attr "fpu" "fpa") (eq_attr "type" "f_load")) 3 3)(define_function_unit "core" 1 0 (and (eq_attr "fpu" "fpa") (eq_attr "type" "f_store")) 4 4)(define_function_unit "core" 1 0 (and (eq_attr "fpu" "fpa") (eq_attr "type" "r_mem_f")) 6 6)(define_function_unit "core" 1 0 (and (eq_attr "fpu" "fpa") (eq_attr "type" "f_mem_r")) 7 7)(define_function_unit "core" 1 0 (and (eq_attr "ldsched" "no") (eq_attr "type" "mult")) 16 16)(define_function_unit "core" 1 0 (and (and (eq_attr "ldsched" "yes") (eq_attr "is_strongarm" "no")) (eq_attr "type" "mult")) 4 4)(define_function_unit "core" 1 0 (and (and (eq_attr "ldsched" "yes") (eq_attr "is_strongarm" "yes")) (eq_attr "type" "mult")) 3 2)(define_function_unit "core" 1 0 (eq_attr "type" "store2") 3 3)(define_function_unit "core" 1 0 (eq_attr "type" "store3") 4 4)(define_function_unit "core" 1 0 (eq_attr "type" "store4") 5 5);; Note: For DImode insns, there is normally no reason why operands should;; not be in the same register, what we don't want is for something being;; written to partially overlap something that is an input.;; Addition insns.(define_insn "adddi3" [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") (plus:DI (match_operand:DI 1 "s_register_operand" "%0,0") (match_operand:DI 2 "s_register_operand" "r,0"))) (clobber (reg:CC 24))] "" "adds\\t%Q0, %Q1, %Q2\;adc\\t%R0, %R1, %R2"[(set_attr "conds" "clob") (set_attr "length" "8")])(define_insn "*adddi_sesidi_di" [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") (plus:DI (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")) (match_operand:DI 1 "s_register_operand" "r,0"))) (clobber (reg:CC 24))] "" "adds\\t%Q0, %Q1, %2\;adc\\t%R0, %R1, %2, asr #31"[(set_attr "conds" "clob") (set_attr "length" "8")])(define_insn "*adddi_zesidi_di" [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") (plus:DI (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")) (match_operand:DI 1 "s_register_operand" "r,0"))) (clobber (reg:CC 24))] "" "adds\\t%Q0, %Q1, %2\;adc\\t%R0, %R1, #0"[(set_attr "conds" "clob") (set_attr "length" "8")])(define_expand "addsi3" [(set (match_operand:SI 0 "s_register_operand" "") (plus:SI (match_operand:SI 1 "s_register_operand" "") (match_operand:SI 2 "reg_or_int_operand" "")))] "" " if (GET_CODE (operands[2]) == CONST_INT) { arm_split_constant (PLUS, SImode, INTVAL (operands[2]), operands[0], operands[1], (reload_in_progress || reload_completed ? 0 : preserve_subexpressions_p ())); DONE; }")(define_split [(set (match_operand:SI 0 "s_register_operand" "") (plus:SI (match_operand:SI 1 "s_register_operand" "") (match_operand:SI 2 "const_int_operand" "")))] "! (const_ok_for_arm (INTVAL (operands[2])) || const_ok_for_arm (-INTVAL (operands[2])))" [(clobber (const_int 0))] " arm_split_constant (PLUS, SImode, INTVAL (operands[2]), operands[0], operands[1], 0); DONE;")(define_insn "*addsi3_insn" [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") (plus:SI (match_operand:SI 1 "s_register_operand" "r,r,r") (match_operand:SI 2 "reg_or_int_operand" "rI,L,?n")))] "" "@ add%?\\t%0, %1, %2 sub%?\\t%0, %1, #%n2 #"[(set_attr "length" "4,4,16")])(define_insn "*addsi3_compare0" [(set (reg:CC_NOOV 24) (compare:CC_NOOV (plus:SI (match_operand:SI 1 "s_register_operand" "r,r") (match_operand:SI 2 "arm_add_operand" "rI,L")) (const_int 0))) (set (match_operand:SI 0 "s_register_operand" "=r,r") (plus:SI (match_dup 1) (match_dup 2)))] "" "@ add%?s\\t%0, %1, %2 sub%?s\\t%0, %1, #%n2"[(set_attr "conds" "set")])(define_insn "*addsi3_compare0_scratch" [(set (reg:CC_NOOV 24) (compare:CC_NOOV (plus:SI (match_operand:SI 0 "s_register_operand" "r,r") (match_operand:SI 1 "arm_add_operand" "rI,L")) (const_int 0)))] "" "@ cmn%?\\t%0, %1 cmp%?\\t%0, #%n1"[(set_attr "conds" "set")]);; The next four insns work because they compare the result with one of;; the operands, and we know that the use of the condition code is;; either GEU or LTU, so we can use the carry flag from the addition;; instead of doing the compare a second time.(define_insn "*addsi3_compare_op1" [(set (reg:CC_C 24) (compare:CC_C (plus:SI (match_operand:SI 1 "s_register_operand" "r,r") (match_operand:SI 2 "arm_add_operand" "rI,L")) (match_dup 1))) (set (match_operand:SI 0 "s_register_operand" "=r,r") (plus:SI (match_dup 1) (match_dup 2)))] "" "@ add%?s\\t%0, %1, %2 sub%?s\\t%0, %1, #%n2"[(set_attr "conds" "set")])
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -