X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fconfig%2Farm%2Farm.md;h=783fab06e8bbbc3da3760ddee7239dd9c26aa2a8;hp=705d22dbf01443d86c25cf1649349b4d97883785;hb=6cffc0378ceae14ffd239aa731e5c3106151aefd;hpb=7d57ec4572c40bafae7a85ab262b5cc2561971ff diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 705d22dbf01..783fab06e8b 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -1,26 +1,26 @@ ;;- Machine description for ARM for GNU compiler ;; Copyright 1991, 1993, 1994, 1995, 1996, 1996, 1997, 1998, 1999, 2000, -;; 2001, 2002, 2003 Free Software Foundation, Inc. +;; 2001, 2002, 2003, 2004, 2005 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. +;; This file is part of GCC. -;; 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. +;; GCC 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. +;; GCC 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. +;; along with GCC; see the file COPYING. If not, write to +;; the Free Software Foundation, 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. ;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. @@ -30,12 +30,22 @@ ;; Register numbers (define_constants - [(IP_REGNUM 12) ; Scratch register + [(R0_REGNUM 0) ; First CORE register + (IP_REGNUM 12) ; Scratch register (SP_REGNUM 13) ; Stack pointer (LR_REGNUM 14) ; Return address register (PC_REGNUM 15) ; Program counter (CC_REGNUM 24) ; Condition code pseudo register - (LAST_ARM_REGNUM 15) + (LAST_ARM_REGNUM 15) ; + (FPA_F0_REGNUM 16) ; FIRST_FPA_REGNUM + (FPA_F7_REGNUM 23) ; LAST_FPA_REGNUM + ] +) +;; 3rd operand to select_dominance_cc_mode +(define_constants + [(DOM_CC_X_AND_Y 0) + (DOM_CC_NX_OR_Y 1) + (DOM_CC_X_OR_Y 2) ] ) @@ -56,7 +66,11 @@ (UNSPEC_PIC_SYM 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. - (UNSPEC_PRLG_STK 4) ; A special barrier that prevents frame accesses + (UNSPEC_PIC_BASE 4) ; Adding the PC value to the offset to the + ; GLOBAL_OFFSET_TABLE. The operation is fully + ; described by the RTL but must be wrapped to + ; prevent combine from trying to rip it apart. + (UNSPEC_PRLG_STK 5) ; A special barrier that prevents frame accesses ; being scheduled before the stack adjustment insn. (UNSPEC_PROLOGUE_USE 6) ; As USE insns are not meaningful after reload, ; this unspec is used to prevent the deletion of @@ -64,6 +78,18 @@ ; and stack frame generation. Operand 0 is the ; register to "use". (UNSPEC_CHECK_ARCH 7); Set CCs to indicate 26-bit or 32-bit mode. + (UNSPEC_WSHUFH 8) ; Used by the intrinsic form of the iWMMXt WSHUFH instruction. + (UNSPEC_WACC 9) ; Used by the intrinsic form of the iWMMXt WACC instruction. + (UNSPEC_TMOVMSK 10) ; Used by the intrinsic form of the iWMMXt TMOVMSK instruction. + (UNSPEC_WSAD 11) ; Used by the intrinsic form of the iWMMXt WSAD instruction. + (UNSPEC_WSADZ 12) ; Used by the intrinsic form of the iWMMXt WSADZ instruction. + (UNSPEC_WMACS 13) ; Used by the intrinsic form of the iWMMXt WMACS instruction. + (UNSPEC_WMACU 14) ; Used by the intrinsic form of the iWMMXt WMACU instruction. + (UNSPEC_WMACSZ 15) ; Used by the intrinsic form of the iWMMXt WMACSZ instruction. + (UNSPEC_WMACUZ 16) ; Used by the intrinsic form of the iWMMXt WMACUZ instruction. + (UNSPEC_CLRDI 17) ; Used by the intrinsic form of the iWMMXt CLRDI instruction. + (UNSPEC_WMADDS 18) ; Used by the intrinsic form of the iWMMXt WMADDS instruction. + (UNSPEC_WMADDU 19) ; Used by the intrinsic form of the iWMMXt WMADDU instruction. ] ) @@ -88,6 +114,14 @@ ; a 32-bit object. (VUNSPEC_POOL_8 7) ; `pool-entry(8)'. An entry in the constant pool for ; a 64-bit object. + (VUNSPEC_TMRC 8) ; Used by the iWMMXt TMRC instruction. + (VUNSPEC_TMCR 9) ; Used by the iWMMXt TMCR instruction. + (VUNSPEC_ALIGN8 10) ; 8-byte alignment version of VUNSPEC_ALIGN + (VUNSPEC_WCMP_EQ 11) ; Used by the iWMMXt WCMPEQ instructions + (VUNSPEC_WCMP_GTU 12) ; Used by the iWMMXt WCMPGTU instructions + (VUNSPEC_WCMP_GT 13) ; Used by the iwMMXT WCMPGT instructions + (VUNSPEC_EH_RETURN 20); Use to override the return address for exception + ; handling. ] ) @@ -99,24 +133,22 @@ ; patterns that share the same RTL in both ARM and Thumb code. (define_attr "is_thumb" "no,yes" (const (symbol_ref "thumb_code"))) -; 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"))) - ; IS_STRONGARM is set to 'yes' when compiling for StrongARM, it affects ; scheduling decisions for the load unit and the multiplier. -(define_attr "is_strongarm" "no,yes" (const (symbol_ref "arm_is_strong"))) +(define_attr "is_strongarm" "no,yes" (const (symbol_ref "arm_tune_strongarm"))) + +; IS_XSCALE is set to 'yes' when compiling for XScale. +(define_attr "is_xscale" "no,yes" (const (symbol_ref "arm_tune_xscale"))) ;; Operand number of an input operand that is shifted. Zero if the ;; given instruction does not shift one of its input operands. -(define_attr "is_xscale" "no,yes" (const (symbol_ref "arm_is_xscale"))) (define_attr "shift" "" (const_int 0)) ; 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"))) +(define_attr "fpu" "none,fpa,fpe2,fpe3,maverick,vfp" + (const (symbol_ref "arm_fpu_attr"))) ; LENGTH of an instruction (in bytes) (define_attr "length" "" (const_int 4)) @@ -137,13 +169,26 @@ (set_attr "length" "4") (set_attr "pool_range" "250")]) +;; The instruction used to implement a particular pattern. This +;; information is used by pipeline descriptions to provide accurate +;; scheduling information. + +(define_attr "insn" + "smulxy,smlaxy,smlalxy,smulwy,smlawx,mul,muls,mla,mlas,umull,umulls,umlal,umlals,smull,smulls,smlal,smlals,smlawy,smuad,smuadx,smlad,smladx,smusd,smusdx,smlsd,smlsdx,smmul,smmulr,other" + (const_string "other")) + ; 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 +; alu any alu instruction that doesn't hit memory or fp +; regs or have a shifted source operand +; alu_shift any data instruction that doesn't hit memory or fp +; regs, but has a source operand shifted by a constant +; alu_shift_reg any data instruction that doesn't hit memory or fp +; regs, but has a source operand shifted by a register value ; mult a multiply instruction ; block blockage insn, this blocks all functional units ; float a floating point arithmetic operation (subject to expansion) @@ -157,20 +202,35 @@ ; even on a machine with an fpa. ; f_load a floating point load from memory ; f_store a floating point store to memory +; f_load[sd] single/double load from memory +; f_store[sd] single/double store to memory +; f_flag a transfer of co-processor flags to the CPSR ; 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 +; f_cvt convert floating<->integral +; branch a branch ; call a subroutine call -; load any load from memory -; store1 store 1 word to memory from arm registers +; load_byte load byte(s) from memory to arm registers +; load1 load 1 word from memory to arm registers +; load2 load 2 words from memory to arm registers +; load3 load 3 words from memory to arm registers +; load4 load 4 words from memory to arm registers +; store store 1 word to memory from arm registers ; store2 store 2 words ; store3 store 3 words -; store4 store 4 words +; store4 store 4 (or more) words +; Additions for Cirrus Maverick co-processor: +; mav_farith Floating point arithmetic (4 cycle) +; mav_dmult Double multiplies (7 cycle) ; (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")) + "alu,alu_shift,alu_shift_reg,mult,block,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith,f_flag,float_em,f_load,f_store,f_loads,f_loadd,f_stores,f_stored,f_mem_r,r_mem_f,f_2_r,r_2_f,f_cvt,branch,call,load_byte,load1,load2,load3,load4,store1,store2,store3,store4,mav_farith,mav_dmult" + (if_then_else + (eq_attr "insn" "smulxy,smlaxy,smlalxy,smulwy,smlawx,mul,muls,mla,mlas,umull,umulls,umlal,umlals,smull,smulls,smlal,smlals") + (const_string "mult") + (const_string "alu"))) ; Load scheduling, set from the arm_ld_sched variable ; initialized by arm_override_options() @@ -198,8 +258,7 @@ (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 "clob") (const_string "nocond"))) ; Predicable means that the insn can be conditionally executed based on @@ -210,15 +269,15 @@ ; 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 +; suffer blockages enough to warrant 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 "model_wbuf" "no,yes" (const (symbol_ref "arm_tune_wbuf"))) ; WRITE_CONFLICT implies that a read following an unrelated write is likely ; to stall the processor. Used with model_wbuf above. (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") + "block,float_em,f_load,f_store,f_mem_r,r_mem_f,call,load1") (const_string "yes") (const_string "no"))) @@ -226,7 +285,7 @@ ; than one on the main cpu execution unit. (define_attr "core_cycles" "single,multi" (if_then_else (eq_attr "type" - "normal,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith") + "alu,alu_shift,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith") (const_string "single") (const_string "multi"))) @@ -234,160 +293,48 @@ ;; distant label. Only applicable to Thumb code. (define_attr "far_jump" "yes,no" (const_string "no")) -;; (define_function_unit {name} {num-units} {n-users} {test} -;; {ready-delay} {issue-delay} [{conflict-list}]) - -;;-------------------------------------------------------------------- -;; Floating point unit (FPA) -;;-------------------------------------------------------------------- -(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) +;;--------------------------------------------------------------------------- +;; Mode macros -(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") - (eq_attr "type" "fdivs")) 31 29) +; A list of modes that are exactly 64 bits in size. We use this to expand +; some splits that are the same for all modes when operating on ARM +; registers. +(define_mode_macro ANY64 [DI DF V8QI V4HI V2SI V2SF]) -(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") - (eq_attr "type" "fmul")) 9 7) +;;--------------------------------------------------------------------------- +;; Predicates -(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") - (eq_attr "type" "ffmul")) 6 4) +(include "predicates.md") -(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") - (eq_attr "type" "farith")) 4 2) +;;--------------------------------------------------------------------------- +;; Pipeline descriptions -(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") - (eq_attr "type" "ffarith")) 2 2) +;; Processor type. This is created automatically from arm-cores.def. +(include "arm-tune.md") -(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") - (eq_attr "type" "r_2_f")) 5 3) +;; True if the generic scheduling description should be used. -(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") - (eq_attr "type" "f_2_r")) 1 2) +(define_attr "generic_sched" "yes,no" + (const (if_then_else + (eq_attr "tune" "arm926ejs,arm1020e,arm1026ejs,arm1136js,arm1136jfs") + (const_string "no") + (const_string "yes")))) -; 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_attr "generic_vfp" "yes,no" + (const (if_then_else + (and (eq_attr "fpu" "vfp") + (eq_attr "tune" "!arm1020e,arm1022e")) + (const_string "yes") + (const_string "no")))) -(define_function_unit "fpa_mem" 1 0 (and (eq_attr "fpu" "fpa") - (eq_attr "type" "f_load")) 3 1) +(include "arm-generic.md") +(include "arm926ejs.md") +(include "arm1020e.md") +(include "arm1026ejs.md") +(include "arm1136jfs.md") -;;-------------------------------------------------------------------- -;; Write buffer -;;-------------------------------------------------------------------- -; Strictly, we should model a 4-deep write buffer for ARM7xx based chips -; -; 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 "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 (eq_attr "core_cycles" "single") 1 1) - -(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) - -;; We do not need to conditionalize the define_function_unit immediately -;; above. This one will be ignored for anything other than xscale -;; compiles and for xscale compiles it provides a larger delay -;; and the scheduler will DTRT. -;; FIXME: this test needs to be revamped to not depend on this feature -;; of the scheduler. - -(define_function_unit "core" 1 0 - (and (and (eq_attr "ldsched" "yes") (eq_attr "type" "load")) - (eq_attr "is_xscale" "yes")) - 3 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) - -(define_function_unit "core" 1 0 - (and (eq_attr "core_cycles" "multi") - (eq_attr "type" "!mult,load,store1,store2,store3,store4")) 32 32) -(include "cirrus.md") - ;;--------------------------------------------------------------------------- ;; Insn patterns ;; @@ -407,7 +354,7 @@ (clobber (reg:CC CC_REGNUM))])] "TARGET_EITHER" " - if (TARGET_CIRRUS) + if (TARGET_HARD_FLOAT && TARGET_MAVERICK) { if (!cirrus_fp_register (operands[0], DImode)) operands[0] = force_reg (DImode, operands[0]); @@ -443,7 +390,7 @@ (plus:DI (match_operand:DI 1 "s_register_operand" "%0, 0") (match_operand:DI 2 "s_register_operand" "r, 0"))) (clobber (reg:CC CC_REGNUM))] - "TARGET_ARM && !TARGET_CIRRUS" + "TARGET_ARM && !(TARGET_HARD_FLOAT && TARGET_MAVERICK)" "#" "TARGET_ARM && reload_completed" [(parallel [(set (reg:CC_C CC_REGNUM) @@ -471,7 +418,7 @@ (match_operand:SI 2 "s_register_operand" "r,r")) (match_operand:DI 1 "s_register_operand" "r,0"))) (clobber (reg:CC CC_REGNUM))] - "TARGET_ARM && !TARGET_CIRRUS" + "TARGET_ARM && !(TARGET_HARD_FLOAT && TARGET_MAVERICK)" "#" "TARGET_ARM && reload_completed" [(parallel [(set (reg:CC_C CC_REGNUM) @@ -500,7 +447,7 @@ (match_operand:SI 2 "s_register_operand" "r,r")) (match_operand:DI 1 "s_register_operand" "r,0"))) (clobber (reg:CC CC_REGNUM))] - "TARGET_ARM && !TARGET_CIRRUS" + "TARGET_ARM && !(TARGET_HARD_FLOAT && TARGET_MAVERICK)" "#" "TARGET_ARM && reload_completed" [(parallel [(set (reg:CC_C CC_REGNUM) @@ -529,20 +476,20 @@ " if (TARGET_ARM && GET_CODE (operands[2]) == CONST_INT) { - arm_split_constant (PLUS, SImode, INTVAL (operands[2]), operands[0], - operands[1], - (no_new_pseudos ? 0 : preserve_subexpressions_p ())); + arm_split_constant (PLUS, SImode, NULL_RTX, + INTVAL (operands[2]), operands[0], operands[1], + optimize && !no_new_pseudos); DONE; } " ) -; If there is a scratch available, this will be faster than synthesising the +; If there is a scratch available, this will be faster than synthesizing the ; addition. (define_peephole2 [(match_scratch:SI 3 "r") - (set (match_operand:SI 0 "s_register_operand" "") - (plus:SI (match_operand:SI 1 "s_register_operand" "") + (set (match_operand:SI 0 "arm_general_register_operand" "") + (plus:SI (match_operand:SI 1 "arm_general_register_operand" "") (match_operand:SI 2 "const_int_operand" "")))] "TARGET_ARM && !(const_ok_for_arm (INTVAL (operands[2])) @@ -568,7 +515,8 @@ || const_ok_for_arm (-INTVAL (operands[2])))" [(clobber (const_int 0))] " - arm_split_constant (PLUS, SImode, INTVAL (operands[2]), operands[0], + arm_split_constant (PLUS, SImode, curr_insn, + INTVAL (operands[2]), operands[0], operands[1], 0); DONE; " @@ -608,15 +556,14 @@ ;; Reloading and elimination of the frame pointer can ;; sometimes cause this optimization to be missed. (define_peephole2 - [(set (match_operand:SI 0 "register_operand" "") + [(set (match_operand:SI 0 "arm_general_register_operand" "") (match_operand:SI 1 "const_int_operand" "")) (set (match_dup 0) - (plus:SI (match_dup 0) (match_operand:SI 2 "register_operand" "")))] + (plus:SI (match_dup 0) (reg:SI SP_REGNUM)))] "TARGET_THUMB - && REGNO (operands[2]) == STACK_POINTER_REGNUM && (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) < 1024 && (INTVAL (operands[1]) & 3) == 0" - [(set (match_dup 0) (plus:SI (match_dup 2) (match_dup 1)))] + [(set (match_dup 0) (plus:SI (reg:SI SP_REGNUM) (match_dup 1)))] "" ) @@ -648,35 +595,70 @@ [(set_attr "conds" "set")] ) -;; These patterns are the same ones as the two regular addsi3_compare0 -;; patterns, except we write them slightly different - the combiner -;; tends to generate them this way. -(define_insn "*addsi3_compare0_for_combiner" - [(set (reg:CC CC_REGNUM) - (compare:CC - (match_operand:SI 1 "s_register_operand" "r,r") - (neg:SI (match_operand:SI 2 "arm_add_operand" "rI,L")))) - (set (match_operand:SI 0 "s_register_operand" "=r,r") - (plus:SI (match_dup 1) (match_dup 2)))] +(define_insn "*compare_negsi_si" + [(set (reg:CC_Z CC_REGNUM) + (compare:CC_Z + (neg:SI (match_operand:SI 0 "s_register_operand" "r")) + (match_operand:SI 1 "s_register_operand" "r")))] "TARGET_ARM" - "@ - add%?s\\t%0, %1, %2 - sub%?s\\t%0, %1, #%n2" + "cmn%?\\t%1, %0" [(set_attr "conds" "set")] ) -(define_insn "*addsi3_compare0_scratch_for_combiner" +;; This is the canonicalization of addsi3_compare0_for_combiner when the +;; addend is a constant. +(define_insn "*cmpsi2_addneg" [(set (reg:CC CC_REGNUM) (compare:CC - (match_operand:SI 0 "s_register_operand" "r,r") - (neg:SI (match_operand:SI 1 "arm_add_operand" "rI,L"))))] - "TARGET_ARM" + (match_operand:SI 1 "s_register_operand" "r,r") + (match_operand:SI 2 "arm_addimm_operand" "I,L"))) + (set (match_operand:SI 0 "s_register_operand" "=r,r") + (plus:SI (match_dup 1) + (match_operand:SI 3 "arm_addimm_operand" "L,I")))] + "TARGET_ARM && INTVAL (operands[2]) == -INTVAL (operands[3])" "@ - cmn%?\\t%0, %1 - cmp%?\\t%0, #%n1" + sub%?s\\t%0, %1, %2 + add%?s\\t%0, %1, #%n2" [(set_attr "conds" "set")] ) +;; Convert the sequence +;; sub rd, rn, #1 +;; cmn rd, #1 (equivalent to cmp rd, #-1) +;; bne dest +;; into +;; subs rd, rn, #1 +;; bcs dest ((unsigned)rn >= 1) +;; similarly for the beq variant using bcc. +;; This is a common looping idiom (while (n--)) +(define_peephole2 + [(set (match_operand:SI 0 "arm_general_register_operand" "") + (plus:SI (match_operand:SI 1 "arm_general_register_operand" "") + (const_int -1))) + (set (match_operand 2 "cc_register" "") + (compare (match_dup 0) (const_int -1))) + (set (pc) + (if_then_else (match_operator 3 "equality_operator" + [(match_dup 2) (const_int 0)]) + (match_operand 4 "" "") + (match_operand 5 "" "")))] + "TARGET_ARM && peep2_reg_dead_p (3, operands[2])" + [(parallel[ + (set (match_dup 2) + (compare:CC + (match_dup 1) (const_int 1))) + (set (match_dup 0) (plus:SI (match_dup 1) (const_int -1)))]) + (set (pc) + (if_then_else (match_op_dup 3 [(match_dup 2) (const_int 0)]) + (match_dup 4) + (match_dup 5)))] + "operands[2] = gen_rtx_REG (CCmode, CC_REGNUM); + operands[3] = gen_rtx_fmt_ee ((GET_CODE (operands[3]) == NE + ? GEU : LTU), + VOIDmode, + operands[2], const0_rtx);" +) + ;; 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 @@ -748,16 +730,19 @@ ) (define_insn "*addsi3_carryin_shift" - [(set (match_operand:SI 0 "s_register_operand" "") + [(set (match_operand:SI 0 "s_register_operand" "=r") (plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0)) (plus:SI (match_operator:SI 2 "shift_operator" - [(match_operand:SI 3 "s_register_operand" "") - (match_operand:SI 4 "reg_or_int_operand" "")]) - (match_operand:SI 1 "s_register_operand" ""))))] + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "reg_or_int_operand" "rM")]) + (match_operand:SI 1 "s_register_operand" "r"))))] "TARGET_ARM" "adc%?\\t%0, %1, %3%S2" - [(set_attr "conds" "use")] + [(set_attr "conds" "use") + (set (attr "type") (if_then_else (match_operand 4 "const_int_operand" "") + (const_string "alu_shift") + (const_string "alu_shift_reg")))] ) (define_insn "*addsi3_carryin_alt1" @@ -803,65 +788,41 @@ (set_attr "length" "4,8")] ) -(define_insn "*arm_addsf3" - [(set (match_operand:SF 0 "s_register_operand" "=f,f") - (plus:SF (match_operand:SF 1 "s_register_operand" "%f,f") - (match_operand:SF 2 "fpu_add_operand" "fG,H")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "@ - adf%?s\\t%0, %1, %2 - suf%?s\\t%0, %1, #%N2" - [(set_attr "type" "farith") - (set_attr "predicable" "yes")] -) - -(define_insn "*arm_adddf3" - [(set (match_operand:DF 0 "s_register_operand" "=f,f") - (plus:DF (match_operand:DF 1 "s_register_operand" "%f,f") - (match_operand:DF 2 "fpu_add_operand" "fG,H")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "@ - adf%?d\\t%0, %1, %2 - suf%?d\\t%0, %1, #%N2" - [(set_attr "type" "farith") - (set_attr "predicable" "yes")] -) - -(define_insn "*adddf_esfdf_df" - [(set (match_operand:DF 0 "s_register_operand" "=f,f") - (plus:DF (float_extend:DF - (match_operand:SF 1 "s_register_operand" "f,f")) - (match_operand:DF 2 "fpu_add_operand" "fG,H")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "@ - adf%?d\\t%0, %1, %2 - suf%?d\\t%0, %1, #%N2" - [(set_attr "type" "farith") - (set_attr "predicable" "yes")] -) +; transform ((x << y) - 1) to ~(~(x-1) << y) Where X is a constant. +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (plus:SI (ashift:SI (match_operand:SI 1 "const_int_operand" "") + (match_operand:SI 2 "s_register_operand" "")) + (const_int -1))) + (clobber (match_operand:SI 3 "s_register_operand" ""))] + "TARGET_ARM" + [(set (match_dup 3) (match_dup 1)) + (set (match_dup 0) (not:SI (ashift:SI (match_dup 3) (match_dup 2))))] + " + operands[1] = GEN_INT (~(INTVAL (operands[1]) - 1)); +") -(define_insn "*adddf_df_esfdf" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (plus:DF (match_operand:DF 1 "s_register_operand" "f") - (float_extend:DF - (match_operand:SF 2 "s_register_operand" "f"))))] +(define_expand "addsf3" + [(set (match_operand:SF 0 "s_register_operand" "") + (plus:SF (match_operand:SF 1 "s_register_operand" "") + (match_operand:SF 2 "arm_float_add_operand" "")))] "TARGET_ARM && TARGET_HARD_FLOAT" - "adf%?d\\t%0, %1, %2" - [(set_attr "type" "farith") - (set_attr "predicable" "yes")] -) + " + if (TARGET_MAVERICK + && !cirrus_fp_register (operands[2], SFmode)) + operands[2] = force_reg (SFmode, operands[2]); +") -(define_insn "*adddf_esfdf_esfdf" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (plus:DF (float_extend:DF - (match_operand:SF 1 "s_register_operand" "f")) - (float_extend:DF - (match_operand:SF 2 "s_register_operand" "f"))))] +(define_expand "adddf3" + [(set (match_operand:DF 0 "s_register_operand" "") + (plus:DF (match_operand:DF 1 "s_register_operand" "") + (match_operand:DF 2 "arm_float_add_operand" "")))] "TARGET_ARM && TARGET_HARD_FLOAT" - "adf%?d\\t%0, %1, %2" - [(set_attr "type" "farith") - (set_attr "predicable" "yes")] -) + " + if (TARGET_MAVERICK + && !cirrus_fp_register (operands[2], DFmode)) + operands[2] = force_reg (DFmode, operands[2]); +") (define_expand "subdi3" [(parallel @@ -871,7 +832,7 @@ (clobber (reg:CC CC_REGNUM))])] "TARGET_EITHER" " - if (TARGET_CIRRUS + if (TARGET_HARD_FLOAT && TARGET_MAVERICK && TARGET_ARM && cirrus_fp_register (operands[0], DImode) && cirrus_fp_register (operands[1], DImode)) @@ -982,10 +943,9 @@ { if (TARGET_ARM) { - arm_split_constant (MINUS, SImode, INTVAL (operands[1]), operands[0], - operands[2], - (no_new_pseudos ? 0 - : preserve_subexpressions_p ())); + arm_split_constant (MINUS, SImode, NULL_RTX, + INTVAL (operands[1]), operands[0], + operands[2], optimize && !no_new_pseudos); DONE; } else /* TARGET_THUMB */ @@ -1016,8 +976,8 @@ && !const_ok_for_arm (INTVAL (operands[1]))" [(clobber (const_int 0))] " - arm_split_constant (MINUS, SImode, INTVAL (operands[1]), operands[0], - operands[2], 0); + arm_split_constant (MINUS, SImode, curr_insn, + INTVAL (operands[1]), operands[0], operands[2], 0); DONE; " [(set_attr "length" "4,16") @@ -1026,9 +986,9 @@ (define_peephole2 [(match_scratch:SI 3 "r") - (set (match_operand:SI 0 "s_register_operand" "") + (set (match_operand:SI 0 "arm_general_register_operand" "") (minus:SI (match_operand:SI 1 "const_int_operand" "") - (match_operand:SI 2 "s_register_operand" "")))] + (match_operand:SI 2 "arm_general_register_operand" "")))] "TARGET_ARM && !const_ok_for_arm (INTVAL (operands[1])) && const_ok_for_arm (~INTVAL (operands[1]))" @@ -1065,64 +1025,36 @@ (set_attr "length" "*,8")] ) -(define_insn "*arm_subsf3" - [(set (match_operand:SF 0 "s_register_operand" "=f,f") - (minus:SF (match_operand:SF 1 "fpu_rhs_operand" "f,G") - (match_operand:SF 2 "fpu_rhs_operand" "fG,f")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "@ - suf%?s\\t%0, %1, %2 - rsf%?s\\t%0, %2, %1" - [(set_attr "type" "farith")] -) - -(define_insn "*arm_subdf3" - [(set (match_operand:DF 0 "s_register_operand" "=f,f") - (minus:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G") - (match_operand:DF 2 "fpu_rhs_operand" "fG,f")))] +(define_expand "subsf3" + [(set (match_operand:SF 0 "s_register_operand" "") + (minus:SF (match_operand:SF 1 "arm_float_rhs_operand" "") + (match_operand:SF 2 "arm_float_rhs_operand" "")))] "TARGET_ARM && TARGET_HARD_FLOAT" - "@ - suf%?d\\t%0, %1, %2 - rsf%?d\\t%0, %2, %1" - [(set_attr "type" "farith") - (set_attr "predicable" "yes")] -) - -(define_insn "*subdf_esfdf_df" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (minus:DF (float_extend:DF - (match_operand:SF 1 "s_register_operand" "f")) - (match_operand:DF 2 "fpu_rhs_operand" "fG")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "suf%?d\\t%0, %1, %2" - [(set_attr "type" "farith") - (set_attr "predicable" "yes")] -) + " + if (TARGET_MAVERICK) + { + if (!cirrus_fp_register (operands[1], SFmode)) + operands[1] = force_reg (SFmode, operands[1]); + if (!cirrus_fp_register (operands[2], SFmode)) + operands[2] = force_reg (SFmode, operands[2]); + } +") -(define_insn "*subdf_df_esfdf" - [(set (match_operand:DF 0 "s_register_operand" "=f,f") - (minus:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G") - (float_extend:DF - (match_operand:SF 2 "s_register_operand" "f,f"))))] +(define_expand "subdf3" + [(set (match_operand:DF 0 "s_register_operand" "") + (minus:DF (match_operand:DF 1 "arm_float_rhs_operand" "") + (match_operand:DF 2 "arm_float_rhs_operand" "")))] "TARGET_ARM && TARGET_HARD_FLOAT" - "@ - suf%?d\\t%0, %1, %2 - rsf%?d\\t%0, %2, %1" - [(set_attr "type" "farith") - (set_attr "predicable" "yes")] -) + " + if (TARGET_MAVERICK) + { + if (!cirrus_fp_register (operands[1], DFmode)) + operands[1] = force_reg (DFmode, operands[1]); + if (!cirrus_fp_register (operands[2], DFmode)) + operands[2] = force_reg (DFmode, operands[2]); + } +") -(define_insn "*subdf_esfdf_esfdf" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (minus:DF (float_extend:DF - (match_operand:SF 1 "s_register_operand" "f")) - (float_extend:DF - (match_operand:SF 2 "s_register_operand" "f"))))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "suf%?d\\t%0, %1, %2" - [(set_attr "type" "farith") - (set_attr "predicable" "yes")] -) ;; Multiplication insns @@ -1141,7 +1073,7 @@ (match_operand:SI 1 "s_register_operand" "%?r,0")))] "TARGET_ARM" "mul%?\\t%0, %2, %1" - [(set_attr "type" "mult") + [(set_attr "insn" "mul") (set_attr "predicable" "yes")] ) @@ -1157,12 +1089,12 @@ "TARGET_THUMB" "* if (which_alternative < 2) - return \"mov\\t%0, %1\;mul\\t%0, %0, %2\"; + return \"mov\\t%0, %1\;mul\\t%0, %2\"; else - return \"mul\\t%0, %0, %2\"; + return \"mul\\t%0, %2\"; " [(set_attr "length" "4,4,2") - (set_attr "type" "mult")] + (set_attr "insn" "mul")] ) (define_insn "*mulsi3_compare0" @@ -1173,10 +1105,10 @@ (const_int 0))) (set (match_operand:SI 0 "s_register_operand" "=&r,&r") (mult:SI (match_dup 2) (match_dup 1)))] - "TARGET_ARM && !arm_is_xscale" + "TARGET_ARM" "mul%?s\\t%0, %2, %1" [(set_attr "conds" "set") - (set_attr "type" "mult")] + (set_attr "insn" "muls")] ) (define_insn "*mulsi_compare0_scratch" @@ -1186,10 +1118,10 @@ (match_operand:SI 1 "s_register_operand" "%?r,0")) (const_int 0))) (clobber (match_scratch:SI 0 "=&r,&r"))] - "TARGET_ARM && !arm_is_xscale" + "TARGET_ARM" "mul%?s\\t%0, %2, %1" [(set_attr "conds" "set") - (set_attr "type" "mult")] + (set_attr "insn" "muls")] ) ;; Unnamed templates to match MLA instruction. @@ -1202,7 +1134,7 @@ (match_operand:SI 3 "s_register_operand" "?r,r,0,0")))] "TARGET_ARM" "mla%?\\t%0, %2, %1, %3" - [(set_attr "type" "mult") + [(set_attr "insn" "mla") (set_attr "predicable" "yes")] ) @@ -1217,10 +1149,10 @@ (set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r,&r") (plus:SI (mult:SI (match_dup 2) (match_dup 1)) (match_dup 3)))] - "TARGET_ARM && !arm_is_xscale" + "TARGET_ARM" "mla%?s\\t%0, %2, %1, %3" [(set_attr "conds" "set") - (set_attr "type" "mult")] + (set_attr "insn" "mlas")] ) (define_insn "*mulsi3addsi_compare0_scratch" @@ -1232,13 +1164,13 @@ (match_operand:SI 3 "s_register_operand" "?r,r,0,0")) (const_int 0))) (clobber (match_scratch:SI 0 "=&r,&r,&r,&r"))] - "TARGET_ARM && !arm_is_xscale" + "TARGET_ARM" "mla%?s\\t%0, %2, %1, %3" [(set_attr "conds" "set") - (set_attr "type" "mult")] + (set_attr "insn" "mlas")] ) -;; Unnamed template to match long long multiply-accumlate (smlal) +;; Unnamed template to match long long multiply-accumulate (smlal) (define_insn "*mulsidi3adddi" [(set (match_operand:DI 0 "s_register_operand" "=&r") @@ -1247,9 +1179,9 @@ (sign_extend:DI (match_operand:SI 2 "s_register_operand" "%r")) (sign_extend:DI (match_operand:SI 3 "s_register_operand" "r"))) (match_operand:DI 1 "s_register_operand" "0")))] - "TARGET_ARM && arm_fast_multiply" + "TARGET_ARM && arm_arch3m" "smlal%?\\t%Q0, %R0, %3, %2" - [(set_attr "type" "mult") + [(set_attr "insn" "smlal") (set_attr "predicable" "yes")] ) @@ -1258,9 +1190,9 @@ (mult:DI (sign_extend:DI (match_operand:SI 1 "s_register_operand" "%r")) (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r"))))] - "TARGET_ARM && arm_fast_multiply" + "TARGET_ARM && arm_arch3m" "smull%?\\t%Q0, %R0, %1, %2" - [(set_attr "type" "mult") + [(set_attr "insn" "smull") (set_attr "predicable" "yes")] ) @@ -1269,13 +1201,13 @@ (mult:DI (zero_extend:DI (match_operand:SI 1 "s_register_operand" "%r")) (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r"))))] - "TARGET_ARM && arm_fast_multiply" + "TARGET_ARM && arm_arch3m" "umull%?\\t%Q0, %R0, %1, %2" - [(set_attr "type" "mult") + [(set_attr "insn" "umull") (set_attr "predicable" "yes")] ) -;; Unnamed template to match long long unsigned multiply-accumlate (umlal) +;; Unnamed template to match long long unsigned multiply-accumulate (umlal) (define_insn "*umulsidi3adddi" [(set (match_operand:DI 0 "s_register_operand" "=&r") @@ -1284,9 +1216,9 @@ (zero_extend:DI (match_operand:SI 2 "s_register_operand" "%r")) (zero_extend:DI (match_operand:SI 3 "s_register_operand" "r"))) (match_operand:DI 1 "s_register_operand" "0")))] - "TARGET_ARM && arm_fast_multiply" + "TARGET_ARM && arm_arch3m" "umlal%?\\t%Q0, %R0, %3, %2" - [(set_attr "type" "mult") + [(set_attr "insn" "umlal") (set_attr "predicable" "yes")] ) @@ -1299,9 +1231,9 @@ (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r,r"))) (const_int 32)))) (clobber (match_scratch:SI 3 "=&r,&r"))] - "TARGET_ARM && arm_fast_multiply" + "TARGET_ARM && arm_arch3m" "smull%?\\t%3, %0, %2, %1" - [(set_attr "type" "mult") + [(set_attr "insn" "smull") (set_attr "predicable" "yes")] ) @@ -1314,9 +1246,9 @@ (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r,r"))) (const_int 32)))) (clobber (match_scratch:SI 3 "=&r,&r"))] - "TARGET_ARM && arm_fast_multiply" + "TARGET_ARM && arm_arch3m" "umull%?\\t%3, %0, %2, %1" - [(set_attr "type" "mult") + [(set_attr "insn" "umull") (set_attr "predicable" "yes")] ) @@ -1326,9 +1258,50 @@ (match_operand:HI 1 "s_register_operand" "%r")) (sign_extend:SI (match_operand:HI 2 "s_register_operand" "r"))))] - "TARGET_ARM && arm_is_xscale" + "TARGET_ARM && arm_arch5e" "smulbb%?\\t%0, %1, %2" - [(set_attr "type" "mult")] + [(set_attr "insn" "smulxy") + (set_attr "predicable" "yes")] +) + +(define_insn "*mulhisi3tb" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (mult:SI (ashiftrt:SI + (match_operand:SI 1 "s_register_operand" "r") + (const_int 16)) + (sign_extend:SI + (match_operand:HI 2 "s_register_operand" "r"))))] + "TARGET_ARM && arm_arch5e" + "smultb%?\\t%0, %1, %2" + [(set_attr "insn" "smulxy") + (set_attr "predicable" "yes")] +) + +(define_insn "*mulhisi3bt" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (mult:SI (sign_extend:SI + (match_operand:HI 1 "s_register_operand" "r")) + (ashiftrt:SI + (match_operand:SI 2 "s_register_operand" "r") + (const_int 16))))] + "TARGET_ARM && arm_arch5e" + "smulbt%?\\t%0, %1, %2" + [(set_attr "insn" "smulxy") + (set_attr "predicable" "yes")] +) + +(define_insn "*mulhisi3tt" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (mult:SI (ashiftrt:SI + (match_operand:SI 1 "s_register_operand" "r") + (const_int 16)) + (ashiftrt:SI + (match_operand:SI 2 "s_register_operand" "r") + (const_int 16))))] + "TARGET_ARM && arm_arch5e" + "smultt%?\\t%0, %1, %2" + [(set_attr "insn" "smulxy") + (set_attr "predicable" "yes")] ) (define_insn "*mulhisi3addsi" @@ -1338,9 +1311,10 @@ (match_operand:HI 2 "s_register_operand" "%r")) (sign_extend:SI (match_operand:HI 3 "s_register_operand" "r")))))] - "TARGET_ARM && arm_is_xscale" + "TARGET_ARM && arm_arch5e" "smlabb%?\\t%0, %2, %3, %1" - [(set_attr "type" "mult")] + [(set_attr "insn" "smlaxy") + (set_attr "predicable" "yes")] ) (define_insn "*mulhidi3adddi" @@ -1351,178 +1325,64 @@ (match_operand:HI 2 "s_register_operand" "%r")) (sign_extend:DI (match_operand:HI 3 "s_register_operand" "r")))))] - "TARGET_ARM && arm_is_xscale" + "TARGET_ARM && arm_arch5e" "smlalbb%?\\t%Q0, %R0, %2, %3" -[(set_attr "type" "mult")]) - -(define_insn "*arm_mulsf3" - [(set (match_operand:SF 0 "s_register_operand" "=f") - (mult:SF (match_operand:SF 1 "s_register_operand" "f") - (match_operand:SF 2 "fpu_rhs_operand" "fG")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "fml%?s\\t%0, %1, %2" - [(set_attr "type" "ffmul") - (set_attr "predicable" "yes")] -) - -(define_insn "*arm_muldf3" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (mult:DF (match_operand:DF 1 "s_register_operand" "f") - (match_operand:DF 2 "fpu_rhs_operand" "fG")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "muf%?d\\t%0, %1, %2" - [(set_attr "type" "fmul") - (set_attr "predicable" "yes")] -) - -(define_insn "*muldf_esfdf_df" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (mult:DF (float_extend:DF - (match_operand:SF 1 "s_register_operand" "f")) - (match_operand:DF 2 "fpu_rhs_operand" "fG")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "muf%?d\\t%0, %1, %2" - [(set_attr "type" "fmul") - (set_attr "predicable" "yes")] -) + [(set_attr "insn" "smlalxy") + (set_attr "predicable" "yes")]) -(define_insn "*muldf_df_esfdf" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (mult:DF (match_operand:DF 1 "s_register_operand" "f") - (float_extend:DF - (match_operand:SF 2 "s_register_operand" "f"))))] +(define_expand "mulsf3" + [(set (match_operand:SF 0 "s_register_operand" "") + (mult:SF (match_operand:SF 1 "s_register_operand" "") + (match_operand:SF 2 "arm_float_rhs_operand" "")))] "TARGET_ARM && TARGET_HARD_FLOAT" - "muf%?d\\t%0, %1, %2" - [(set_attr "type" "fmul") - (set_attr "predicable" "yes")] -) + " + if (TARGET_MAVERICK + && !cirrus_fp_register (operands[2], SFmode)) + operands[2] = force_reg (SFmode, operands[2]); +") -(define_insn "*muldf_esfdf_esfdf" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (mult:DF - (float_extend:DF (match_operand:SF 1 "s_register_operand" "f")) - (float_extend:DF (match_operand:SF 2 "s_register_operand" "f"))))] +(define_expand "muldf3" + [(set (match_operand:DF 0 "s_register_operand" "") + (mult:DF (match_operand:DF 1 "s_register_operand" "") + (match_operand:DF 2 "arm_float_rhs_operand" "")))] "TARGET_ARM && TARGET_HARD_FLOAT" - "muf%?d\\t%0, %1, %2" - [(set_attr "type" "fmul") - (set_attr "predicable" "yes")] -) + " + if (TARGET_MAVERICK + && !cirrus_fp_register (operands[2], DFmode)) + operands[2] = force_reg (DFmode, operands[2]); +") ;; Division insns -(define_insn "divsf3" - [(set (match_operand:SF 0 "s_register_operand" "=f,f") - (div:SF (match_operand:SF 1 "fpu_rhs_operand" "f,G") - (match_operand:SF 2 "fpu_rhs_operand" "fG,f")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "@ - fdv%?s\\t%0, %1, %2 - frd%?s\\t%0, %2, %1" - [(set_attr "type" "fdivs") - (set_attr "predicable" "yes")] -) - -(define_insn "divdf3" - [(set (match_operand:DF 0 "s_register_operand" "=f,f") - (div:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G") - (match_operand:DF 2 "fpu_rhs_operand" "fG,f")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "@ - dvf%?d\\t%0, %1, %2 - rdf%?d\\t%0, %2, %1" - [(set_attr "type" "fdivd") - (set_attr "predicable" "yes")] -) - -(define_insn "*divdf_esfdf_df" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (div:DF (float_extend:DF - (match_operand:SF 1 "s_register_operand" "f")) - (match_operand:DF 2 "fpu_rhs_operand" "fG")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "dvf%?d\\t%0, %1, %2" - [(set_attr "type" "fdivd") - (set_attr "predicable" "yes")] -) - -(define_insn "*divdf_df_esfdf" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (div:DF (match_operand:DF 1 "fpu_rhs_operand" "fG") - (float_extend:DF - (match_operand:SF 2 "s_register_operand" "f"))))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "rdf%?d\\t%0, %2, %1" - [(set_attr "type" "fdivd") - (set_attr "predicable" "yes")] -) +(define_expand "divsf3" + [(set (match_operand:SF 0 "s_register_operand" "") + (div:SF (match_operand:SF 1 "arm_float_rhs_operand" "") + (match_operand:SF 2 "arm_float_rhs_operand" "")))] + "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" + "") -(define_insn "*divdf_esfdf_esfdf" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (div:DF (float_extend:DF - (match_operand:SF 1 "s_register_operand" "f")) - (float_extend:DF - (match_operand:SF 2 "s_register_operand" "f"))))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "dvf%?d\\t%0, %1, %2" - [(set_attr "type" "fdivd") - (set_attr "predicable" "yes")] -) +(define_expand "divdf3" + [(set (match_operand:DF 0 "s_register_operand" "") + (div:DF (match_operand:DF 1 "arm_float_rhs_operand" "") + (match_operand:DF 2 "arm_float_rhs_operand" "")))] + "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" + "") ;; Modulo insns -(define_insn "modsf3" - [(set (match_operand:SF 0 "s_register_operand" "=f") - (mod:SF (match_operand:SF 1 "s_register_operand" "f") - (match_operand:SF 2 "fpu_rhs_operand" "fG")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "rmf%?s\\t%0, %1, %2" - [(set_attr "type" "fdivs") - (set_attr "predicable" "yes")] -) - -(define_insn "moddf3" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (mod:DF (match_operand:DF 1 "s_register_operand" "f") - (match_operand:DF 2 "fpu_rhs_operand" "fG")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "rmf%?d\\t%0, %1, %2" - [(set_attr "type" "fdivd") - (set_attr "predicable" "yes")] -) - -(define_insn "*moddf_esfdf_df" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (mod:DF (float_extend:DF - (match_operand:SF 1 "s_register_operand" "f")) - (match_operand:DF 2 "fpu_rhs_operand" "fG")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "rmf%?d\\t%0, %1, %2" - [(set_attr "type" "fdivd") - (set_attr "predicable" "yes")] -) - -(define_insn "*moddf_df_esfdf" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (mod:DF (match_operand:DF 1 "s_register_operand" "f") - (float_extend:DF - (match_operand:SF 2 "s_register_operand" "f"))))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "rmf%?d\\t%0, %1, %2" - [(set_attr "type" "fdivd") - (set_attr "predicable" "yes")] -) +(define_expand "modsf3" + [(set (match_operand:SF 0 "s_register_operand" "") + (mod:SF (match_operand:SF 1 "s_register_operand" "") + (match_operand:SF 2 "arm_float_rhs_operand" "")))] + "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA" + "") -(define_insn "*moddf_esfdf_esfdf" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (mod:DF (float_extend:DF - (match_operand:SF 1 "s_register_operand" "f")) - (float_extend:DF - (match_operand:SF 2 "s_register_operand" "f"))))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "rmf%?d\\t%0, %1, %2" - [(set_attr "type" "fdivd") - (set_attr "predicable" "yes")] -) +(define_expand "moddf3" + [(set (match_operand:DF 0 "s_register_operand" "") + (mod:DF (match_operand:DF 1 "s_register_operand" "") + (match_operand:DF 2 "arm_float_rhs_operand" "")))] + "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA" + "") ;; Boolean and,ior,xor insns @@ -1535,7 +1395,7 @@ (match_operator:DI 6 "logical_binary_operator" [(match_operand:DI 1 "s_register_operand" "") (match_operand:DI 2 "s_register_operand" "")]))] - "TARGET_ARM && reload_completed" + "TARGET_ARM && reload_completed && ! IS_IWMMXT_REGNUM (REGNO (operands[0]))" [(set (match_dup 0) (match_op_dup:SI 6 [(match_dup 1) (match_dup 2)])) (set (match_dup 3) (match_op_dup:SI 6 [(match_dup 4) (match_dup 5)]))] " @@ -1612,7 +1472,7 @@ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") (and:DI (match_operand:DI 1 "s_register_operand" "%0,r") (match_operand:DI 2 "s_register_operand" "r,r")))] - "TARGET_ARM" + "TARGET_ARM && ! TARGET_IWMMXT" "#" [(set_attr "length" "8")] ) @@ -1658,10 +1518,10 @@ { if (GET_CODE (operands[2]) == CONST_INT) { - arm_split_constant (AND, SImode, INTVAL (operands[2]), operands[0], - operands[1], - (no_new_pseudos - ? 0 : preserve_subexpressions_p ())); + arm_split_constant (AND, SImode, NULL_RTX, + INTVAL (operands[2]), operands[0], + operands[1], optimize && !no_new_pseudos); + DONE; } } @@ -1725,8 +1585,8 @@ || const_ok_for_arm (~INTVAL (operands[2])))" [(clobber (const_int 0))] " - arm_split_constant (AND, SImode, INTVAL (operands[2]), operands[0], - operands[1], 0); + arm_split_constant (AND, SImode, curr_insn, + INTVAL (operands[2]), operands[0], operands[1], 0); DONE; " [(set_attr "length" "4,4,16") @@ -1792,7 +1652,7 @@ [(set_attr "conds" "set")] ) -(define_insn "*ne_zeroextractsi" +(define_insn_and_split "*ne_zeroextractsi" [(set (match_operand:SI 0 "s_register_operand" "=r") (ne:SI (zero_extract:SI (match_operand:SI 1 "s_register_operand" "r") @@ -1805,67 +1665,245 @@ && INTVAL (operands[2]) > 0 && INTVAL (operands[2]) + (INTVAL (operands[3]) & 1) <= 8 && INTVAL (operands[2]) + INTVAL (operands[3]) <= 32)" - "* + "#" + "TARGET_ARM + && (INTVAL (operands[3]) >= 0 && INTVAL (operands[3]) < 32 + && INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) + (INTVAL (operands[3]) & 1) <= 8 + && INTVAL (operands[2]) + INTVAL (operands[3]) <= 32)" + [(parallel [(set (reg:CC_NOOV CC_REGNUM) + (compare:CC_NOOV (and:SI (match_dup 1) (match_dup 2)) + (const_int 0))) + (set (match_dup 0) (and:SI (match_dup 1) (match_dup 2)))]) + (set (match_dup 0) + (if_then_else:SI (eq (reg:CC_NOOV CC_REGNUM) (const_int 0)) + (match_dup 0) (const_int 1)))] + " operands[2] = GEN_INT (((1 << INTVAL (operands[2])) - 1) - << INTVAL (operands[3])); - output_asm_insn (\"ands\\t%0, %1, %2\", operands); - return \"movne\\t%0, #1\"; + << INTVAL (operands[3])); " [(set_attr "conds" "clob") (set_attr "length" "8")] ) -;;; ??? This pattern is bogus. If operand3 has bits outside the range -;;; represented by the bitfield, then this will produce incorrect results. -;;; Somewhere, the value needs to be truncated. On targets like the m68k, -;;; which have a real bit-field insert instruction, the truncation happens -;;; in the bit-field insert instruction itself. Since arm does not have a -;;; bit-field insert instruction, we would have to emit code here to truncate -;;; the value before we insert. This loses some of the advantage of having -;;; this insv pattern, so this pattern needs to be reevalutated. - -(define_expand "insv" - [(set (zero_extract:SI (match_operand:SI 0 "s_register_operand" "") - (match_operand:SI 1 "general_operand" "") - (match_operand:SI 2 "general_operand" "")) - (match_operand:SI 3 "reg_or_int_operand" ""))] +(define_insn_and_split "*ne_zeroextractsi_shifted" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (ne:SI (zero_extract:SI + (match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "const_int_operand" "n") + (const_int 0)) + (const_int 0))) + (clobber (reg:CC CC_REGNUM))] "TARGET_ARM" + "#" + "TARGET_ARM" + [(parallel [(set (reg:CC_NOOV CC_REGNUM) + (compare:CC_NOOV (ashift:SI (match_dup 1) (match_dup 2)) + (const_int 0))) + (set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2)))]) + (set (match_dup 0) + (if_then_else:SI (eq (reg:CC_NOOV CC_REGNUM) (const_int 0)) + (match_dup 0) (const_int 1)))] " - { - int start_bit = INTVAL (operands[2]); - int width = INTVAL (operands[1]); - HOST_WIDE_INT mask = (((HOST_WIDE_INT)1) << width) - 1; - rtx target, subtarget; - - target = operands[0]; - /* Avoid using a subreg as a subtarget, and avoid writing a paradoxical - subreg as the final target. */ - if (GET_CODE (target) == SUBREG) - { - subtarget = gen_reg_rtx (SImode); - if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (target))) - < GET_MODE_SIZE (SImode)) - target = SUBREG_REG (target); - } - else - subtarget = target; - - if (GET_CODE (operands[3]) == CONST_INT) - { - /* Since we are inserting a known constant, we may be able to - reduce the number of bits that we have to clear so that - the mask becomes simple. */ - /* ??? This code does not check to see if the new mask is actually - simpler. It may not be. */ - rtx op1 = gen_reg_rtx (SImode); - /* ??? Truncate operand3 to fit in the bitfield. See comment before - start of this pattern. */ - HOST_WIDE_INT op3_value = mask & INTVAL (operands[3]); - HOST_WIDE_INT mask2 = ((mask & ~op3_value) << start_bit); + operands[2] = GEN_INT (32 - INTVAL (operands[2])); + " + [(set_attr "conds" "clob") + (set_attr "length" "8")] +) - emit_insn (gen_andsi3 (op1, operands[0], GEN_INT (~mask2))); - emit_insn (gen_iorsi3 (subtarget, op1, - GEN_INT (op3_value << start_bit))); +(define_insn_and_split "*ite_ne_zeroextractsi" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI (ne (zero_extract:SI + (match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "const_int_operand" "n") + (match_operand:SI 3 "const_int_operand" "n")) + (const_int 0)) + (match_operand:SI 4 "arm_not_operand" "rIK") + (const_int 0))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_ARM + && (INTVAL (operands[3]) >= 0 && INTVAL (operands[3]) < 32 + && INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) + (INTVAL (operands[3]) & 1) <= 8 + && INTVAL (operands[2]) + INTVAL (operands[3]) <= 32) + && !reg_overlap_mentioned_p (operands[0], operands[4])" + "#" + "TARGET_ARM + && (INTVAL (operands[3]) >= 0 && INTVAL (operands[3]) < 32 + && INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) + (INTVAL (operands[3]) & 1) <= 8 + && INTVAL (operands[2]) + INTVAL (operands[3]) <= 32) + && !reg_overlap_mentioned_p (operands[0], operands[4])" + [(parallel [(set (reg:CC_NOOV CC_REGNUM) + (compare:CC_NOOV (and:SI (match_dup 1) (match_dup 2)) + (const_int 0))) + (set (match_dup 0) (and:SI (match_dup 1) (match_dup 2)))]) + (set (match_dup 0) + (if_then_else:SI (eq (reg:CC_NOOV CC_REGNUM) (const_int 0)) + (match_dup 0) (match_dup 4)))] + " + operands[2] = GEN_INT (((1 << INTVAL (operands[2])) - 1) + << INTVAL (operands[3])); + " + [(set_attr "conds" "clob") + (set_attr "length" "8")] +) + +(define_insn_and_split "*ite_ne_zeroextractsi_shifted" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI (ne (zero_extract:SI + (match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "const_int_operand" "n") + (const_int 0)) + (const_int 0)) + (match_operand:SI 3 "arm_not_operand" "rIK") + (const_int 0))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_ARM && !reg_overlap_mentioned_p (operands[0], operands[3])" + "#" + "TARGET_ARM && !reg_overlap_mentioned_p (operands[0], operands[3])" + [(parallel [(set (reg:CC_NOOV CC_REGNUM) + (compare:CC_NOOV (ashift:SI (match_dup 1) (match_dup 2)) + (const_int 0))) + (set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2)))]) + (set (match_dup 0) + (if_then_else:SI (eq (reg:CC_NOOV CC_REGNUM) (const_int 0)) + (match_dup 0) (match_dup 3)))] + " + operands[2] = GEN_INT (32 - INTVAL (operands[2])); + " + [(set_attr "conds" "clob") + (set_attr "length" "8")] +) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (zero_extract:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "const_int_operand" "") + (match_operand:SI 3 "const_int_operand" ""))) + (clobber (match_operand:SI 4 "s_register_operand" ""))] + "TARGET_THUMB" + [(set (match_dup 4) (ashift:SI (match_dup 1) (match_dup 2))) + (set (match_dup 0) (lshiftrt:SI (match_dup 4) (match_dup 3)))] + "{ + HOST_WIDE_INT temp = INTVAL (operands[2]); + + operands[2] = GEN_INT (32 - temp - INTVAL (operands[3])); + operands[3] = GEN_INT (32 - temp); + }" +) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (match_operator:SI 1 "shiftable_operator" + [(zero_extract:SI (match_operand:SI 2 "s_register_operand" "") + (match_operand:SI 3 "const_int_operand" "") + (match_operand:SI 4 "const_int_operand" "")) + (match_operand:SI 5 "s_register_operand" "")])) + (clobber (match_operand:SI 6 "s_register_operand" ""))] + "TARGET_ARM" + [(set (match_dup 6) (ashift:SI (match_dup 2) (match_dup 3))) + (set (match_dup 0) + (match_op_dup 1 + [(lshiftrt:SI (match_dup 6) (match_dup 4)) + (match_dup 5)]))] + "{ + HOST_WIDE_INT temp = INTVAL (operands[3]); + + operands[3] = GEN_INT (32 - temp - INTVAL (operands[4])); + operands[4] = GEN_INT (32 - temp); + }" +) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (sign_extract:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "const_int_operand" "") + (match_operand:SI 3 "const_int_operand" "")))] + "TARGET_THUMB" + [(set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2))) + (set (match_dup 0) (ashiftrt:SI (match_dup 0) (match_dup 3)))] + "{ + HOST_WIDE_INT temp = INTVAL (operands[2]); + + operands[2] = GEN_INT (32 - temp - INTVAL (operands[3])); + operands[3] = GEN_INT (32 - temp); + }" +) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (match_operator:SI 1 "shiftable_operator" + [(sign_extract:SI (match_operand:SI 2 "s_register_operand" "") + (match_operand:SI 3 "const_int_operand" "") + (match_operand:SI 4 "const_int_operand" "")) + (match_operand:SI 5 "s_register_operand" "")])) + (clobber (match_operand:SI 6 "s_register_operand" ""))] + "TARGET_ARM" + [(set (match_dup 6) (ashift:SI (match_dup 2) (match_dup 3))) + (set (match_dup 0) + (match_op_dup 1 + [(ashiftrt:SI (match_dup 6) (match_dup 4)) + (match_dup 5)]))] + "{ + HOST_WIDE_INT temp = INTVAL (operands[3]); + + operands[3] = GEN_INT (32 - temp - INTVAL (operands[4])); + operands[4] = GEN_INT (32 - temp); + }" +) + +;;; ??? This pattern is bogus. If operand3 has bits outside the range +;;; represented by the bitfield, then this will produce incorrect results. +;;; Somewhere, the value needs to be truncated. On targets like the m68k, +;;; which have a real bit-field insert instruction, the truncation happens +;;; in the bit-field insert instruction itself. Since arm does not have a +;;; bit-field insert instruction, we would have to emit code here to truncate +;;; the value before we insert. This loses some of the advantage of having +;;; this insv pattern, so this pattern needs to be reevalutated. + +(define_expand "insv" + [(set (zero_extract:SI (match_operand:SI 0 "s_register_operand" "") + (match_operand:SI 1 "general_operand" "") + (match_operand:SI 2 "general_operand" "")) + (match_operand:SI 3 "reg_or_int_operand" ""))] + "TARGET_ARM" + " + { + int start_bit = INTVAL (operands[2]); + int width = INTVAL (operands[1]); + HOST_WIDE_INT mask = (((HOST_WIDE_INT)1) << width) - 1; + rtx target, subtarget; + + target = operands[0]; + /* Avoid using a subreg as a subtarget, and avoid writing a paradoxical + subreg as the final target. */ + if (GET_CODE (target) == SUBREG) + { + subtarget = gen_reg_rtx (SImode); + if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (target))) + < GET_MODE_SIZE (SImode)) + target = SUBREG_REG (target); + } + else + subtarget = target; + + if (GET_CODE (operands[3]) == CONST_INT) + { + /* Since we are inserting a known constant, we may be able to + reduce the number of bits that we have to clear so that + the mask becomes simple. */ + /* ??? This code does not check to see if the new mask is actually + simpler. It may not be. */ + rtx op1 = gen_reg_rtx (SImode); + /* ??? Truncate operand3 to fit in the bitfield. See comment before + start of this pattern. */ + HOST_WIDE_INT op3_value = mask & INTVAL (operands[3]); + HOST_WIDE_INT mask2 = ((mask & ~op3_value) << start_bit); + + emit_insn (gen_andsi3 (op1, operands[0], GEN_INT (~mask2))); + emit_insn (gen_iorsi3 (subtarget, op1, + gen_int_mode (op3_value << start_bit, SImode))); } else if (start_bit == 0 && !(const_ok_for_arm (mask) @@ -1874,7 +1912,7 @@ /* A Trick, since we are setting the bottom bits in the word, we can shift operand[3] up, operand[0] down, OR them together and rotate the result back again. This takes 3 insns, and - the third might be mergable into another op. */ + the third might be mergeable into another op. */ /* The shift up copes with the possibility that operand[3] is wider than the bitfield. */ rtx op0 = gen_reg_rtx (SImode); @@ -1966,7 +2004,7 @@ (match_operand:DI 2 "s_register_operand" "0,r")))] "TARGET_ARM" "#" - "TARGET_ARM && reload_completed" + "TARGET_ARM && reload_completed && ! IS_IWMMXT_REGNUM (REGNO (operands[0]))" [(set (match_dup 0) (and:SI (not:SI (match_dup 1)) (match_dup 2))) (set (match_dup 3) (and:SI (not:SI (match_dup 4)) (match_dup 5)))] " @@ -2051,16 +2089,18 @@ ) (define_insn "andsi_not_shiftsi_si" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (and:SI (not:SI (match_operator:SI 4 "shift_operator" - [(match_operand:SI 2 "s_register_operand" "r") - (match_operand:SI 3 "arm_rhs_operand" "rM")])) - (match_operand:SI 1 "s_register_operand" "r")))] + [(set (match_operand:SI 0 "s_register_operand" "=r") + (and:SI (not:SI (match_operator:SI 4 "shift_operator" + [(match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 3 "arm_rhs_operand" "rM")])) + (match_operand:SI 1 "s_register_operand" "r")))] "TARGET_ARM" "bic%?\\t%0, %1, %2%S4" [(set_attr "predicable" "yes") (set_attr "shift" "2") - ] + (set (attr "type") (if_then_else (match_operand 3 "const_int_operand" "") + (const_string "alu_shift") + (const_string "alu_shift_reg")))] ) (define_insn "*andsi_notsi_si_compare0" @@ -2092,7 +2132,7 @@ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") (ior:DI (match_operand:DI 1 "s_register_operand" "%0,r") (match_operand:DI 2 "s_register_operand" "r,r")))] - "TARGET_ARM" + "TARGET_ARM && ! TARGET_IWMMXT" "#" [(set_attr "length" "8") (set_attr "predicable" "yes")] @@ -2132,10 +2172,9 @@ { if (TARGET_ARM) { - arm_split_constant (IOR, SImode, INTVAL (operands[2]), operands[0], - operands[1], - (no_new_pseudos - ? 0 : preserve_subexpressions_p ())); + arm_split_constant (IOR, SImode, NULL_RTX, + INTVAL (operands[2]), operands[0], operands[1], + optimize && !no_new_pseudos); DONE; } else /* TARGET_THUMB */ @@ -2157,8 +2196,8 @@ && !const_ok_for_arm (INTVAL (operands[2]))" [(clobber (const_int 0))] " - arm_split_constant (IOR, SImode, INTVAL (operands[2]), operands[0], - operands[1], 0); + arm_split_constant (IOR, SImode, curr_insn, + INTVAL (operands[2]), operands[0], operands[1], 0); DONE; " [(set_attr "length" "4,16") @@ -2176,8 +2215,8 @@ (define_peephole2 [(match_scratch:SI 3 "r") - (set (match_operand:SI 0 "s_register_operand" "") - (ior:SI (match_operand:SI 1 "s_register_operand" "") + (set (match_operand:SI 0 "arm_general_register_operand" "") + (ior:SI (match_operand:SI 1 "arm_general_register_operand" "") (match_operand:SI 2 "const_int_operand" "")))] "TARGET_ARM && !const_ok_for_arm (INTVAL (operands[2])) @@ -2214,7 +2253,7 @@ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") (xor:DI (match_operand:DI 1 "s_register_operand" "%0,r") (match_operand:DI 2 "s_register_operand" "r,r")))] - "TARGET_ARM" + "TARGET_ARM && !TARGET_IWMMXT" "#" [(set_attr "length" "8") (set_attr "predicable" "yes")] @@ -2323,6 +2362,109 @@ (set_attr "predicable" "yes")] ) +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (match_operator:SI 1 "logical_binary_operator" + [(zero_extract:SI (match_operand:SI 2 "s_register_operand" "") + (match_operand:SI 3 "const_int_operand" "") + (match_operand:SI 4 "const_int_operand" "")) + (match_operator:SI 9 "logical_binary_operator" + [(lshiftrt:SI (match_operand:SI 5 "s_register_operand" "") + (match_operand:SI 6 "const_int_operand" "")) + (match_operand:SI 7 "s_register_operand" "")])])) + (clobber (match_operand:SI 8 "s_register_operand" ""))] + "TARGET_ARM + && GET_CODE (operands[1]) == GET_CODE (operands[9]) + && INTVAL (operands[3]) == 32 - INTVAL (operands[6])" + [(set (match_dup 8) + (match_op_dup 1 + [(ashift:SI (match_dup 2) (match_dup 4)) + (match_dup 5)])) + (set (match_dup 0) + (match_op_dup 1 + [(lshiftrt:SI (match_dup 8) (match_dup 6)) + (match_dup 7)]))] + " + operands[4] = GEN_INT (32 - (INTVAL (operands[3]) + INTVAL (operands[4]))); +") + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (match_operator:SI 1 "logical_binary_operator" + [(match_operator:SI 9 "logical_binary_operator" + [(lshiftrt:SI (match_operand:SI 5 "s_register_operand" "") + (match_operand:SI 6 "const_int_operand" "")) + (match_operand:SI 7 "s_register_operand" "")]) + (zero_extract:SI (match_operand:SI 2 "s_register_operand" "") + (match_operand:SI 3 "const_int_operand" "") + (match_operand:SI 4 "const_int_operand" ""))])) + (clobber (match_operand:SI 8 "s_register_operand" ""))] + "TARGET_ARM + && GET_CODE (operands[1]) == GET_CODE (operands[9]) + && INTVAL (operands[3]) == 32 - INTVAL (operands[6])" + [(set (match_dup 8) + (match_op_dup 1 + [(ashift:SI (match_dup 2) (match_dup 4)) + (match_dup 5)])) + (set (match_dup 0) + (match_op_dup 1 + [(lshiftrt:SI (match_dup 8) (match_dup 6)) + (match_dup 7)]))] + " + operands[4] = GEN_INT (32 - (INTVAL (operands[3]) + INTVAL (operands[4]))); +") + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (match_operator:SI 1 "logical_binary_operator" + [(sign_extract:SI (match_operand:SI 2 "s_register_operand" "") + (match_operand:SI 3 "const_int_operand" "") + (match_operand:SI 4 "const_int_operand" "")) + (match_operator:SI 9 "logical_binary_operator" + [(ashiftrt:SI (match_operand:SI 5 "s_register_operand" "") + (match_operand:SI 6 "const_int_operand" "")) + (match_operand:SI 7 "s_register_operand" "")])])) + (clobber (match_operand:SI 8 "s_register_operand" ""))] + "TARGET_ARM + && GET_CODE (operands[1]) == GET_CODE (operands[9]) + && INTVAL (operands[3]) == 32 - INTVAL (operands[6])" + [(set (match_dup 8) + (match_op_dup 1 + [(ashift:SI (match_dup 2) (match_dup 4)) + (match_dup 5)])) + (set (match_dup 0) + (match_op_dup 1 + [(ashiftrt:SI (match_dup 8) (match_dup 6)) + (match_dup 7)]))] + " + operands[4] = GEN_INT (32 - (INTVAL (operands[3]) + INTVAL (operands[4]))); +") + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (match_operator:SI 1 "logical_binary_operator" + [(match_operator:SI 9 "logical_binary_operator" + [(ashiftrt:SI (match_operand:SI 5 "s_register_operand" "") + (match_operand:SI 6 "const_int_operand" "")) + (match_operand:SI 7 "s_register_operand" "")]) + (sign_extract:SI (match_operand:SI 2 "s_register_operand" "") + (match_operand:SI 3 "const_int_operand" "") + (match_operand:SI 4 "const_int_operand" ""))])) + (clobber (match_operand:SI 8 "s_register_operand" ""))] + "TARGET_ARM + && GET_CODE (operands[1]) == GET_CODE (operands[9]) + && INTVAL (operands[3]) == 32 - INTVAL (operands[6])" + [(set (match_dup 8) + (match_op_dup 1 + [(ashift:SI (match_dup 2) (match_dup 4)) + (match_dup 5)])) + (set (match_dup 0) + (match_op_dup 1 + [(ashiftrt:SI (match_dup 8) (match_dup 6)) + (match_dup 7)]))] + " + operands[4] = GEN_INT (32 - (INTVAL (operands[3]) + INTVAL (operands[4]))); +") ;; Minimum and maximum insns @@ -2391,8 +2533,8 @@ (clobber (reg:CC CC_REGNUM))] "TARGET_ARM" "* - operands[3] = gen_rtx (minmax_code (operands[3]), SImode, operands[1], - operands[2]); + operands[3] = gen_rtx_fmt_ee (minmax_code (operands[3]), SImode, + operands[1], operands[2]); output_asm_insn (\"cmp\\t%1, %2\", operands); output_asm_insn (\"str%d3\\t%1, %0\", operands); output_asm_insn (\"str%D3\\t%2, %0\", operands); @@ -2413,16 +2555,13 @@ (match_operand:SI 3 "arm_rhs_operand" "rI,rI")]) (match_operand:SI 1 "s_register_operand" "0,?r")])) (clobber (reg:CC CC_REGNUM))] - "TARGET_ARM - && (GET_CODE (operands[1]) != REG - || (REGNO(operands[1]) != FRAME_POINTER_REGNUM - && REGNO(operands[1]) != ARG_POINTER_REGNUM))" + "TARGET_ARM && !arm_eliminable_register (operands[1])" "* { enum rtx_code code = GET_CODE (operands[4]); - operands[5] = gen_rtx (minmax_code (operands[5]), SImode, operands[2], - operands[3]); + operands[5] = gen_rtx_fmt_ee (minmax_code (operands[5]), SImode, + operands[2], operands[3]); output_asm_insn (\"cmp\\t%2, %3\", operands); output_asm_insn (\"%i4%d5\\t%0, %1, %2\", operands); if (which_alternative != 0 || operands[3] != const0_rtx @@ -2437,6 +2576,41 @@ ;; Shift and rotation insns +(define_expand "ashldi3" + [(set (match_operand:DI 0 "s_register_operand" "") + (ashift:DI (match_operand:DI 1 "s_register_operand" "") + (match_operand:SI 2 "reg_or_int_operand" "")))] + "TARGET_ARM" + " + if (GET_CODE (operands[2]) == CONST_INT) + { + if ((HOST_WIDE_INT) INTVAL (operands[2]) == 1) + { + emit_insn (gen_arm_ashldi3_1bit (operands[0], operands[1])); + DONE; + } + /* Ideally we shouldn't fail here if we could know that operands[1] + ends up already living in an iwmmxt register. Otherwise it's + cheaper to have the alternate code being generated than moving + values to iwmmxt regs and back. */ + FAIL; + } + else if (!TARGET_REALLY_IWMMXT && !(TARGET_HARD_FLOAT && TARGET_MAVERICK)) + FAIL; + " +) + +(define_insn "arm_ashldi3_1bit" + [(set (match_operand:DI 0 "s_register_operand" "=&r,r") + (ashift:DI (match_operand:DI 1 "s_register_operand" "?r,0") + (const_int 1))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_ARM" + "movs\\t%Q0, %Q1, asl #1\;adc\\t%R0, %R1, %R1" + [(set_attr "conds" "clob") + (set_attr "length" "8")] +) + (define_expand "ashlsi3" [(set (match_operand:SI 0 "s_register_operand" "") (ashift:SI (match_operand:SI 1 "s_register_operand" "") @@ -2461,6 +2635,41 @@ [(set_attr "length" "2")] ) +(define_expand "ashrdi3" + [(set (match_operand:DI 0 "s_register_operand" "") + (ashiftrt:DI (match_operand:DI 1 "s_register_operand" "") + (match_operand:SI 2 "reg_or_int_operand" "")))] + "TARGET_ARM" + " + if (GET_CODE (operands[2]) == CONST_INT) + { + if ((HOST_WIDE_INT) INTVAL (operands[2]) == 1) + { + emit_insn (gen_arm_ashrdi3_1bit (operands[0], operands[1])); + DONE; + } + /* Ideally we shouldn't fail here if we could know that operands[1] + ends up already living in an iwmmxt register. Otherwise it's + cheaper to have the alternate code being generated than moving + values to iwmmxt regs and back. */ + FAIL; + } + else if (!TARGET_REALLY_IWMMXT) + FAIL; + " +) + +(define_insn "arm_ashrdi3_1bit" + [(set (match_operand:DI 0 "s_register_operand" "=&r,r") + (ashiftrt:DI (match_operand:DI 1 "s_register_operand" "?r,0") + (const_int 1))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_ARM" + "movs\\t%R0, %R1, asr #1\;mov\\t%Q0, %Q1, rrx" + [(set_attr "conds" "clob") + (set_attr "length" "8")] +) + (define_expand "ashrsi3" [(set (match_operand:SI 0 "s_register_operand" "") (ashiftrt:SI (match_operand:SI 1 "s_register_operand" "") @@ -2482,6 +2691,41 @@ [(set_attr "length" "2")] ) +(define_expand "lshrdi3" + [(set (match_operand:DI 0 "s_register_operand" "") + (lshiftrt:DI (match_operand:DI 1 "s_register_operand" "") + (match_operand:SI 2 "reg_or_int_operand" "")))] + "TARGET_ARM" + " + if (GET_CODE (operands[2]) == CONST_INT) + { + if ((HOST_WIDE_INT) INTVAL (operands[2]) == 1) + { + emit_insn (gen_arm_lshrdi3_1bit (operands[0], operands[1])); + DONE; + } + /* Ideally we shouldn't fail here if we could know that operands[1] + ends up already living in an iwmmxt register. Otherwise it's + cheaper to have the alternate code being generated than moving + values to iwmmxt regs and back. */ + FAIL; + } + else if (!TARGET_REALLY_IWMMXT) + FAIL; + " +) + +(define_insn "arm_lshrdi3_1bit" + [(set (match_operand:DI 0 "s_register_operand" "=&r,r") + (lshiftrt:DI (match_operand:DI 1 "s_register_operand" "?r,0") + (const_int 1))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_ARM" + "movs\\t%R0, %R1, lsr #1\;mov\\t%Q0, %Q1, rrx" + [(set_attr "conds" "clob") + (set_attr "length" "8")] +) + (define_expand "lshrsi3" [(set (match_operand:SI 0 "s_register_operand" "") (lshiftrt:SI (match_operand:SI 1 "s_register_operand" "") @@ -2552,19 +2796,6 @@ [(set_attr "length" "2")] ) -(define_expand "ashldi3" - [(set (match_operand:DI 0 "s_register_operand" "") - (ashift:DI (match_operand:DI 1 "general_operand" "") - (match_operand:SI 2 "general_operand" "")))] - "TARGET_ARM && (TARGET_CIRRUS)" - " - if (! s_register_operand (operands[1], DImode)) - operands[1] = copy_to_mode_reg (DImode, operands[1]); - if (! s_register_operand (operands[2], SImode)) - operands[2] = copy_to_mode_reg (SImode, operands[2]); - " -) - (define_insn "*arm_shiftsi3" [(set (match_operand:SI 0 "s_register_operand" "=r") (match_operator:SI 3 "shift_operator" @@ -2574,7 +2805,9 @@ "mov%?\\t%0, %1%S3" [(set_attr "predicable" "yes") (set_attr "shift" "1") - ] + (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "") + (const_string "alu_shift") + (const_string "alu_shift_reg")))] ) (define_insn "*shiftsi3_compare0" @@ -2589,7 +2822,9 @@ "mov%?s\\t%0, %1%S3" [(set_attr "conds" "set") (set_attr "shift" "1") - ] + (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "") + (const_string "alu_shift") + (const_string "alu_shift_reg")))] ) (define_insn "*shiftsi3_compare0_scratch" @@ -2602,8 +2837,7 @@ "TARGET_ARM" "mov%?s\\t%0, %1%S3" [(set_attr "conds" "set") - (set_attr "shift" "1") - ] + (set_attr "shift" "1")] ) (define_insn "*notsi_shiftsi" @@ -2615,7 +2849,9 @@ "mvn%?\\t%0, %1%S3" [(set_attr "predicable" "yes") (set_attr "shift" "1") - ] + (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "") + (const_string "alu_shift") + (const_string "alu_shift_reg")))] ) (define_insn "*notsi_shiftsi_compare0" @@ -2630,7 +2866,9 @@ "mvn%?s\\t%0, %1%S3" [(set_attr "conds" "set") (set_attr "shift" "1") - ] + (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "") + (const_string "alu_shift") + (const_string "alu_shift_reg")))] ) (define_insn "*not_shiftsi_compare0_scratch" @@ -2644,7 +2882,9 @@ "mvn%?s\\t%0, %1%S3" [(set_attr "conds" "set") (set_attr "shift" "1") - ] + (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "") + (const_string "alu_shift") + (const_string "alu_shift_reg")))] ) ;; We don't really have extzv, but defining this using shifts helps @@ -2738,39 +2978,32 @@ [(set_attr "length" "2")] ) -(define_insn "*arm_negsf2" - [(set (match_operand:SF 0 "s_register_operand" "=f") - (neg:SF (match_operand:SF 1 "s_register_operand" "f")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "mnf%?s\\t%0, %1" - [(set_attr "type" "ffarith") - (set_attr "predicable" "yes")] -) - -(define_insn "*arm_negdf2" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (neg:DF (match_operand:DF 1 "s_register_operand" "f")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "mnf%?d\\t%0, %1" - [(set_attr "type" "ffarith") - (set_attr "predicable" "yes")] +(define_expand "negsf2" + [(set (match_operand:SF 0 "s_register_operand" "") + (neg:SF (match_operand:SF 1 "s_register_operand" "")))] + "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" + "" ) -(define_insn "*negdf_esfdf" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (neg:DF (float_extend:DF - (match_operand:SF 1 "s_register_operand" "f"))))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "mnf%?d\\t%0, %1" - [(set_attr "type" "ffarith") - (set_attr "predicable" "yes")] -) +(define_expand "negdf2" + [(set (match_operand:DF 0 "s_register_operand" "") + (neg:DF (match_operand:DF 1 "s_register_operand" "")))] + "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" + "") ;; abssi2 doesn't really clobber the condition codes if a different register ;; is being set. To keep things simple, assume during rtl manipulations that ;; it does, but tell the final scan operator the truth. Similarly for ;; (neg (abs...)) +(define_expand "abssi2" + [(parallel + [(set (match_operand:SI 0 "s_register_operand" "") + (abs:SI (match_operand:SI 1 "s_register_operand" ""))) + (clobber (reg:CC CC_REGNUM))])] + "TARGET_ARM" + "") + (define_insn "*arm_abssi2" [(set (match_operand:SI 0 "s_register_operand" "=r,&r") (abs:SI (match_operand:SI 1 "s_register_operand" "0,r"))) @@ -2799,61 +3032,29 @@ (set_attr "length" "8")] ) -(define_insn "*arm_abssf2" - [(set (match_operand:SF 0 "s_register_operand" "=f") - (abs:SF (match_operand:SF 1 "s_register_operand" "f")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "abs%?s\\t%0, %1" - [(set_attr "type" "ffarith") - (set_attr "predicable" "yes")] -) - -(define_insn "*arm_absdf2" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (abs:DF (match_operand:DF 1 "s_register_operand" "f")))] +(define_expand "abssf2" + [(set (match_operand:SF 0 "s_register_operand" "") + (abs:SF (match_operand:SF 1 "s_register_operand" "")))] "TARGET_ARM && TARGET_HARD_FLOAT" - "abs%?d\\t%0, %1" - [(set_attr "type" "ffarith") - (set_attr "predicable" "yes")] -) - -(define_insn "*absdf_esfdf" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (abs:DF (float_extend:DF - (match_operand:SF 1 "s_register_operand" "f"))))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "abs%?d\\t%0, %1" - [(set_attr "type" "ffarith") - (set_attr "predicable" "yes")] -) + "") -(define_insn "sqrtsf2" - [(set (match_operand:SF 0 "s_register_operand" "=f") - (sqrt:SF (match_operand:SF 1 "s_register_operand" "f")))] +(define_expand "absdf2" + [(set (match_operand:DF 0 "s_register_operand" "") + (abs:DF (match_operand:DF 1 "s_register_operand" "")))] "TARGET_ARM && TARGET_HARD_FLOAT" - "sqt%?s\\t%0, %1" - [(set_attr "type" "float_em") - (set_attr "predicable" "yes")] -) + "") -(define_insn "sqrtdf2" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (sqrt:DF (match_operand:DF 1 "s_register_operand" "f")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "sqt%?d\\t%0, %1" - [(set_attr "type" "float_em") - (set_attr "predicable" "yes")] -) +(define_expand "sqrtsf2" + [(set (match_operand:SF 0 "s_register_operand" "") + (sqrt:SF (match_operand:SF 1 "s_register_operand" "")))] + "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" + "") -(define_insn "*sqrtdf_esfdf" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (sqrt:DF (float_extend:DF - (match_operand:SF 1 "s_register_operand" "f"))))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "sqt%?d\\t%0, %1" - [(set_attr "type" "float_em") - (set_attr "predicable" "yes")] -) +(define_expand "sqrtdf2" + [(set (match_operand:DF 0 "s_register_operand" "") + (sqrt:DF (match_operand:DF 1 "s_register_operand" "")))] + "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" + "") (define_insn_and_split "one_cmpldi2" [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") @@ -2920,52 +3121,68 @@ ;; Fixed <--> Floating conversion insns -(define_insn "*arm_floatsisf2" - [(set (match_operand:SF 0 "s_register_operand" "=f") - (float:SF (match_operand:SI 1 "s_register_operand" "r")))] +(define_expand "floatsisf2" + [(set (match_operand:SF 0 "s_register_operand" "") + (float:SF (match_operand:SI 1 "s_register_operand" "")))] "TARGET_ARM && TARGET_HARD_FLOAT" - "flt%?s\\t%0, %1" - [(set_attr "type" "r_2_f") - (set_attr "predicable" "yes")] -) + " + if (TARGET_MAVERICK) + { + emit_insn (gen_cirrus_floatsisf2 (operands[0], operands[1])); + DONE; + } +") -(define_insn "*arm_floatsidf2" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (float:DF (match_operand:SI 1 "s_register_operand" "r")))] +(define_expand "floatsidf2" + [(set (match_operand:DF 0 "s_register_operand" "") + (float:DF (match_operand:SI 1 "s_register_operand" "")))] "TARGET_ARM && TARGET_HARD_FLOAT" - "flt%?d\\t%0, %1" - [(set_attr "type" "r_2_f") - (set_attr "predicable" "yes")] -) + " + if (TARGET_MAVERICK) + { + emit_insn (gen_cirrus_floatsidf2 (operands[0], operands[1])); + DONE; + } +") -(define_insn "*arm_fix_truncsfsi2" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (fix:SI (match_operand:SF 1 "s_register_operand" "f")))] +(define_expand "fix_truncsfsi2" + [(set (match_operand:SI 0 "s_register_operand" "") + (fix:SI (fix:SF (match_operand:SF 1 "s_register_operand" ""))))] "TARGET_ARM && TARGET_HARD_FLOAT" - "fix%?z\\t%0, %1" - [(set_attr "type" "f_2_r") - (set_attr "predicable" "yes")] -) + " + if (TARGET_MAVERICK) + { + if (!cirrus_fp_register (operands[0], SImode)) + operands[0] = force_reg (SImode, operands[0]); + if (!cirrus_fp_register (operands[1], SFmode)) + operands[1] = force_reg (SFmode, operands[0]); + emit_insn (gen_cirrus_truncsfsi2 (operands[0], operands[1])); + DONE; + } +") -(define_insn "*arm_fix_truncdfsi2" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (fix:SI (match_operand:DF 1 "s_register_operand" "f")))] +(define_expand "fix_truncdfsi2" + [(set (match_operand:SI 0 "s_register_operand" "") + (fix:SI (fix:DF (match_operand:DF 1 "s_register_operand" ""))))] "TARGET_ARM && TARGET_HARD_FLOAT" - "fix%?z\\t%0, %1" - [(set_attr "type" "f_2_r") - (set_attr "predicable" "yes")] -) + " + if (TARGET_MAVERICK) + { + if (!cirrus_fp_register (operands[1], DFmode)) + operands[1] = force_reg (DFmode, operands[0]); + emit_insn (gen_cirrus_truncdfsi2 (operands[0], operands[1])); + DONE; + } +") ;; Truncation insns -(define_insn "*arm_truncdfsf2" - [(set (match_operand:SF 0 "s_register_operand" "=f") +(define_expand "truncdfsf2" + [(set (match_operand:SF 0 "s_register_operand" "") (float_truncate:SF - (match_operand:DF 1 "s_register_operand" "f")))] + (match_operand:DF 1 "s_register_operand" "")))] "TARGET_ARM && TARGET_HARD_FLOAT" - "mvf%?s\\t%0, %1" - [(set_attr "type" "ffarith") - (set_attr "predicable" "yes")] + "" ) ;; Zero and sign extension instructions. @@ -2993,7 +3210,7 @@ ldr%?b\\t%Q0, %1\;mov%?\\t%R0, #0" [(set_attr "length" "8") (set_attr "predicable" "yes") - (set_attr "type" "*,load") + (set_attr "type" "*,load_byte") (set_attr "pool_range" "*,4092") (set_attr "neg_pool_range" "*,4084")] ) @@ -3022,72 +3239,38 @@ "TARGET_EITHER" " { - if (TARGET_ARM) + if ((TARGET_THUMB || arm_arch4) && GET_CODE (operands[1]) == MEM) { - if (arm_arch4 && GET_CODE (operands[1]) == MEM) - { - /* Note: We do not have to worry about TARGET_MMU_TRAPS - here because the insn below will generate an LDRH instruction - rather than an LDR instruction, so we cannot get an unaligned - word access. */ - emit_insn (gen_rtx_SET (VOIDmode, operands[0], - gen_rtx_ZERO_EXTEND (SImode, - operands[1]))); - DONE; - } - if (TARGET_MMU_TRAPS && GET_CODE (operands[1]) == MEM) - { - emit_insn (gen_movhi_bytes (operands[0], operands[1])); - DONE; - } - if (!s_register_operand (operands[1], HImode)) - operands[1] = copy_to_mode_reg (HImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - operands[2] = gen_reg_rtx (SImode); + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_ZERO_EXTEND (SImode, operands[1]))); + DONE; } - else /* TARGET_THUMB */ - { - if (GET_CODE (operands[1]) == MEM) - { - rtx tmp; - tmp = gen_rtx_ZERO_EXTEND (SImode, operands[1]); - tmp = gen_rtx_SET (VOIDmode, operands[0], tmp); - emit_insn (tmp); - } - else - { - rtx ops[3]; - - if (!s_register_operand (operands[1], HImode)) - operands[1] = copy_to_mode_reg (HImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - operands[2] = gen_reg_rtx (SImode); - - ops[0] = operands[2]; - ops[1] = operands[1]; - ops[2] = GEN_INT (16); - - emit_insn (gen_rtx_SET (VOIDmode, ops[0], - gen_rtx_ASHIFT (SImode, ops[1], ops[2]))); + if (TARGET_ARM && GET_CODE (operands[1]) == MEM) + { + emit_insn (gen_movhi_bytes (operands[0], operands[1])); + DONE; + } - ops[0] = operands[0]; - ops[1] = operands[2]; - ops[2] = GEN_INT (16); + if (!s_register_operand (operands[1], HImode)) + operands[1] = copy_to_mode_reg (HImode, operands[1]); - emit_insn (gen_rtx_SET (VOIDmode, ops[0], - gen_rtx_LSHIFTRT (SImode, ops[1], - ops[2]))); - } - DONE; + if (arm_arch6) + { + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_ZERO_EXTEND (SImode, operands[1]))); + DONE; } + + operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_reg_rtx (SImode); }" ) (define_insn "*thumb_zero_extendhisi2" - [(set (match_operand:SI 0 "register_operand" "=l") - (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] - "TARGET_THUMB" + [(set (match_operand:SI 0 "register_operand" "=l") + (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] + "TARGET_THUMB && !arm_arch6" "* rtx mem = XEXP (operands[1], 0); @@ -3122,49 +3305,89 @@ return \"ldrh\\t%0, %1\"; " [(set_attr "length" "4") - (set_attr "type" "load") + (set_attr "type" "load_byte") (set_attr "pool_range" "60")] ) +(define_insn "*thumb_zero_extendhisi2_v6" + [(set (match_operand:SI 0 "register_operand" "=l,l") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "l,m")))] + "TARGET_THUMB && arm_arch6" + "* + rtx mem; + + if (which_alternative == 0) + return \"uxth\\t%0, %1\"; + + mem = XEXP (operands[1], 0); + + if (GET_CODE (mem) == CONST) + mem = XEXP (mem, 0); + + if (GET_CODE (mem) == LABEL_REF) + return \"ldr\\t%0, %1\"; + + if (GET_CODE (mem) == PLUS) + { + rtx a = XEXP (mem, 0); + rtx b = XEXP (mem, 1); + + /* This can happen due to bugs in reload. */ + if (GET_CODE (a) == REG && REGNO (a) == SP_REGNUM) + { + rtx ops[2]; + ops[0] = operands[0]; + ops[1] = a; + + output_asm_insn (\"mov %0, %1\", ops); + + XEXP (mem, 0) = operands[0]; + } + + else if ( GET_CODE (a) == LABEL_REF + && GET_CODE (b) == CONST_INT) + return \"ldr\\t%0, %1\"; + } + + return \"ldrh\\t%0, %1\"; + " + [(set_attr "length" "2,4") + (set_attr "type" "alu_shift,load_byte") + (set_attr "pool_range" "*,60")] +) + (define_insn "*arm_zero_extendhisi2" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] - "TARGET_ARM && arm_arch4" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] + "TARGET_ARM && arm_arch4 && !arm_arch6" "ldr%?h\\t%0, %1" - [(set_attr "type" "load") + [(set_attr "type" "load_byte") (set_attr "predicable" "yes") (set_attr "pool_range" "256") (set_attr "neg_pool_range" "244")] ) -(define_split - [(set (match_operand:SI 0 "s_register_operand" "") - (zero_extend:SI (match_operand:HI 1 "alignable_memory_operand" ""))) - (clobber (match_operand:SI 2 "s_register_operand" ""))] - "TARGET_ARM && (!arm_arch4)" - [(set (match_dup 2) (match_dup 1)) - (set (match_dup 0) (lshiftrt:SI (match_dup 2) (const_int 16)))] - " - if ((operands[1] = arm_gen_rotated_half_load (operands[1])) == NULL) - FAIL; - " +(define_insn "*arm_zero_extendhisi2_v6" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))] + "TARGET_ARM && arm_arch6" + "@ + uxth%?\\t%0, %1 + ldr%?h\\t%0, %1" + [(set_attr "type" "alu_shift,load_byte") + (set_attr "predicable" "yes") + (set_attr "pool_range" "*,256") + (set_attr "neg_pool_range" "*,244")] ) -(define_split - [(set (match_operand:SI 0 "s_register_operand" "") - (match_operator:SI 3 "shiftable_operator" - [(zero_extend:SI (match_operand:HI 1 "alignable_memory_operand" "")) - (match_operand:SI 4 "s_register_operand" "")])) - (clobber (match_operand:SI 2 "s_register_operand" ""))] - "TARGET_ARM && (!arm_arch4)" - [(set (match_dup 2) (match_dup 1)) - (set (match_dup 0) - (match_op_dup 3 - [(lshiftrt:SI (match_dup 2) (const_int 16)) (match_dup 4)]))] - " - if ((operands[1] = arm_gen_rotated_half_load (operands[1])) == NULL) - FAIL; - " +(define_insn "*arm_zero_extendhisi2addsi" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (zero_extend:SI (match_operand:HI 1 "s_register_operand" "r")) + (match_operand:SI 2 "s_register_operand" "r")))] + "TARGET_ARM && arm_arch6" + "uxtah%?\\t%0, %2, %1" + [(set_attr "type" "alu_shift") + (set_attr "predicable" "yes")] ) (define_expand "zero_extendqisi2" @@ -3172,7 +3395,7 @@ (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] "TARGET_EITHER" " - if (GET_CODE (operands[1]) != MEM) + if (!arm_arch6 && GET_CODE (operands[1]) != MEM) { if (TARGET_ARM) { @@ -3208,26 +3431,61 @@ ) (define_insn "*thumb_zero_extendqisi2" - [(set (match_operand:SI 0 "register_operand" "=l") - (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] - "TARGET_THUMB" + [(set (match_operand:SI 0 "register_operand" "=l") + (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] + "TARGET_THUMB && !arm_arch6" "ldrb\\t%0, %1" [(set_attr "length" "2") - (set_attr "type" "load") + (set_attr "type" "load_byte") (set_attr "pool_range" "32")] ) +(define_insn "*thumb_zero_extendqisi2_v6" + [(set (match_operand:SI 0 "register_operand" "=l,l") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "l,m")))] + "TARGET_THUMB && arm_arch6" + "@ + uxtb\\t%0, %1 + ldrb\\t%0, %1" + [(set_attr "length" "2,2") + (set_attr "type" "alu_shift,load_byte") + (set_attr "pool_range" "*,32")] +) + (define_insn "*arm_zero_extendqisi2" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] - "TARGET_ARM" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] + "TARGET_ARM && !arm_arch6" "ldr%?b\\t%0, %1\\t%@ zero_extendqisi2" - [(set_attr "type" "load") + [(set_attr "type" "load_byte") (set_attr "predicable" "yes") (set_attr "pool_range" "4096") (set_attr "neg_pool_range" "4084")] ) +(define_insn "*arm_zero_extendqisi2_v6" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] + "TARGET_ARM && arm_arch6" + "@ + uxtb%?\\t%0, %1 + ldr%?b\\t%0, %1\\t%@ zero_extendqisi2" + [(set_attr "type" "alu_shift,load_byte") + (set_attr "predicable" "yes") + (set_attr "pool_range" "*,4096") + (set_attr "neg_pool_range" "*,4084")] +) + +(define_insn "*arm_zero_extendqisi2addsi" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (zero_extend:SI (match_operand:QI 1 "s_register_operand" "r")) + (match_operand:SI 2 "s_register_operand" "r")))] + "TARGET_ARM && arm_arch6" + "uxtab%?\\t%0, %2, %1" + [(set_attr "predicable" "yes") + (set_attr "type" "alu_shift")] +) + (define_split [(set (match_operand:SI 0 "s_register_operand" "") (zero_extend:SI (subreg:QI (match_operand:SI 1 "" "") 0))) @@ -3257,55 +3515,51 @@ "TARGET_EITHER" " { - if (TARGET_ARM && arm_arch4 && GET_CODE (operands[1]) == MEM) + if (GET_CODE (operands[1]) == MEM) { - /* Note: We do not have to worry about TARGET_MMU_TRAPS - here because the insn below will generate an LDRH instruction - rather than an LDR instruction, so we cannot get an unaligned - word access. */ - emit_insn (gen_rtx_SET (VOIDmode, operands[0], - gen_rtx_SIGN_EXTEND (SImode, operands[1]))); - DONE; + if (TARGET_THUMB) + { + emit_insn (gen_thumb_extendhisi2 (operands[0], operands[1])); + DONE; + } + else if (arm_arch4) + { + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_SIGN_EXTEND (SImode, operands[1]))); + DONE; + } } - if (TARGET_ARM && TARGET_MMU_TRAPS && GET_CODE (operands[1]) == MEM) + if (TARGET_ARM && GET_CODE (operands[1]) == MEM) { emit_insn (gen_extendhisi2_mem (operands[0], operands[1])); DONE; } + if (!s_register_operand (operands[1], HImode)) operands[1] = copy_to_mode_reg (HImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - operands[2] = gen_reg_rtx (SImode); - if (TARGET_THUMB) + if (arm_arch6) { - rtx ops[3]; - - ops[0] = operands[2]; - ops[1] = operands[1]; - ops[2] = GEN_INT (16); - - emit_insn (gen_rtx_SET (VOIDmode, ops[0], - gen_rtx_ASHIFT (SImode, ops[1], ops[2]))); - - ops[0] = operands[0]; - ops[1] = operands[2]; - ops[2] = GEN_INT (16); - - emit_insn (gen_rtx_SET (VOIDmode, ops[0], - gen_rtx_ASHIFTRT (SImode, ops[1], ops[2]))); - + if (TARGET_THUMB) + emit_insn (gen_thumb_extendhisi2 (operands[0], operands[1])); + else + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_SIGN_EXTEND (SImode, operands[1]))); + DONE; } + + operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_reg_rtx (SImode); }" ) -(define_insn "*thumb_extendhisi2_insn" - [(set (match_operand:SI 0 "register_operand" "=l") - (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))) - (clobber (match_scratch:SI 2 "=&l"))] - "TARGET_THUMB" +(define_insn "thumb_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=l") + (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))) + (clobber (match_scratch:SI 2 "=&l"))] + "TARGET_THUMB && !arm_arch6" "* { rtx ops[4]; @@ -3342,12 +3596,8 @@ ops[1] = mem; ops[2] = const0_rtx; } - - if (GET_CODE (ops[1]) != REG) - { - debug_rtx (ops[1]); - abort (); - } + + gcc_assert (GET_CODE (ops[1]) == REG); ops[0] = operands[0]; ops[3] = operands[2]; @@ -3355,10 +3605,79 @@ return \"\"; }" [(set_attr "length" "4") - (set_attr "type" "load") + (set_attr "type" "load_byte") (set_attr "pool_range" "1020")] ) +;; We used to have an early-clobber on the scratch register here. +;; However, there's a bug somewhere in reload which means that this +;; can be partially ignored during spill allocation if the memory +;; address also needs reloading; this causes us to die later on when +;; we try to verify the operands. Fortunately, we don't really need +;; the early-clobber: we can always use operand 0 if operand 2 +;; overlaps the address. +(define_insn "*thumb_extendhisi2_insn_v6" + [(set (match_operand:SI 0 "register_operand" "=l,l") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "l,m"))) + (clobber (match_scratch:SI 2 "=X,l"))] + "TARGET_THUMB && arm_arch6" + "* + { + rtx ops[4]; + rtx mem; + + if (which_alternative == 0) + return \"sxth\\t%0, %1\"; + + mem = XEXP (operands[1], 0); + + /* This code used to try to use 'V', and fix the address only if it was + offsettable, but this fails for e.g. REG+48 because 48 is outside the + range of QImode offsets, and offsettable_address_p does a QImode + address check. */ + + if (GET_CODE (mem) == CONST) + mem = XEXP (mem, 0); + + if (GET_CODE (mem) == LABEL_REF) + return \"ldr\\t%0, %1\"; + + if (GET_CODE (mem) == PLUS) + { + rtx a = XEXP (mem, 0); + rtx b = XEXP (mem, 1); + + if (GET_CODE (a) == LABEL_REF + && GET_CODE (b) == CONST_INT) + return \"ldr\\t%0, %1\"; + + if (GET_CODE (b) == REG) + return \"ldrsh\\t%0, %1\"; + + ops[1] = a; + ops[2] = b; + } + else + { + ops[1] = mem; + ops[2] = const0_rtx; + } + + gcc_assert (GET_CODE (ops[1]) == REG); + + ops[0] = operands[0]; + if (reg_mentioned_p (operands[2], ops[1])) + ops[3] = ops[0]; + else + ops[3] = operands[2]; + output_asm_insn (\"mov\\t%3, %2\;ldrsh\\t%0, [%1, %3]\", ops); + return \"\"; + }" + [(set_attr "length" "2,4") + (set_attr "type" "alu_shift,load_byte") + (set_attr "pool_range" "*,1020")] +) + (define_expand "extendhisi2_mem" [(set (match_dup 2) (zero_extend:SI (match_operand:HI 1 "" ""))) (set (match_dup 3) @@ -3372,10 +3691,8 @@ rtx mem1, mem2; rtx addr = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); - mem1 = gen_rtx_MEM (QImode, addr); - MEM_COPY_ATTRIBUTES (mem1, operands[1]); - mem2 = gen_rtx_MEM (QImode, plus_constant (addr, 1)); - MEM_COPY_ATTRIBUTES (mem2, operands[1]); + mem1 = change_address (operands[1], QImode, addr); + mem2 = change_address (operands[1], QImode, plus_constant (addr, 1)); operands[0] = gen_lowpart (SImode, operands[0]); operands[1] = mem1; operands[2] = gen_reg_rtx (SImode); @@ -3396,44 +3713,36 @@ }" ) -(define_insn "*arm_extendhisi_insn" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))] - "TARGET_ARM && arm_arch4" +(define_insn "*arm_extendhisi2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))] + "TARGET_ARM && arm_arch4 && !arm_arch6" "ldr%?sh\\t%0, %1" - [(set_attr "type" "load") + [(set_attr "type" "load_byte") (set_attr "predicable" "yes") (set_attr "pool_range" "256") (set_attr "neg_pool_range" "244")] ) -(define_split - [(set (match_operand:SI 0 "s_register_operand" "") - (sign_extend:SI (match_operand:HI 1 "alignable_memory_operand" ""))) - (clobber (match_operand:SI 2 "s_register_operand" ""))] - "TARGET_ARM && (!arm_arch4)" - [(set (match_dup 2) (match_dup 1)) - (set (match_dup 0) (ashiftrt:SI (match_dup 2) (const_int 16)))] - " - if ((operands[1] = arm_gen_rotated_half_load (operands[1])) == NULL) - FAIL; - " +(define_insn "*arm_extendhisi2_v6" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))] + "TARGET_ARM && arm_arch6" + "@ + sxth%?\\t%0, %1 + ldr%?sh\\t%0, %1" + [(set_attr "type" "alu_shift,load_byte") + (set_attr "predicable" "yes") + (set_attr "pool_range" "*,256") + (set_attr "neg_pool_range" "*,244")] ) -(define_split - [(set (match_operand:SI 0 "s_register_operand" "") - (match_operator:SI 3 "shiftable_operator" - [(sign_extend:SI (match_operand:HI 1 "alignable_memory_operand" "")) - (match_operand:SI 4 "s_register_operand" "")])) - (clobber (match_operand:SI 2 "s_register_operand" ""))] - "TARGET_ARM && (!arm_arch4)" - [(set (match_dup 2) (match_dup 1)) - (set (match_dup 0) - (match_op_dup 3 - [(ashiftrt:SI (match_dup 2) (const_int 16)) (match_dup 4)]))] - "if ((operands[1] = arm_gen_rotated_half_load (operands[1])) == NULL) - FAIL; - " +(define_insn "*arm_extendhisi2addsi" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (sign_extend:SI (match_operand:HI 1 "s_register_operand" "r")) + (match_operand:SI 2 "s_register_operand" "r")))] + "TARGET_ARM && arm_arch6" + "sxtah%?\\t%0, %2, %1" ) (define_expand "extendqihi2" @@ -3461,59 +3770,17 @@ }" ) -; Rather than restricting all byte accesses to memory addresses that ldrsb -; can handle, we fix up the ones that ldrsb can't grok with a split. (define_insn "*extendqihi_insn" - [(set (match_operand:HI 0 "s_register_operand" "=r") - (sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))] + [(set (match_operand:HI 0 "s_register_operand" "=r") + (sign_extend:HI (match_operand:QI 1 "memory_operand" "Uq")))] "TARGET_ARM && arm_arch4" - "* - /* If the address is invalid, this will split the instruction into two. */ - if (bad_signed_byte_operand (operands[1], VOIDmode)) - return \"#\"; - return \"ldr%?sb\\t%0, %1\"; - " - [(set_attr "type" "load") + "ldr%?sb\\t%0, %1" + [(set_attr "type" "load_byte") (set_attr "predicable" "yes") - (set_attr "length" "8") (set_attr "pool_range" "256") (set_attr "neg_pool_range" "244")] ) -(define_split - [(set (match_operand:HI 0 "s_register_operand" "") - (sign_extend:HI (match_operand:QI 1 "bad_signed_byte_operand" "")))] - "TARGET_ARM && arm_arch4 && reload_completed" - [(set (match_dup 3) (match_dup 1)) - (set (match_dup 0) (sign_extend:HI (match_dup 2)))] - " - { - HOST_WIDE_INT offset; - - operands[3] = gen_rtx_REG (SImode, REGNO (operands[0])); - operands[2] = gen_rtx_MEM (QImode, operands[3]); - MEM_COPY_ATTRIBUTES (operands[2], operands[1]); - operands[1] = XEXP (operands[1], 0); - if (GET_CODE (operands[1]) == PLUS - && GET_CODE (XEXP (operands[1], 1)) == CONST_INT - && !(const_ok_for_arm (offset = INTVAL (XEXP (operands[1], 1))) - || const_ok_for_arm (-offset))) - { - HOST_WIDE_INT low = (offset > 0 - ? (offset & 0xff) : -((-offset) & 0xff)); - XEXP (operands[2], 0) = plus_constant (operands[3], low); - operands[1] = plus_constant (XEXP (operands[1], 0), offset - low); - } - /* Ensure the sum is in correct canonical form */ - else if (GET_CODE (operands[1]) == PLUS - && GET_CODE (XEXP (operands[1], 1)) != CONST_INT - && !s_register_operand (XEXP (operands[1], 1), VOIDmode)) - operands[1] = gen_rtx_PLUS (GET_MODE (operands[1]), - XEXP (operands[1], 1), - XEXP (operands[1], 0)); - }" -) - (define_expand "extendqisi2" [(set (match_dup 2) (ashift:SI (match_operand:QI 1 "general_operand" "") @@ -3524,97 +3791,66 @@ "TARGET_EITHER" " { - if (TARGET_ARM && arm_arch4 && GET_CODE (operands[1]) == MEM) + if ((TARGET_THUMB || arm_arch4) && GET_CODE (operands[1]) == MEM) { - emit_insn (gen_rtx_SET (VOIDmode, - operands[0], + emit_insn (gen_rtx_SET (VOIDmode, operands[0], gen_rtx_SIGN_EXTEND (SImode, operands[1]))); DONE; } + if (!s_register_operand (operands[1], QImode)) operands[1] = copy_to_mode_reg (QImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - operands[2] = gen_reg_rtx (SImode); - - if (TARGET_THUMB) - { - rtx ops[3]; - - ops[0] = operands[2]; - ops[1] = operands[1]; - ops[2] = GEN_INT (24); - - emit_insn (gen_rtx_SET (VOIDmode, ops[0], - gen_rtx_ASHIFT (SImode, ops[1], ops[2]))); - ops[0] = operands[0]; - ops[1] = operands[2]; - ops[2] = GEN_INT (24); - - emit_insn (gen_rtx_SET (VOIDmode, ops[0], - gen_rtx_ASHIFTRT (SImode, ops[1], ops[2]))); - - DONE; + if (arm_arch6) + { + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_SIGN_EXTEND (SImode, operands[1]))); + DONE; } + + operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_reg_rtx (SImode); }" ) -; Rather than restricting all byte accesses to memory addresses that ldrsb -; can handle, we fix up the ones that ldrsb can't grok with a split. -(define_insn "*arm_extendqisi_insn" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))] - "TARGET_ARM && arm_arch4" - "* - /* If the address is invalid, this will split the instruction into two. */ - if (bad_signed_byte_operand (operands[1], VOIDmode)) - return \"#\"; - return \"ldr%?sb\\t%0, %1\"; - " - [(set_attr "type" "load") +(define_insn "*arm_extendqisi" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (sign_extend:SI (match_operand:QI 1 "memory_operand" "Uq")))] + "TARGET_ARM && arm_arch4 && !arm_arch6" + "ldr%?sb\\t%0, %1" + [(set_attr "type" "load_byte") (set_attr "predicable" "yes") - (set_attr "length" "8") (set_attr "pool_range" "256") (set_attr "neg_pool_range" "244")] ) -(define_split - [(set (match_operand:SI 0 "s_register_operand" "") - (sign_extend:SI (match_operand:QI 1 "bad_signed_byte_operand" "")))] - "TARGET_ARM && arm_arch4 && reload_completed" - [(set (match_dup 0) (match_dup 1)) - (set (match_dup 0) (sign_extend:SI (match_dup 2)))] - " - { - HOST_WIDE_INT offset; - - operands[2] = gen_rtx_MEM (QImode, operands[0]); - MEM_COPY_ATTRIBUTES (operands[2], operands[1]); - operands[1] = XEXP (operands[1], 0); - if (GET_CODE (operands[1]) == PLUS - && GET_CODE (XEXP (operands[1], 1)) == CONST_INT - && !(const_ok_for_arm (offset = INTVAL (XEXP (operands[1], 1))) - || const_ok_for_arm (-offset))) - { - HOST_WIDE_INT low = (offset > 0 - ? (offset & 0xff) : -((-offset) & 0xff)); - XEXP (operands[2], 0) = plus_constant (operands[0], low); - operands[1] = plus_constant (XEXP (operands[1], 0), offset - low); - } - /* Ensure the sum is in correct canonical form */ - else if (GET_CODE (operands[1]) == PLUS - && GET_CODE (XEXP (operands[1], 1)) != CONST_INT - && !s_register_operand (XEXP (operands[1], 1), VOIDmode)) - operands[1] = gen_rtx_PLUS (GET_MODE (operands[1]), - XEXP (operands[1], 1), - XEXP (operands[1], 0)); - }" +(define_insn "*arm_extendqisi_v6" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,Uq")))] + "TARGET_ARM && arm_arch6" + "@ + sxtb%?\\t%0, %1 + ldr%?sb\\t%0, %1" + [(set_attr "type" "alu_shift,load_byte") + (set_attr "predicable" "yes") + (set_attr "pool_range" "*,256") + (set_attr "neg_pool_range" "*,244")] ) -(define_insn "*thumb_extendqisi2_insn" - [(set (match_operand:SI 0 "register_operand" "=l,l") - (sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))] - "TARGET_THUMB" +(define_insn "*arm_extendqisi2addsi" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (sign_extend:SI (match_operand:QI 1 "s_register_operand" "r")) + (match_operand:SI 2 "s_register_operand" "r")))] + "TARGET_ARM && arm_arch6" + "sxtab%?\\t%0, %2, %1" + [(set_attr "type" "alu_shift") + (set_attr "predicable" "yes")] +) + +(define_insn "*thumb_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=l,l") + (sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))] + "TARGET_THUMB && !arm_arch6" "* { rtx ops[3]; @@ -3656,10 +3892,9 @@ else output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); } - else if (GET_CODE (b) != REG) - abort (); else { + gcc_assert (GET_CODE (b) == REG); if (REGNO (b) == REGNO (ops[0])) { output_asm_insn (\"ldrb\\t%0, [%2, %1]\", ops); @@ -3686,17 +3921,95 @@ return \"\"; }" [(set_attr "length" "2,6") - (set_attr "type" "load,load") + (set_attr "type" "load_byte,load_byte") (set_attr "pool_range" "32,32")] ) -(define_insn "*arm_extendsfdf2" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (float_extend:DF (match_operand:SF 1 "s_register_operand" "f")))] +(define_insn "*thumb_extendqisi2_v6" + [(set (match_operand:SI 0 "register_operand" "=l,l,l") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "l,V,m")))] + "TARGET_THUMB && arm_arch6" + "* + { + rtx ops[3]; + rtx mem; + + if (which_alternative == 0) + return \"sxtb\\t%0, %1\"; + + mem = XEXP (operands[1], 0); + + if (GET_CODE (mem) == CONST) + mem = XEXP (mem, 0); + + if (GET_CODE (mem) == LABEL_REF) + return \"ldr\\t%0, %1\"; + + if (GET_CODE (mem) == PLUS + && GET_CODE (XEXP (mem, 0)) == LABEL_REF) + return \"ldr\\t%0, %1\"; + + if (which_alternative == 0) + return \"ldrsb\\t%0, %1\"; + + ops[0] = operands[0]; + + if (GET_CODE (mem) == PLUS) + { + rtx a = XEXP (mem, 0); + rtx b = XEXP (mem, 1); + + ops[1] = a; + ops[2] = b; + + if (GET_CODE (a) == REG) + { + if (GET_CODE (b) == REG) + output_asm_insn (\"ldrsb\\t%0, [%1, %2]\", ops); + else if (REGNO (a) == REGNO (ops[0])) + { + output_asm_insn (\"ldrb\\t%0, [%1, %2]\", ops); + output_asm_insn (\"sxtb\\t%0, %0\", ops); + } + else + output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); + } + else + { + gcc_assert (GET_CODE (b) == REG); + if (REGNO (b) == REGNO (ops[0])) + { + output_asm_insn (\"ldrb\\t%0, [%2, %1]\", ops); + output_asm_insn (\"sxtb\\t%0, %0\", ops); + } + else + output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); + } + } + else if (GET_CODE (mem) == REG && REGNO (ops[0]) == REGNO (mem)) + { + output_asm_insn (\"ldrb\\t%0, [%0, #0]\", ops); + output_asm_insn (\"sxtb\\t%0, %0\", ops); + } + else + { + ops[1] = mem; + ops[2] = const0_rtx; + + output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); + } + return \"\"; + }" + [(set_attr "length" "2,2,4") + (set_attr "type" "alu_shift,load_byte,load_byte") + (set_attr "pool_range" "*,32,32")] +) + +(define_expand "extendsfdf2" + [(set (match_operand:DF 0 "s_register_operand" "") + (float_extend:DF (match_operand:SF 1 "s_register_operand" "")))] "TARGET_ARM && TARGET_HARD_FLOAT" - "mvf%?d\\t%0, %1" - [(set_attr "type" "ffarith") - (set_attr "predicable" "yes")] + "" ) ;; Move insns (including loads and stores) @@ -3777,16 +4090,117 @@ ) (define_insn "*arm_movdi" - [(set (match_operand:DI 0 "nonimmediate_di_operand" "=r, r, o<>") - (match_operand:DI 1 "di_operand" "rIK,mi,r"))] - "TARGET_ARM && !TARGET_CIRRUS" + [(set (match_operand:DI 0 "nonimmediate_di_operand" "=r, r, r, r, m") + (match_operand:DI 1 "di_operand" "rDa,Db,Dc,mi,r"))] + "TARGET_ARM + && !(TARGET_HARD_FLOAT && (TARGET_MAVERICK || TARGET_VFP)) + && !TARGET_IWMMXT" "* - return (output_move_double (operands)); + switch (which_alternative) + { + case 0: + case 1: + case 2: + return \"#\"; + default: + return output_move_double (operands); + } + " + [(set_attr "length" "8,12,16,8,8") + (set_attr "type" "*,*,*,load2,store2") + (set_attr "pool_range" "*,*,*,1020,*") + (set_attr "neg_pool_range" "*,*,*,1008,*")] +) + +(define_split + [(set (match_operand:ANY64 0 "arm_general_register_operand" "") + (match_operand:ANY64 1 "const_double_operand" ""))] + "TARGET_ARM + && reload_completed + && (arm_const_double_inline_cost (operands[1]) + <= ((optimize_size || arm_ld_sched) ? 3 : 4))" + [(const_int 0)] + " + arm_split_constant (SET, SImode, curr_insn, + INTVAL (gen_lowpart (SImode, operands[1])), + gen_lowpart (SImode, operands[0]), NULL_RTX, 0); + arm_split_constant (SET, SImode, curr_insn, + INTVAL (gen_highpart_mode (SImode, + GET_MODE (operands[0]), + operands[1])), + gen_highpart (SImode, operands[0]), NULL_RTX, 0); + DONE; + " +) + +; If optimizing for size, or if we have load delay slots, then +; we want to split the constant into two separate operations. +; In both cases this may split a trivial part into a single data op +; leaving a single complex constant to load. We can also get longer +; offsets in a LDR which means we get better chances of sharing the pool +; entries. Finally, we can normally do a better job of scheduling +; LDR instructions than we can with LDM. +; This pattern will only match if the one above did not. +(define_split + [(set (match_operand:ANY64 0 "arm_general_register_operand" "") + (match_operand:ANY64 1 "const_double_operand" ""))] + "TARGET_ARM && reload_completed + && arm_const_double_by_parts (operands[1])" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 2) (match_dup 3))] + " + operands[2] = gen_highpart (SImode, operands[0]); + operands[3] = gen_highpart_mode (SImode, GET_MODE (operands[0]), + operands[1]); + operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = gen_lowpart (SImode, operands[1]); + " +) + +(define_split + [(set (match_operand:ANY64 0 "arm_general_register_operand" "") + (match_operand:ANY64 1 "arm_general_register_operand" ""))] + "TARGET_EITHER && reload_completed" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 2) (match_dup 3))] + " + operands[2] = gen_highpart (SImode, operands[0]); + operands[3] = gen_highpart (SImode, operands[1]); + operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = gen_lowpart (SImode, operands[1]); + + /* Handle a partial overlap. */ + if (rtx_equal_p (operands[0], operands[3])) + { + rtx tmp0 = operands[0]; + rtx tmp1 = operands[1]; + + operands[0] = operands[2]; + operands[1] = operands[3]; + operands[2] = tmp0; + operands[3] = tmp1; + } + " +) + +;; We can't actually do base+index doubleword loads if the index and +;; destination overlap. Split here so that we at least have chance to +;; schedule. +(define_split + [(set (match_operand:DI 0 "s_register_operand" "") + (mem:DI (plus:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "s_register_operand" ""))))] + "TARGET_LDRD + && reg_overlap_mentioned_p (operands[0], operands[1]) + && reg_overlap_mentioned_p (operands[0], operands[2])" + [(set (match_dup 4) + (plus:SI (match_dup 1) + (match_dup 2))) + (set (match_dup 0) + (mem:DI (match_dup 4)))] + " + operands[4] = gen_rtx_REG (SImode, REGNO(operands[0])); " - [(set_attr "length" "8") - (set_attr "type" "*,load,store2") - (set_attr "pool_range" "*,1020,*") - (set_attr "neg_pool_range" "*,1008,*")] ) ;;; ??? This should have alternatives for constants. @@ -3797,7 +4211,7 @@ [(set (match_operand:DI 0 "nonimmediate_operand" "=l,l,l,l,>,l, m,*r") (match_operand:DI 1 "general_operand" "l, I,J,>,l,mi,l,*r"))] "TARGET_THUMB - && !TARGET_CIRRUS + && !(TARGET_HARD_FLOAT && TARGET_MAVERICK) && ( register_operand (operands[0], DImode) || register_operand (operands[1], DImode))" "* @@ -3821,7 +4235,7 @@ case 5: return thumb_load_double_from_address (operands); case 6: - operands[2] = gen_rtx (MEM, SImode, + operands[2] = gen_rtx_MEM (SImode, plus_constant (XEXP (operands[0], 0), 4)); output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); return \"\"; @@ -3832,7 +4246,7 @@ } }" [(set_attr "length" "4,4,6,2,2,6,4,4") - (set_attr "type" "*,*,*,load,store2,load,store2,*") + (set_attr "type" "*,*,*,load2,store2,load2,store2,*") (set_attr "pool_range" "*,*,*,*,*,1020,*,*")] ) @@ -3843,21 +4257,21 @@ " if (TARGET_ARM) { - /* Everything except mem = const or mem = mem can be done easily */ + /* Everything except mem = const or mem = mem can be done easily. */ if (GET_CODE (operands[0]) == MEM) operands[1] = force_reg (SImode, operands[1]); - if (GET_CODE (operands[1]) == CONST_INT + if (arm_general_register_operand (operands[0], SImode) + && GET_CODE (operands[1]) == CONST_INT && !(const_ok_for_arm (INTVAL (operands[1])) || const_ok_for_arm (~INTVAL (operands[1])))) { - arm_split_constant (SET, SImode, INTVAL (operands[1]), operands[0], - NULL_RTX, - (no_new_pseudos ? 0 - : preserve_subexpressions_p ())); + arm_split_constant (SET, SImode, NULL_RTX, + INTVAL (operands[1]), operands[0], NULL_RTX, + optimize && !no_new_pseudos); DONE; } } - else /* TARGET_THUMB.... */ + else /* TARGET_THUMB.... */ { if (!no_new_pseudos) { @@ -3878,7 +4292,8 @@ (define_insn "*arm_movsi_insn" [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r, m") (match_operand:SI 1 "general_operand" "rI,K,mi,r"))] - "TARGET_ARM + "TARGET_ARM && ! TARGET_IWMMXT + && !(TARGET_HARD_FLOAT && TARGET_VFP) && ( register_operand (operands[0], SImode) || register_operand (operands[1], SImode))" "@ @@ -3886,22 +4301,22 @@ mvn%?\\t%0, #%B1 ldr%?\\t%0, %1 str%?\\t%1, %0" - [(set_attr "type" "*,*,load,store1") + [(set_attr "type" "*,*,load1,store1") (set_attr "predicable" "yes") (set_attr "pool_range" "*,*,4096,*") (set_attr "neg_pool_range" "*,*,4084,*")] ) (define_split - [(set (match_operand:SI 0 "s_register_operand" "") + [(set (match_operand:SI 0 "arm_general_register_operand" "") (match_operand:SI 1 "const_int_operand" ""))] "TARGET_ARM && (!(const_ok_for_arm (INTVAL (operands[1])) || const_ok_for_arm (~INTVAL (operands[1]))))" [(clobber (const_int 0))] " - arm_split_constant (SET, SImode, INTVAL (operands[1]), operands[0], - NULL_RTX, 0); + arm_split_constant (SET, SImode, NULL_RTX, + INTVAL (operands[1]), operands[0], NULL_RTX, 0); DONE; " ) @@ -3923,7 +4338,7 @@ str\\t%1, %0 mov\\t%0, %1" [(set_attr "length" "2,2,4,4,2,2,2,2,2") - (set_attr "type" "*,*,*,*,load,store1,load,store1,*") + (set_attr "type" "*,*,*,*,load1,store1,load1,store1,*") (set_attr "pool_range" "*,*,*,*,*,*,1020,*,*")] ) @@ -3975,7 +4390,7 @@ (unspec:SI [(match_operand:SI 1 "" "mX")] UNSPEC_PIC_SYM))] "TARGET_ARM && flag_pic" "ldr%?\\t%0, %1" - [(set_attr "type" "load") + [(set_attr "type" "load1") (set (attr "pool_range") (const_int 4096)) (set (attr "neg_pool_range") (const_int 4084))] ) @@ -3985,14 +4400,14 @@ (unspec:SI [(match_operand:SI 1 "" "mX")] UNSPEC_PIC_SYM))] "TARGET_THUMB && flag_pic" "ldr\\t%0, %1" - [(set_attr "type" "load") + [(set_attr "type" "load1") (set (attr "pool_range") (const_int 1024))] ) ;; This variant is used for AOF assembly, since it needs to mention the ;; pic register in the rtl. (define_expand "pic_load_addr_based" - [(set (match_operand:SI 0 "s_register_operand" "=r") + [(set (match_operand:SI 0 "s_register_operand" "") (unspec:SI [(match_operand 1 "" "") (match_dup 2)] UNSPEC_PIC_SYM))] "TARGET_ARM && flag_pic" "operands[2] = pic_offset_table_rtx;" @@ -4011,7 +4426,7 @@ output_asm_insn (\"ldr%?\\t%0, %a1\", operands); return \"\"; " - [(set_attr "type" "load") + [(set_attr "type" "load1") (set (attr "pool_range") (if_then_else (eq_attr "is_thumb" "yes") (const_int 1024) @@ -4024,7 +4439,9 @@ (define_insn "pic_add_dot_plus_four" [(set (match_operand:SI 0 "register_operand" "+r") - (plus:SI (match_dup 0) (const (plus:SI (pc) (const_int 4))))) + (unspec:SI [(plus:SI (match_dup 0) + (const (plus:SI (pc) (const_int 4))))] + UNSPEC_PIC_BASE)) (use (label_ref (match_operand 1 "" "")))] "TARGET_THUMB && flag_pic" "* @@ -4037,7 +4454,9 @@ (define_insn "pic_add_dot_plus_eight" [(set (match_operand:SI 0 "register_operand" "+r") - (plus:SI (match_dup 0) (const (plus:SI (pc) (const_int 8))))) + (unspec:SI [(plus:SI (match_dup 0) + (const (plus:SI (pc) (const_int 8))))] + UNSPEC_PIC_BASE)) (use (label_ref (match_operand 1 "" "")))] "TARGET_ARM && flag_pic" "* @@ -4053,7 +4472,9 @@ "flag_pic" " { - arm_finalize_pic (0); + /* r3 is clobbered by set/longjmp, so we can use it as a scratch + register. */ + arm_load_pic_register (3); DONE; }") @@ -4089,7 +4510,7 @@ (set (match_dup 2) (ashiftrt:SI (match_operand 0 "" "") (const_int 8))) ;; store the high byte - (set (match_dup 4) (subreg:QI (match_dup 2) 0))] ;explicit subreg safe + (set (match_dup 4) (match_dup 5))] "TARGET_ARM" " { @@ -4105,7 +4526,8 @@ operands[1] = adjust_address (operands[1], QImode, 0); operands[3] = gen_lowpart (QImode, operands[0]); operands[0] = gen_lowpart (SImode, operands[0]); - operands[2] = gen_reg_rtx (SImode); + operands[2] = gen_reg_rtx (SImode); + operands[5] = gen_lowpart (QImode, operands[2]); }" ) @@ -4113,7 +4535,7 @@ [(set (match_dup 4) (match_dup 3)) (set (match_dup 2) (ashiftrt:SI (match_operand 0 "" "") (const_int 8))) - (set (match_operand 1 "" "") (subreg:QI (match_dup 2) 3))] + (set (match_operand 1 "" "") (match_dup 5))] "TARGET_ARM" " { @@ -4130,13 +4552,14 @@ operands[3] = gen_lowpart (QImode, operands[0]); operands[0] = gen_lowpart (SImode, operands[0]); operands[2] = gen_reg_rtx (SImode); + operands[5] = gen_lowpart (QImode, operands[2]); }" ) ;; Subroutine to store a half word integer constant into memory. (define_expand "storeinthi" [(set (match_operand 0 "" "") - (subreg:QI (match_operand 1 "" "") 0)) + (match_operand 1 "" "")) (set (match_dup 3) (match_dup 2))] "TARGET_ARM" " @@ -4177,6 +4600,7 @@ operands[3] = adjust_address (op0, QImode, 1); operands[0] = adjust_address (operands[0], QImode, 0); operands[2] = gen_lowpart (QImode, operands[2]); + operands[1] = gen_lowpart (QImode, operands[1]); }" ) @@ -4241,7 +4665,7 @@ emit_insn (gen_movsi (reg, GEN_INT (val))); operands[1] = gen_lowpart (HImode, reg); } - else if (arm_arch4 && !no_new_pseudos && optimize > 0 + else if (arm_arch4 && optimize && !no_new_pseudos && GET_CODE (operands[1]) == MEM) { rtx reg = gen_reg_rtx (SImode); @@ -4251,101 +4675,50 @@ } else if (!arm_arch4) { - /* Note: We do not have to worry about TARGET_MMU_TRAPS - for v4 and up architectures because LDRH instructions will - be used to access the HI values, and these cannot generate - unaligned word access faults in the MMU. */ if (GET_CODE (operands[1]) == MEM) { - if (TARGET_MMU_TRAPS) - { - rtx base; - rtx offset = const0_rtx; - rtx reg = gen_reg_rtx (SImode); - - if ((GET_CODE (base = XEXP (operands[1], 0)) == REG - || (GET_CODE (base) == PLUS - && (GET_CODE (offset = XEXP (base, 1)) - == CONST_INT) - && ((INTVAL(offset) & 1) != 1) - && GET_CODE (base = XEXP (base, 0)) == REG)) - && REGNO_POINTER_ALIGN (REGNO (base)) >= 32) - { - HOST_WIDE_INT new_offset = INTVAL (offset) & ~3; - rtx new; - - new = gen_rtx_MEM (SImode, - plus_constant (base, new_offset)); - MEM_COPY_ATTRIBUTES (new, operands[1]); - emit_insn (gen_movsi (reg, new)); - if (((INTVAL (offset) & 2) != 0) - ^ (BYTES_BIG_ENDIAN ? 1 : 0)) - { - rtx reg2 = gen_reg_rtx (SImode); - - emit_insn (gen_lshrsi3 (reg2, reg, - GEN_INT (16))); - reg = reg2; - } - } - else - emit_insn (gen_movhi_bytes (reg, operands[1])); - - operands[1] = gen_lowpart (HImode, reg); - } - else if (BYTES_BIG_ENDIAN) + rtx base; + rtx offset = const0_rtx; + rtx reg = gen_reg_rtx (SImode); + + if ((GET_CODE (base = XEXP (operands[1], 0)) == REG + || (GET_CODE (base) == PLUS + && (GET_CODE (offset = XEXP (base, 1)) + == CONST_INT) + && ((INTVAL(offset) & 1) != 1) + && GET_CODE (base = XEXP (base, 0)) == REG)) + && REGNO_POINTER_ALIGN (REGNO (base)) >= 32) { - rtx base; - rtx offset = const0_rtx; - - if ((GET_CODE (base = XEXP (operands[1], 0)) == REG - || (GET_CODE (base) == PLUS - && (GET_CODE (offset = XEXP (base, 1)) - == CONST_INT) - && GET_CODE (base = XEXP (base, 0)) == REG)) - && REGNO_POINTER_ALIGN (REGNO (base)) >= 32) - { - rtx reg = gen_reg_rtx (SImode); - rtx new; - - if ((INTVAL (offset) & 2) == 2) - { - HOST_WIDE_INT new_offset = INTVAL (offset) ^ 2; - new = gen_rtx_MEM (SImode, - plus_constant (base, - new_offset)); - MEM_COPY_ATTRIBUTES (new, operands[1]); - emit_insn (gen_movsi (reg, new)); - } - else - { - new = gen_rtx_MEM (SImode, - XEXP (operands[1], 0)); - MEM_COPY_ATTRIBUTES (new, operands[1]); - emit_insn (gen_rotated_loadsi (reg, new)); - } - - operands[1] = gen_lowpart (HImode, reg); - } - else - { - emit_insn (gen_movhi_bigend (operands[0], - operands[1])); - DONE; - } + rtx new; + + new = widen_memory_access (operands[1], SImode, + ((INTVAL (offset) & ~3) + - INTVAL (offset))); + emit_insn (gen_movsi (reg, new)); + if (((INTVAL (offset) & 2) != 0) + ^ (BYTES_BIG_ENDIAN ? 1 : 0)) + { + rtx reg2 = gen_reg_rtx (SImode); + + emit_insn (gen_lshrsi3 (reg2, reg, GEN_INT (16))); + reg = reg2; + } } + else + emit_insn (gen_movhi_bytes (reg, operands[1])); + + operands[1] = gen_lowpart (HImode, reg); } } } - /* Handle loading a large integer during reload */ + /* Handle loading a large integer during reload. */ else if (GET_CODE (operands[1]) == CONST_INT && !const_ok_for_arm (INTVAL (operands[1])) && !const_ok_for_arm (~INTVAL (operands[1]))) { /* Writing a constant to memory needs a scratch, which should be handled with SECONDARY_RELOADs. */ - if (GET_CODE (operands[0]) != REG) - abort (); + gcc_assert (GET_CODE (operands[0]) == REG); operands[0] = gen_rtx_SUBREG (SImode, operands[0], 0); emit_insn (gen_movsi (operands[0], operands[1])); @@ -4356,8 +4729,13 @@ { if (!no_new_pseudos) { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (HImode, operands[1]); + if (GET_CODE (operands[1]) == CONST_INT) + { + rtx reg = gen_reg_rtx (SImode); + + emit_insn (gen_movsi (reg, operands[1])); + operands[1] = gen_lowpart (HImode, reg); + } /* ??? We shouldn't really get invalid addresses here, but this can happen if we are passed a SP (never OK for HImode/QImode) or @@ -4380,17 +4758,28 @@ operands[1] = replace_equiv_address (operands[1], copy_to_reg (XEXP (operands[1], 0))); + + if (GET_CODE (operands[1]) == MEM && optimize > 0) + { + rtx reg = gen_reg_rtx (SImode); + + emit_insn (gen_zero_extendhisi2 (reg, operands[1])); + operands[1] = gen_lowpart (HImode, reg); + } + + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (HImode, operands[1]); } - /* Handle loading a large integer during reload */ else if (GET_CODE (operands[1]) == CONST_INT && !CONST_OK_FOR_THUMB_LETTER (INTVAL (operands[1]), 'I')) { + /* Handle loading a large integer during reload. */ + /* Writing a constant to memory needs a scratch, which should be handled with SECONDARY_RELOADs. */ - if (GET_CODE (operands[0]) != REG) - abort (); + gcc_assert (GET_CODE (operands[0]) == REG); - operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); + operands[0] = gen_rtx_SUBREG (SImode, operands[0], 0); emit_insn (gen_movsi (operands[0], operands[1])); DONE; } @@ -4399,8 +4788,8 @@ ) (define_insn "*thumb_movhi_insn" - [(set (match_operand:HI 0 "nonimmediate_operand" "=l,l, m,*r,*h,l") - (match_operand:HI 1 "general_operand" "l,mn,l,*h,*r,I"))] + [(set (match_operand:HI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") + (match_operand:HI 1 "general_operand" "l,m,l,*h,*r,I"))] "TARGET_THUMB && ( register_operand (operands[0], HImode) || register_operand (operands[1], HImode))" @@ -4412,7 +4801,7 @@ case 3: return \"mov %0, %1\"; case 4: return \"mov %0, %1\"; case 5: return \"mov %0, %1\"; - default: abort (); + default: gcc_unreachable (); case 1: /* The stack pointer can end up being taken as an index register. Catch this case here and deal with it. */ @@ -4432,29 +4821,10 @@ return \"ldrh %0, %1\"; }" [(set_attr "length" "2,4,2,2,2,2") - (set_attr "type" "*,load,store1,*,*,*") - (set_attr "pool_range" "*,64,*,*,*,*")] + (set_attr "type" "*,load1,store1,*,*,*")] ) -(define_insn "rotated_loadsi" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (rotate:SI (match_operand:SI 1 "offsettable_memory_operand" "o") - (const_int 16)))] - "TARGET_ARM && (!TARGET_MMU_TRAPS)" - "* - { - rtx ops[2]; - - ops[0] = operands[0]; - ops[1] = gen_rtx_MEM (SImode, plus_constant (XEXP (operands[1], 0), 2)); - output_asm_insn (\"ldr%?\\t%0, %1\\t%@ load-rotate\", ops); - return \"\"; - }" - [(set_attr "type" "load") - (set_attr "predicable" "yes")] -) - (define_expand "movhi_bytes" [(set (match_dup 2) (zero_extend:SI (match_operand:HI 1 "" ""))) (set (match_dup 3) @@ -4467,10 +4837,8 @@ rtx mem1, mem2; rtx addr = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); - mem1 = gen_rtx_MEM (QImode, addr); - MEM_COPY_ATTRIBUTES (mem1, operands[1]); - mem2 = gen_rtx_MEM (QImode, plus_constant (addr, 1)); - MEM_COPY_ATTRIBUTES (mem2, operands[1]); + mem1 = change_address (operands[1], QImode, addr); + mem2 = change_address (operands[1], QImode, plus_constant (addr, 1)); operands[0] = gen_lowpart (SImode, operands[0]); operands[1] = mem1; operands[2] = gen_reg_rtx (SImode); @@ -4497,11 +4865,12 @@ (set (match_dup 3) (ashiftrt:SI (match_dup 2) (const_int 16))) (set (match_operand:HI 0 "s_register_operand" "") - (subreg:HI (match_dup 3) 0))] + (match_dup 4))] "TARGET_ARM" " operands[2] = gen_reg_rtx (SImode); operands[3] = gen_reg_rtx (SImode); + operands[4] = gen_lowpart (HImode, operands[3]); " ) @@ -4517,86 +4886,39 @@ "@ mov%?\\t%0, %1\\t%@ movhi mvn%?\\t%0, #%B1\\t%@ movhi - str%?h\\t%1, %0\\t%@ movhi + str%?h\\t%1, %0\\t%@ movhi ldr%?h\\t%0, %1\\t%@ movhi" - [(set_attr "type" "*,*,store1,load") + [(set_attr "type" "*,*,store1,load1") (set_attr "predicable" "yes") (set_attr "pool_range" "*,*,*,256") (set_attr "neg_pool_range" "*,*,*,244")] ) -(define_insn "*movhi_insn_littleend" - [(set (match_operand:HI 0 "s_register_operand" "=r,r,r") - (match_operand:HI 1 "general_operand" "rI,K,m"))] - "TARGET_ARM - && !arm_arch4 - && !BYTES_BIG_ENDIAN - && !TARGET_MMU_TRAPS - && (GET_CODE (operands[1]) != CONST_INT - || const_ok_for_arm (INTVAL (operands[1])) - || const_ok_for_arm (~INTVAL (operands[1])))" - "@ - mov%?\\t%0, %1\\t%@ movhi - mvn%?\\t%0, #%B1\\t%@ movhi - ldr%?\\t%0, %1\\t%@ movhi" - [(set_attr "type" "*,*,load") - (set_attr "predicable" "yes") - (set_attr "pool_range" "4096") - (set_attr "neg_pool_range" "4084")] -) - -(define_insn "*movhi_insn_bigend" - [(set (match_operand:HI 0 "s_register_operand" "=r,r,r") - (match_operand:HI 1 "general_operand" "rI,K,m"))] - "TARGET_ARM - && !arm_arch4 - && BYTES_BIG_ENDIAN - && !TARGET_MMU_TRAPS - && (GET_CODE (operands[1]) != CONST_INT - || const_ok_for_arm (INTVAL (operands[1])) - || const_ok_for_arm (~INTVAL (operands[1])))" - "@ - mov%?\\t%0, %1\\t%@ movhi - mvn%?\\t%0, #%B1\\t%@ movhi - ldr%?\\t%0, %1\\t%@ movhi_bigend\;mov%?\\t%0, %0, asr #16" - [(set_attr "type" "*,*,load") - (set_attr "predicable" "yes") - (set_attr "length" "4,4,8") - (set_attr "pool_range" "*,*,4092") - (set_attr "neg_pool_range" "*,*,4084")] -) - -(define_insn "*loadhi_si_bigend" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (rotate:SI (subreg:SI (match_operand:HI 1 "memory_operand" "m") 0) - (const_int 16)))] - "TARGET_ARM - && BYTES_BIG_ENDIAN - && !TARGET_MMU_TRAPS" - "ldr%?\\t%0, %1\\t%@ movhi_bigend" - [(set_attr "type" "load") - (set_attr "predicable" "yes") - (set_attr "pool_range" "4096") - (set_attr "neg_pool_range" "4084")] -) - (define_insn "*movhi_bytes" [(set (match_operand:HI 0 "s_register_operand" "=r,r") (match_operand:HI 1 "arm_rhs_operand" "rI,K"))] - "TARGET_ARM && TARGET_MMU_TRAPS" + "TARGET_ARM" "@ mov%?\\t%0, %1\\t%@ movhi mvn%?\\t%0, #%B1\\t%@ movhi" [(set_attr "predicable" "yes")] ) -(define_insn "thumb_movhi_clobber" - [(set (match_operand:HI 0 "memory_operand" "=m") - (match_operand:HI 1 "register_operand" "l")) - (clobber (match_operand:SI 2 "register_operand" "=&l"))] +(define_expand "thumb_movhi_clobber" + [(set (match_operand:HI 0 "memory_operand" "") + (match_operand:HI 1 "register_operand" "")) + (clobber (match_operand:DI 2 "register_operand" ""))] "TARGET_THUMB" - "* - abort ();" + " + if (strict_memory_address_p (HImode, XEXP (operands[0], 0)) + && REGNO (operands[1]) <= LAST_LO_REGNUM) + { + emit_insn (gen_movhi (operands[0], operands[1])); + DONE; + } + /* XXX Fixme, need to handle other cases here as well. */ + gcc_unreachable (); + " ) ;; We use a DImode scratch because we may occasionally need an additional @@ -4619,7 +4941,7 @@ [(parallel [(match_operand:HI 0 "s_register_operand" "=r") (match_operand:HI 1 "arm_reload_memory_operand" "o") (match_operand:DI 2 "s_register_operand" "=&r")])] - "TARGET_THUMB || (TARGET_ARM && TARGET_MMU_TRAPS)" + "TARGET_EITHER" " if (TARGET_ARM) arm_reload_in_hi (operands); @@ -4633,37 +4955,20 @@ (match_operand:QI 1 "general_operand" ""))] "TARGET_EITHER" " - if (TARGET_ARM) - { - /* Everything except mem = const or mem = mem can be done easily */ - - if (!no_new_pseudos) - { - if (GET_CODE (operands[1]) == CONST_INT) - { - rtx reg = gen_reg_rtx (SImode); - - emit_insn (gen_movsi (reg, operands[1])); - operands[1] = gen_lowpart (QImode, reg); - } - if (GET_CODE (operands[1]) == MEM && optimize > 0) - { - rtx reg = gen_reg_rtx (SImode); + /* Everything except mem = const or mem = mem can be done easily */ - emit_insn (gen_zero_extendqisi2 (reg, operands[1])); - operands[1] = gen_lowpart (QImode, reg); - } - if (GET_CODE (operands[0]) == MEM) - operands[1] = force_reg (QImode, operands[1]); - } - } - else /* TARGET_THUMB */ + if (!no_new_pseudos) { - if (!no_new_pseudos) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (QImode, operands[1]); + if (GET_CODE (operands[1]) == CONST_INT) + { + rtx reg = gen_reg_rtx (SImode); + + emit_insn (gen_movsi (reg, operands[1])); + operands[1] = gen_lowpart (QImode, reg); + } + if (TARGET_THUMB) + { /* ??? We shouldn't really get invalid addresses here, but this can happen if we are passed a SP (never OK for HImode/QImode) or virtual register (rejected by GO_IF_LEGITIMATE_ADDRESS for @@ -4684,20 +4989,32 @@ operands[1] = replace_equiv_address (operands[1], copy_to_reg (XEXP (operands[1], 0))); - } - /* Handle loading a large integer during reload */ - else if (GET_CODE (operands[1]) == CONST_INT - && !CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) - { - /* Writing a constant to memory needs a scratch, which should - be handled with SECONDARY_RELOADs. */ - if (GET_CODE (operands[0]) != REG) - abort (); + } - operands[0] = gen_rtx_SUBREG (SImode, operands[0], 0); - emit_insn (gen_movsi (operands[0], operands[1])); - DONE; - } + if (GET_CODE (operands[1]) == MEM && optimize > 0) + { + rtx reg = gen_reg_rtx (SImode); + + emit_insn (gen_zero_extendqisi2 (reg, operands[1])); + operands[1] = gen_lowpart (QImode, reg); + } + + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (QImode, operands[1]); + } + else if (TARGET_THUMB + && GET_CODE (operands[1]) == CONST_INT + && !CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) + { + /* Handle loading a large integer during reload. */ + + /* Writing a constant to memory needs a scratch, which should + be handled with SECONDARY_RELOADs. */ + gcc_assert (GET_CODE (operands[0]) == REG); + + operands[0] = gen_rtx_SUBREG (SImode, operands[0], 0); + emit_insn (gen_movsi (operands[0], operands[1])); + DONE; } " ) @@ -4714,7 +5031,7 @@ mvn%?\\t%0, #%B1 ldr%?b\\t%0, %1 str%?b\\t%1, %0" - [(set_attr "type" "*,*,load,store1") + [(set_attr "type" "*,*,load1,store1") (set_attr "predicable" "yes")] ) @@ -4732,7 +5049,7 @@ mov\\t%0, %1 mov\\t%0, %1" [(set_attr "length" "2") - (set_attr "type" "*,load,store1,*,*,*") + (set_attr "type" "*,load1,store1,*,*,*") (set_attr "pool_range" "*,32,*,*,*,*")] ) @@ -4761,7 +5078,7 @@ [(set (match_operand:SF 0 "nonimmediate_operand" "") (match_operand:SF 1 "immediate_operand" ""))] "TARGET_ARM - && !TARGET_HARD_FLOAT + && !(TARGET_HARD_FLOAT && TARGET_FPA) && reload_completed && GET_CODE (operands[1]) == CONST_DOUBLE" [(set (match_dup 2) (match_dup 3))] @@ -4773,52 +5090,22 @@ " ) -(define_insn "*arm_movsf_hard_insn" - [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f, m,f,r,r,r, m") - (match_operand:SF 1 "general_operand" "fG,H,mE,f,r,f,r,mE,r"))] +(define_insn "*arm_movsf_soft_insn" + [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m") + (match_operand:SF 1 "general_operand" "r,mE,r"))] "TARGET_ARM - && TARGET_HARD_FLOAT + && TARGET_SOFT_FLOAT && (GET_CODE (operands[0]) != MEM || register_operand (operands[1], SFmode))" "@ - mvf%?s\\t%0, %1 - mnf%?s\\t%0, #%N1 - ldf%?s\\t%0, %1 - stf%?s\\t%1, %0 - str%?\\t%1, [%|sp, #-4]!\;ldf%?s\\t%0, [%|sp], #4 - stf%?s\\t%1, [%|sp, #-4]!\;ldr%?\\t%0, [%|sp], #4 mov%?\\t%0, %1 ldr%?\\t%0, %1\\t%@ float str%?\\t%1, %0\\t%@ float" - [(set_attr "length" "4,4,4,4,8,8,4,4,4") + [(set_attr "length" "4,4,4") (set_attr "predicable" "yes") - (set_attr "type" - "ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r,*,load,store1") - (set_attr "pool_range" "*,*,1024,*,*,*,*,4096,*") - (set_attr "neg_pool_range" "*,*,1012,*,*,*,*,4084,*")] -) - -;; Exactly the same as above, except that all `f' cases are deleted. -;; This is necessary to prevent reload from ever trying to use a `f' reg -;; when -msoft-float. - -(define_insn "*arm_movsf_soft_insn" - [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m") - (match_operand:SF 1 "general_operand" "r,mE,r"))] - "TARGET_ARM - && !TARGET_CIRRUS - && TARGET_SOFT_FLOAT - && (GET_CODE (operands[0]) != MEM - || register_operand (operands[1], SFmode))" - "@ - mov%?\\t%0, %1 - ldr%?\\t%0, %1\\t%@ float - str%?\\t%1, %0\\t%@ float" - [(set_attr "length" "4,4,4") - (set_attr "predicable" "yes") - (set_attr "type" "*,load,store1") - (set_attr "pool_range" "*,4096,*") - (set_attr "neg_pool_range" "*,4084,*")] + (set_attr "type" "*,load1,store1") + (set_attr "pool_range" "*,4096,*") + (set_attr "neg_pool_range" "*,4084,*")] ) ;;; ??? This should have alternatives for constants. @@ -4837,7 +5124,7 @@ mov\\t%0, %1 mov\\t%0, %1" [(set_attr "length" "2") - (set_attr "type" "*,load,store1,load,store1,*,*") + (set_attr "type" "*,load1,store1,load1,store1,*,*") (set_attr "pool_range" "*,*,*,1020,*,*,*")] ) @@ -4895,7 +5182,8 @@ emit_insn (gen_addsi3 (operands[2], XEXP (XEXP (operands[0], 0), 0), XEXP (XEXP (operands[0], 0), 1))); - emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_MEM (DFmode, operands[2]), + emit_insn (gen_rtx_SET (VOIDmode, + replace_equiv_address (operands[0], operands[2]), operands[1])); if (code == POST_DEC) @@ -4905,53 +5193,24 @@ }" ) -(define_insn "*movdf_hard_insn" - [(set (match_operand:DF 0 "nonimmediate_operand" - "=r,Q,r,m,r, f, f,f, m,!f,!r") - (match_operand:DF 1 "general_operand" - "Q, r,r,r,mF,fG,H,mF,f,r, f"))] - "TARGET_ARM - && TARGET_HARD_FLOAT - && (GET_CODE (operands[0]) != MEM - || register_operand (operands[1], DFmode))" +(define_insn "*movdf_soft_insn" + [(set (match_operand:DF 0 "nonimmediate_soft_df_operand" "=r,r,r,r,m") + (match_operand:DF 1 "soft_df_operand" "rDa,Db,Dc,mF,r"))] + "TARGET_ARM && TARGET_SOFT_FLOAT + " "* - { switch (which_alternative) { + case 0: + case 1: + case 2: + return \"#\"; default: - case 0: return \"ldm%?ia\\t%m1, %M0\\t%@ double\"; - case 1: return \"stm%?ia\\t%m0, %M1\\t%@ double\"; - case 2: case 3: case 4: return output_move_double (operands); - case 5: return \"mvf%?d\\t%0, %1\"; - case 6: return \"mnf%?d\\t%0, #%N1\"; - case 7: return \"ldf%?d\\t%0, %1\"; - case 8: return \"stf%?d\\t%1, %0\"; - case 9: return output_mov_double_fpu_from_arm (operands); - case 10: return output_mov_double_arm_from_fpu (operands); + return output_move_double (operands); } - } - " - [(set_attr "length" "4,4,8,8,8,4,4,4,4,8,8") - (set_attr "predicable" "yes") - (set_attr "type" - "load,store2,*,store2,load,ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r") - (set_attr "pool_range" "*,*,*,*,1020,*,*,1024,*,*,*") - (set_attr "neg_pool_range" "*,*,*,*,1008,*,*,1008,*,*,*")] -) - -;; Software floating point version. This is essentially the same as movdi. -;; Do not use `f' as a constraint to prevent reload from ever trying to use -;; an `f' reg. - -(define_insn "*movdf_soft_insn" - [(set (match_operand:DF 0 "nonimmediate_soft_df_operand" "=r,r,m") - (match_operand:DF 1 "soft_df_operand" "r,mF,r"))] - "TARGET_ARM && TARGET_SOFT_FLOAT - && !TARGET_CIRRUS " - "* return output_move_double (operands);" - [(set_attr "length" "8,8,8") - (set_attr "type" "*,load,store2") + [(set_attr "length" "8,12,16,8,8") + (set_attr "type" "*,*,*,load2,store2") (set_attr "pool_range" "1020") (set_attr "neg_pool_range" "1008")] ) @@ -4981,8 +5240,8 @@ case 3: return thumb_load_double_from_address (operands); case 4: - operands[2] = gen_rtx (MEM, SImode, - plus_constant (XEXP (operands[0], 0), 4)); + operands[2] = gen_rtx_MEM (SImode, + plus_constant (XEXP (operands[0], 0), 4)); output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); return \"\"; case 5: @@ -4992,39 +5251,41 @@ } " [(set_attr "length" "4,2,2,6,4,4") - (set_attr "type" "*,load,store2,load,store2,*") + (set_attr "type" "*,load2,store2,load2,store2,*") (set_attr "pool_range" "*,*,*,1020,*,*")] ) - -;; Saving and restoring the floating point registers in the prologue should -;; be done in XFmode, even though we don't support that for anything else -;; (Well, strictly it's 'internal representation', but that's effectively -;; XFmode). - -(define_insn "*movxf_hard_insn" - [(set (match_operand:XF 0 "nonimmediate_operand" "=f,f,f,m,f,r,r") - (match_operand:XF 1 "general_operand" "fG,H,m,f,r,f,r"))] - "TARGET_ARM && TARGET_HARD_FLOAT && reload_completed" - "* - switch (which_alternative) - { - default: - case 0: return \"mvf%?e\\t%0, %1\"; - case 1: return \"mnf%?e\\t%0, #%N1\"; - case 2: return \"ldf%?e\\t%0, %1\"; - case 3: return \"stf%?e\\t%1, %0\"; - case 4: return output_mov_long_double_fpu_from_arm (operands); - case 5: return output_mov_long_double_arm_from_fpu (operands); - case 6: return output_mov_long_double_arm_from_arm (operands); - } +(define_expand "movxf" + [(set (match_operand:XF 0 "general_operand" "") + (match_operand:XF 1 "general_operand" ""))] + "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA" + " + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (XFmode, operands[1]); " - [(set_attr "length" "4,4,4,4,8,8,12") - (set_attr "predicable" "yes") - (set_attr "type" "ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r,*") - (set_attr "pool_range" "*,*,1024,*,*,*,*") - (set_attr "neg_pool_range" "*,*,1004,*,*,*,*")] ) + +;; Vector Moves +(define_expand "movv2si" + [(set (match_operand:V2SI 0 "nonimmediate_operand" "") + (match_operand:V2SI 1 "general_operand" ""))] + "TARGET_REALLY_IWMMXT" +{ +}) + +(define_expand "movv4hi" + [(set (match_operand:V4HI 0 "nonimmediate_operand" "") + (match_operand:V4HI 1 "general_operand" ""))] + "TARGET_REALLY_IWMMXT" +{ +}) + +(define_expand "movv8qi" + [(set (match_operand:V8QI 0 "nonimmediate_operand" "") + (match_operand:V8QI 1 "general_operand" ""))] + "TARGET_REALLY_IWMMXT" +{ +}) ;; load- and store-multiple insns @@ -5036,7 +5297,9 @@ (match_operand:SI 1 "" "")) (use (match_operand:SI 2 "" ""))])] "TARGET_ARM" - " +{ + HOST_WIDE_INT offset = 0; + /* Support only fixed point registers. */ if (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) > 14 @@ -5050,11 +5313,8 @@ operands[3] = arm_gen_load_multiple (REGNO (operands[0]), INTVAL (operands[2]), force_reg (SImode, XEXP (operands[1], 0)), - TRUE, FALSE, RTX_UNCHANGING_P(operands[1]), - MEM_IN_STRUCT_P(operands[1]), - MEM_SCALAR_P (operands[1])); - " -) + TRUE, FALSE, operands[1], &offset); +}) ;; Load multiple with write-back @@ -5073,10 +5333,28 @@ (mem:SI (plus:SI (match_dup 2) (const_int 12))))])] "TARGET_ARM && XVECLEN (operands[0], 0) == 5" "ldm%?ia\\t%1!, {%3, %4, %5, %6}" - [(set_attr "type" "load") + [(set_attr "type" "load4") (set_attr "predicable" "yes")] ) +(define_insn "*ldmsi_postinc4_thumb" + [(match_parallel 0 "load_multiple_operation" + [(set (match_operand:SI 1 "s_register_operand" "=l") + (plus:SI (match_operand:SI 2 "s_register_operand" "1") + (const_int 16))) + (set (match_operand:SI 3 "arm_hard_register_operand" "") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "arm_hard_register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 4)))) + (set (match_operand:SI 5 "arm_hard_register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 8)))) + (set (match_operand:SI 6 "arm_hard_register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 12))))])] + "TARGET_THUMB && XVECLEN (operands[0], 0) == 5" + "ldmia\\t%1!, {%3, %4, %5, %6}" + [(set_attr "type" "load4")] +) + (define_insn "*ldmsi_postinc3" [(match_parallel 0 "load_multiple_operation" [(set (match_operand:SI 1 "s_register_operand" "=r") @@ -5090,7 +5368,7 @@ (mem:SI (plus:SI (match_dup 2) (const_int 8))))])] "TARGET_ARM && XVECLEN (operands[0], 0) == 4" "ldm%?ia\\t%1!, {%3, %4, %5}" - [(set_attr "type" "load") + [(set_attr "type" "load3") (set_attr "predicable" "yes")] ) @@ -5105,7 +5383,7 @@ (mem:SI (plus:SI (match_dup 2) (const_int 4))))])] "TARGET_ARM && XVECLEN (operands[0], 0) == 3" "ldm%?ia\\t%1!, {%3, %4}" - [(set_attr "type" "load") + [(set_attr "type" "load2") (set_attr "predicable" "yes")] ) @@ -5123,7 +5401,7 @@ (mem:SI (plus:SI (match_dup 1) (const_int 12))))])] "TARGET_ARM && XVECLEN (operands[0], 0) == 4" "ldm%?ia\\t%1, {%2, %3, %4, %5}" - [(set_attr "type" "load") + [(set_attr "type" "load4") (set_attr "predicable" "yes")] ) @@ -5137,7 +5415,7 @@ (mem:SI (plus:SI (match_dup 1) (const_int 8))))])] "TARGET_ARM && XVECLEN (operands[0], 0) == 3" "ldm%?ia\\t%1, {%2, %3, %4}" - [(set_attr "type" "load") + [(set_attr "type" "load3") (set_attr "predicable" "yes")] ) @@ -5149,7 +5427,7 @@ (mem:SI (plus:SI (match_dup 1) (const_int 4))))])] "TARGET_ARM && XVECLEN (operands[0], 0) == 2" "ldm%?ia\\t%1, {%2, %3}" - [(set_attr "type" "load") + [(set_attr "type" "load2") (set_attr "predicable" "yes")] ) @@ -5158,8 +5436,10 @@ (match_operand:SI 1 "" "")) (use (match_operand:SI 2 "" ""))])] "TARGET_ARM" - " - /* Support only fixed point registers */ +{ + HOST_WIDE_INT offset = 0; + + /* Support only fixed point registers. */ if (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) > 14 || INTVAL (operands[2]) < 2 @@ -5172,11 +5452,8 @@ operands[3] = arm_gen_store_multiple (REGNO (operands[1]), INTVAL (operands[2]), force_reg (SImode, XEXP (operands[0], 0)), - TRUE, FALSE, RTX_UNCHANGING_P (operands[0]), - MEM_IN_STRUCT_P(operands[0]), - MEM_SCALAR_P (operands[0])); - " -) + TRUE, FALSE, operands[0], &offset); +}) ;; Store multiple with write-back @@ -5199,6 +5476,24 @@ (set_attr "type" "store4")] ) +(define_insn "*stmsi_postinc4_thumb" + [(match_parallel 0 "store_multiple_operation" + [(set (match_operand:SI 1 "s_register_operand" "=l") + (plus:SI (match_operand:SI 2 "s_register_operand" "1") + (const_int 16))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "arm_hard_register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) + (match_operand:SI 4 "arm_hard_register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 8))) + (match_operand:SI 5 "arm_hard_register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 12))) + (match_operand:SI 6 "arm_hard_register_operand" ""))])] + "TARGET_THUMB && XVECLEN (operands[0], 0) == 5" + "stmia\\t%1!, {%3, %4, %5, %6}" + [(set_attr "type" "store4")] +) + (define_insn "*stmsi_postinc3" [(match_parallel 0 "store_multiple_operation" [(set (match_operand:SI 1 "s_register_operand" "=r") @@ -5279,7 +5574,7 @@ ;; We could let this apply for blocks of less than this, but it clobbers so ;; many registers that there is then probably a better way. -(define_expand "movstrqi" +(define_expand "movmemqi" [(match_operand:BLK 0 "general_operand" "") (match_operand:BLK 1 "general_operand" "") (match_operand:SI 2 "const_int_operand" "") @@ -5288,7 +5583,7 @@ " if (TARGET_ARM) { - if (arm_gen_movstrqi (operands)) + if (arm_gen_movmemqi (operands)) DONE; FAIL; } @@ -5298,7 +5593,7 @@ || INTVAL (operands[2]) > 48) FAIL; - thumb_expand_movstrqi (operands); + thumb_expand_movmemqi (operands); DONE; } " @@ -5350,7 +5645,7 @@ ;; Compare & branch insns -;; The range calcualations are based as follows: +;; The range calculations are based as follows: ;; For forward branches, the address calculation returns the address of ;; the next instruction. This is 2 beyond the branch instruction. ;; For backward branches, the address calculation returns the address of @@ -5366,17 +5661,36 @@ ;; For a 'b' pos_range = 2046, neg_range = -2048 giving (-2040->2048). ;; For a 'b' pos_range = 254, neg_range = -256 giving (-250 ->256). -(define_insn "cbranchsi4" - [(set (pc) - (if_then_else - (match_operator 0 "arm_comparison_operator" - [(match_operand:SI 1 "register_operand" "l,r") - (match_operand:SI 2 "nonmemory_operand" "rI,r")]) - (label_ref (match_operand 3 "" "")) - (pc)))] +(define_expand "cbranchsi4" + [(set (pc) (if_then_else + (match_operator 0 "arm_comparison_operator" + [(match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "TARGET_THUMB" + " + if (thumb_cmpneg_operand (operands[2], SImode)) + { + emit_jump_insn (gen_cbranchsi4_scratch (NULL, operands[1], operands[2], + operands[3], operands[0])); + DONE; + } + if (!thumb_cmp_operand (operands[2], SImode)) + operands[2] = force_reg (SImode, operands[2]); + ") + +(define_insn "*cbranchsi4_insn" + [(set (pc) (if_then_else + (match_operator 0 "arm_comparison_operator" + [(match_operand:SI 1 "s_register_operand" "l,*h") + (match_operand:SI 2 "thumb_cmp_operand" "lI*h,*r")]) + (label_ref (match_operand 3 "" "")) + (pc)))] "TARGET_THUMB" "* output_asm_insn (\"cmp\\t%1, %2\", operands); + switch (get_attr_length (insn)) { case 4: return \"b%d0\\t%l3\"; @@ -5401,13 +5715,111 @@ (const_int 8))))] ) +(define_insn "cbranchsi4_scratch" + [(set (pc) (if_then_else + (match_operator 4 "arm_comparison_operator" + [(match_operand:SI 1 "s_register_operand" "l,0") + (match_operand:SI 2 "thumb_cmpneg_operand" "L,J")]) + (label_ref (match_operand 3 "" "")) + (pc))) + (clobber (match_scratch:SI 0 "=l,l"))] + "TARGET_THUMB" + "* + output_asm_insn (\"add\\t%0, %1, #%n2\", operands); + + switch (get_attr_length (insn)) + { + case 4: return \"b%d4\\t%l3\"; + case 6: return \"b%D4\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\"; + default: return \"b%D4\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\"; + } + " + [(set (attr "far_jump") + (if_then_else + (eq_attr "length" "8") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (and (ge (minus (match_dup 3) (pc)) (const_int -250)) + (le (minus (match_dup 3) (pc)) (const_int 256))) + (const_int 4) + (if_then_else + (and (ge (minus (match_dup 3) (pc)) (const_int -2040)) + (le (minus (match_dup 3) (pc)) (const_int 2048))) + (const_int 6) + (const_int 8))))] +) +(define_insn "*movsi_cbranchsi4" + [(set (pc) + (if_then_else + (match_operator 3 "arm_comparison_operator" + [(match_operand:SI 1 "s_register_operand" "0,l,l,l") + (const_int 0)]) + (label_ref (match_operand 2 "" "")) + (pc))) + (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,l,*h,*m") + (match_dup 1))] + "TARGET_THUMB" + "*{ + if (which_alternative == 0) + output_asm_insn (\"cmp\t%0, #0\", operands); + else if (which_alternative == 1) + output_asm_insn (\"sub\t%0, %1, #0\", operands); + else + { + output_asm_insn (\"cmp\t%1, #0\", operands); + if (which_alternative == 2) + output_asm_insn (\"mov\t%0, %1\", operands); + else + output_asm_insn (\"str\t%1, %0\", operands); + } + switch (get_attr_length (insn) - ((which_alternative > 1) ? 2 : 0)) + { + case 4: return \"b%d3\\t%l2\"; + case 6: return \"b%D3\\t.LCB%=\;b\\t%l2\\t%@long jump\\n.LCB%=:\"; + default: return \"b%D3\\t.LCB%=\;bl\\t%l2\\t%@far jump\\n.LCB%=:\"; + } + }" + [(set (attr "far_jump") + (if_then_else + (ior (and (gt (symbol_ref ("which_alternative")) + (const_int 1)) + (eq_attr "length" "8")) + (eq_attr "length" "10")) + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (le (symbol_ref ("which_alternative")) + (const_int 1)) + (if_then_else + (and (ge (minus (match_dup 2) (pc)) (const_int -250)) + (le (minus (match_dup 2) (pc)) (const_int 256))) + (const_int 4) + (if_then_else + (and (ge (minus (match_dup 2) (pc)) (const_int -2040)) + (le (minus (match_dup 2) (pc)) (const_int 2048))) + (const_int 6) + (const_int 8))) + (if_then_else + (and (ge (minus (match_dup 2) (pc)) (const_int -248)) + (le (minus (match_dup 2) (pc)) (const_int 256))) + (const_int 6) + (if_then_else + (and (ge (minus (match_dup 2) (pc)) (const_int -2038)) + (le (minus (match_dup 2) (pc)) (const_int 2048))) + (const_int 8) + (const_int 10)))))] +) + (define_insn "*negated_cbranchsi4" [(set (pc) (if_then_else - (match_operator 0 "arm_comparison_operator" - [(match_operand:SI 1 "register_operand" "l") - (neg:SI (match_operand:SI 2 "nonmemory_operand" "l"))]) - (label_ref (match_operand 3 "" "")) + (match_operator 0 "equality_operator" + [(match_operand:SI 1 "s_register_operand" "l") + (neg:SI (match_operand:SI 2 "s_register_operand" "l"))]) + (label_ref (match_operand 3 "" "")) (pc)))] "TARGET_THUMB" "* @@ -5436,6 +5848,844 @@ (const_int 8))))] ) +(define_insn "*tbit_cbranch" + [(set (pc) + (if_then_else + (match_operator 0 "equality_operator" + [(zero_extract:SI (match_operand:SI 1 "s_register_operand" "l") + (const_int 1) + (match_operand:SI 2 "const_int_operand" "i")) + (const_int 0)]) + (label_ref (match_operand 3 "" "")) + (pc))) + (clobber (match_scratch:SI 4 "=l"))] + "TARGET_THUMB" + "* + { + rtx op[3]; + op[0] = operands[4]; + op[1] = operands[1]; + op[2] = GEN_INT (32 - 1 - INTVAL (operands[2])); + + output_asm_insn (\"lsl\\t%0, %1, %2\", op); + switch (get_attr_length (insn)) + { + case 4: return \"b%d0\\t%l3\"; + case 6: return \"b%D0\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\"; + default: return \"b%D0\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\"; + } + }" + [(set (attr "far_jump") + (if_then_else + (eq_attr "length" "8") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (and (ge (minus (match_dup 3) (pc)) (const_int -250)) + (le (minus (match_dup 3) (pc)) (const_int 256))) + (const_int 4) + (if_then_else + (and (ge (minus (match_dup 3) (pc)) (const_int -2040)) + (le (minus (match_dup 3) (pc)) (const_int 2048))) + (const_int 6) + (const_int 8))))] +) + +(define_insn "*tstsi3_cbranch" + [(set (pc) + (if_then_else + (match_operator 3 "equality_operator" + [(and:SI (match_operand:SI 0 "s_register_operand" "%l") + (match_operand:SI 1 "s_register_operand" "l")) + (const_int 0)]) + (label_ref (match_operand 2 "" "")) + (pc)))] + "TARGET_THUMB" + "* + { + output_asm_insn (\"tst\\t%0, %1\", operands); + switch (get_attr_length (insn)) + { + case 4: return \"b%d3\\t%l2\"; + case 6: return \"b%D3\\t.LCB%=\;b\\t%l2\\t%@long jump\\n.LCB%=:\"; + default: return \"b%D3\\t.LCB%=\;bl\\t%l2\\t%@far jump\\n.LCB%=:\"; + } + }" + [(set (attr "far_jump") + (if_then_else + (eq_attr "length" "8") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (and (ge (minus (match_dup 2) (pc)) (const_int -250)) + (le (minus (match_dup 2) (pc)) (const_int 256))) + (const_int 4) + (if_then_else + (and (ge (minus (match_dup 2) (pc)) (const_int -2040)) + (le (minus (match_dup 2) (pc)) (const_int 2048))) + (const_int 6) + (const_int 8))))] +) + +(define_insn "*andsi3_cbranch" + [(set (pc) + (if_then_else + (match_operator 5 "equality_operator" + [(and:SI (match_operand:SI 2 "s_register_operand" "%0,1,1,1") + (match_operand:SI 3 "s_register_operand" "l,l,l,l")) + (const_int 0)]) + (label_ref (match_operand 4 "" "")) + (pc))) + (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,*?h,*?m,*?m") + (and:SI (match_dup 2) (match_dup 3))) + (clobber (match_scratch:SI 1 "=X,l,&l,&l"))] + "TARGET_THUMB" + "* + { + if (which_alternative == 0) + output_asm_insn (\"and\\t%0, %3\", operands); + else if (which_alternative == 1) + { + output_asm_insn (\"and\\t%1, %3\", operands); + output_asm_insn (\"mov\\t%0, %1\", operands); + } + else + { + output_asm_insn (\"and\\t%1, %3\", operands); + output_asm_insn (\"str\\t%1, %0\", operands); + } + + switch (get_attr_length (insn) - (which_alternative ? 2 : 0)) + { + case 4: return \"b%d5\\t%l4\"; + case 6: return \"b%D5\\t.LCB%=\;b\\t%l4\\t%@long jump\\n.LCB%=:\"; + default: return \"b%D5\\t.LCB%=\;bl\\t%l4\\t%@far jump\\n.LCB%=:\"; + } + }" + [(set (attr "far_jump") + (if_then_else + (ior (and (eq (symbol_ref ("which_alternative")) + (const_int 0)) + (eq_attr "length" "8")) + (eq_attr "length" "10")) + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (eq (symbol_ref ("which_alternative")) + (const_int 0)) + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -250)) + (le (minus (match_dup 4) (pc)) (const_int 256))) + (const_int 4) + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -2040)) + (le (minus (match_dup 4) (pc)) (const_int 2048))) + (const_int 6) + (const_int 8))) + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -248)) + (le (minus (match_dup 4) (pc)) (const_int 256))) + (const_int 6) + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -2038)) + (le (minus (match_dup 4) (pc)) (const_int 2048))) + (const_int 8) + (const_int 10)))))] +) + +(define_insn "*orrsi3_cbranch_scratch" + [(set (pc) + (if_then_else + (match_operator 4 "equality_operator" + [(ior:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "s_register_operand" "l")) + (const_int 0)]) + (label_ref (match_operand 3 "" "")) + (pc))) + (clobber (match_scratch:SI 0 "=l"))] + "TARGET_THUMB" + "* + { + output_asm_insn (\"orr\\t%0, %2\", operands); + switch (get_attr_length (insn)) + { + case 4: return \"b%d4\\t%l3\"; + case 6: return \"b%D4\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\"; + default: return \"b%D4\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\"; + } + }" + [(set (attr "far_jump") + (if_then_else + (eq_attr "length" "8") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (and (ge (minus (match_dup 3) (pc)) (const_int -250)) + (le (minus (match_dup 3) (pc)) (const_int 256))) + (const_int 4) + (if_then_else + (and (ge (minus (match_dup 3) (pc)) (const_int -2040)) + (le (minus (match_dup 3) (pc)) (const_int 2048))) + (const_int 6) + (const_int 8))))] +) + +(define_insn "*orrsi3_cbranch" + [(set (pc) + (if_then_else + (match_operator 5 "equality_operator" + [(ior:SI (match_operand:SI 2 "s_register_operand" "%0,1,1,1") + (match_operand:SI 3 "s_register_operand" "l,l,l,l")) + (const_int 0)]) + (label_ref (match_operand 4 "" "")) + (pc))) + (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,*?h,*?m,*?m") + (ior:SI (match_dup 2) (match_dup 3))) + (clobber (match_scratch:SI 1 "=X,l,&l,&l"))] + "TARGET_THUMB" + "* + { + if (which_alternative == 0) + output_asm_insn (\"orr\\t%0, %3\", operands); + else if (which_alternative == 1) + { + output_asm_insn (\"orr\\t%1, %3\", operands); + output_asm_insn (\"mov\\t%0, %1\", operands); + } + else + { + output_asm_insn (\"orr\\t%1, %3\", operands); + output_asm_insn (\"str\\t%1, %0\", operands); + } + + switch (get_attr_length (insn) - (which_alternative ? 2 : 0)) + { + case 4: return \"b%d5\\t%l4\"; + case 6: return \"b%D5\\t.LCB%=\;b\\t%l4\\t%@long jump\\n.LCB%=:\"; + default: return \"b%D5\\t.LCB%=\;bl\\t%l4\\t%@far jump\\n.LCB%=:\"; + } + }" + [(set (attr "far_jump") + (if_then_else + (ior (and (eq (symbol_ref ("which_alternative")) + (const_int 0)) + (eq_attr "length" "8")) + (eq_attr "length" "10")) + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (eq (symbol_ref ("which_alternative")) + (const_int 0)) + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -250)) + (le (minus (match_dup 4) (pc)) (const_int 256))) + (const_int 4) + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -2040)) + (le (minus (match_dup 4) (pc)) (const_int 2048))) + (const_int 6) + (const_int 8))) + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -248)) + (le (minus (match_dup 4) (pc)) (const_int 256))) + (const_int 6) + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -2038)) + (le (minus (match_dup 4) (pc)) (const_int 2048))) + (const_int 8) + (const_int 10)))))] +) + +(define_insn "*xorsi3_cbranch_scratch" + [(set (pc) + (if_then_else + (match_operator 4 "equality_operator" + [(xor:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "s_register_operand" "l")) + (const_int 0)]) + (label_ref (match_operand 3 "" "")) + (pc))) + (clobber (match_scratch:SI 0 "=l"))] + "TARGET_THUMB" + "* + { + output_asm_insn (\"eor\\t%0, %2\", operands); + switch (get_attr_length (insn)) + { + case 4: return \"b%d4\\t%l3\"; + case 6: return \"b%D4\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\"; + default: return \"b%D4\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\"; + } + }" + [(set (attr "far_jump") + (if_then_else + (eq_attr "length" "8") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (and (ge (minus (match_dup 3) (pc)) (const_int -250)) + (le (minus (match_dup 3) (pc)) (const_int 256))) + (const_int 4) + (if_then_else + (and (ge (minus (match_dup 3) (pc)) (const_int -2040)) + (le (minus (match_dup 3) (pc)) (const_int 2048))) + (const_int 6) + (const_int 8))))] +) + +(define_insn "*xorsi3_cbranch" + [(set (pc) + (if_then_else + (match_operator 5 "equality_operator" + [(xor:SI (match_operand:SI 2 "s_register_operand" "%0,1,1,1") + (match_operand:SI 3 "s_register_operand" "l,l,l,l")) + (const_int 0)]) + (label_ref (match_operand 4 "" "")) + (pc))) + (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,*?h,*?m,*?m") + (xor:SI (match_dup 2) (match_dup 3))) + (clobber (match_scratch:SI 1 "=X,l,&l,&l"))] + "TARGET_THUMB" + "* + { + if (which_alternative == 0) + output_asm_insn (\"eor\\t%0, %3\", operands); + else if (which_alternative == 1) + { + output_asm_insn (\"eor\\t%1, %3\", operands); + output_asm_insn (\"mov\\t%0, %1\", operands); + } + else + { + output_asm_insn (\"eor\\t%1, %3\", operands); + output_asm_insn (\"str\\t%1, %0\", operands); + } + + switch (get_attr_length (insn) - (which_alternative ? 2 : 0)) + { + case 4: return \"b%d5\\t%l4\"; + case 6: return \"b%D5\\t.LCB%=\;b\\t%l4\\t%@long jump\\n.LCB%=:\"; + default: return \"b%D5\\t.LCB%=\;bl\\t%l4\\t%@far jump\\n.LCB%=:\"; + } + }" + [(set (attr "far_jump") + (if_then_else + (ior (and (eq (symbol_ref ("which_alternative")) + (const_int 0)) + (eq_attr "length" "8")) + (eq_attr "length" "10")) + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (eq (symbol_ref ("which_alternative")) + (const_int 0)) + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -250)) + (le (minus (match_dup 4) (pc)) (const_int 256))) + (const_int 4) + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -2040)) + (le (minus (match_dup 4) (pc)) (const_int 2048))) + (const_int 6) + (const_int 8))) + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -248)) + (le (minus (match_dup 4) (pc)) (const_int 256))) + (const_int 6) + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -2038)) + (le (minus (match_dup 4) (pc)) (const_int 2048))) + (const_int 8) + (const_int 10)))))] +) + +(define_insn "*bicsi3_cbranch_scratch" + [(set (pc) + (if_then_else + (match_operator 4 "equality_operator" + [(and:SI (not:SI (match_operand:SI 2 "s_register_operand" "l")) + (match_operand:SI 1 "s_register_operand" "0")) + (const_int 0)]) + (label_ref (match_operand 3 "" "")) + (pc))) + (clobber (match_scratch:SI 0 "=l"))] + "TARGET_THUMB" + "* + { + output_asm_insn (\"bic\\t%0, %2\", operands); + switch (get_attr_length (insn)) + { + case 4: return \"b%d4\\t%l3\"; + case 6: return \"b%D4\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\"; + default: return \"b%D4\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\"; + } + }" + [(set (attr "far_jump") + (if_then_else + (eq_attr "length" "8") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (and (ge (minus (match_dup 3) (pc)) (const_int -250)) + (le (minus (match_dup 3) (pc)) (const_int 256))) + (const_int 4) + (if_then_else + (and (ge (minus (match_dup 3) (pc)) (const_int -2040)) + (le (minus (match_dup 3) (pc)) (const_int 2048))) + (const_int 6) + (const_int 8))))] +) + +(define_insn "*bicsi3_cbranch" + [(set (pc) + (if_then_else + (match_operator 5 "equality_operator" + [(and:SI (not:SI (match_operand:SI 3 "s_register_operand" "l,l,l,l,l")) + (match_operand:SI 2 "s_register_operand" "0,1,1,1,1")) + (const_int 0)]) + (label_ref (match_operand 4 "" "")) + (pc))) + (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=!l,l,*?h,*?m,*?m") + (and:SI (not:SI (match_dup 3)) (match_dup 2))) + (clobber (match_scratch:SI 1 "=X,l,l,&l,&l"))] + "TARGET_THUMB" + "* + { + if (which_alternative == 0) + output_asm_insn (\"bic\\t%0, %3\", operands); + else if (which_alternative <= 2) + { + output_asm_insn (\"bic\\t%1, %3\", operands); + /* It's ok if OP0 is a lo-reg, even though the mov will set the + conditions again, since we're only testing for equality. */ + output_asm_insn (\"mov\\t%0, %1\", operands); + } + else + { + output_asm_insn (\"bic\\t%1, %3\", operands); + output_asm_insn (\"str\\t%1, %0\", operands); + } + + switch (get_attr_length (insn) - (which_alternative ? 2 : 0)) + { + case 4: return \"b%d5\\t%l4\"; + case 6: return \"b%D5\\t.LCB%=\;b\\t%l4\\t%@long jump\\n.LCB%=:\"; + default: return \"b%D5\\t.LCB%=\;bl\\t%l4\\t%@far jump\\n.LCB%=:\"; + } + }" + [(set (attr "far_jump") + (if_then_else + (ior (and (eq (symbol_ref ("which_alternative")) + (const_int 0)) + (eq_attr "length" "8")) + (eq_attr "length" "10")) + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (eq (symbol_ref ("which_alternative")) + (const_int 0)) + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -250)) + (le (minus (match_dup 4) (pc)) (const_int 256))) + (const_int 4) + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -2040)) + (le (minus (match_dup 4) (pc)) (const_int 2048))) + (const_int 6) + (const_int 8))) + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -248)) + (le (minus (match_dup 4) (pc)) (const_int 256))) + (const_int 6) + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -2038)) + (le (minus (match_dup 4) (pc)) (const_int 2048))) + (const_int 8) + (const_int 10)))))] +) + +(define_insn "*cbranchne_decr1" + [(set (pc) + (if_then_else (match_operator 3 "equality_operator" + [(match_operand:SI 2 "s_register_operand" "l,l,1,l") + (const_int 0)]) + (label_ref (match_operand 4 "" "")) + (pc))) + (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,*?h,*?m,*?m") + (plus:SI (match_dup 2) (const_int -1))) + (clobber (match_scratch:SI 1 "=X,l,&l,&l"))] + "TARGET_THUMB" + "* + { + rtx cond[2]; + cond[0] = gen_rtx_fmt_ee ((GET_CODE (operands[3]) == NE + ? GEU : LTU), + VOIDmode, operands[2], const1_rtx); + cond[1] = operands[4]; + + if (which_alternative == 0) + output_asm_insn (\"sub\\t%0, %2, #1\", operands); + else if (which_alternative == 1) + { + /* We must provide an alternative for a hi reg because reload + cannot handle output reloads on a jump instruction, but we + can't subtract into that. Fortunately a mov from lo to hi + does not clobber the condition codes. */ + output_asm_insn (\"sub\\t%1, %2, #1\", operands); + output_asm_insn (\"mov\\t%0, %1\", operands); + } + else + { + /* Similarly, but the target is memory. */ + output_asm_insn (\"sub\\t%1, %2, #1\", operands); + output_asm_insn (\"str\\t%1, %0\", operands); + } + + switch (get_attr_length (insn) - (which_alternative ? 2 : 0)) + { + case 4: + output_asm_insn (\"b%d0\\t%l1\", cond); + return \"\"; + case 6: + output_asm_insn (\"b%D0\\t.LCB%=\", cond); + return \"b\\t%l4\\t%@long jump\\n.LCB%=:\"; + default: + output_asm_insn (\"b%D0\\t.LCB%=\", cond); + return \"bl\\t%l4\\t%@far jump\\n.LCB%=:\"; + } + } + " + [(set (attr "far_jump") + (if_then_else + (ior (and (eq (symbol_ref ("which_alternative")) + (const_int 0)) + (eq_attr "length" "8")) + (eq_attr "length" "10")) + (const_string "yes") + (const_string "no"))) + (set_attr_alternative "length" + [ + ;; Alternative 0 + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -250)) + (le (minus (match_dup 4) (pc)) (const_int 256))) + (const_int 4) + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -2040)) + (le (minus (match_dup 4) (pc)) (const_int 2048))) + (const_int 6) + (const_int 8))) + ;; Alternative 1 + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -248)) + (le (minus (match_dup 4) (pc)) (const_int 256))) + (const_int 6) + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -2038)) + (le (minus (match_dup 4) (pc)) (const_int 2048))) + (const_int 8) + (const_int 10))) + ;; Alternative 2 + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -248)) + (le (minus (match_dup 4) (pc)) (const_int 256))) + (const_int 6) + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -2038)) + (le (minus (match_dup 4) (pc)) (const_int 2048))) + (const_int 8) + (const_int 10))) + ;; Alternative 3 + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -248)) + (le (minus (match_dup 4) (pc)) (const_int 256))) + (const_int 6) + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -2038)) + (le (minus (match_dup 4) (pc)) (const_int 2048))) + (const_int 8) + (const_int 10)))])] +) + +(define_insn "*addsi3_cbranch" + [(set (pc) + (if_then_else + (match_operator 4 "comparison_operator" + [(plus:SI + (match_operand:SI 2 "s_register_operand" "%l,0,*0,1,1,1") + (match_operand:SI 3 "reg_or_int_operand" "lL,IJ,*r,lIJ,lIJ,lIJ")) + (const_int 0)]) + (label_ref (match_operand 5 "" "")) + (pc))) + (set + (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,l,*!h,*?h,*?m,*?m") + (plus:SI (match_dup 2) (match_dup 3))) + (clobber (match_scratch:SI 1 "=X,X,X,l,&l,&l"))] + "TARGET_THUMB + && (GET_CODE (operands[4]) == EQ + || GET_CODE (operands[4]) == NE + || GET_CODE (operands[4]) == GE + || GET_CODE (operands[4]) == LT)" + "* + { + rtx cond[3]; + + + cond[0] = (which_alternative < 3) ? operands[0] : operands[1]; + cond[1] = operands[2]; + cond[2] = operands[3]; + + if (GET_CODE (cond[2]) == CONST_INT && INTVAL (cond[2]) < 0) + output_asm_insn (\"sub\\t%0, %1, #%n2\", cond); + else + output_asm_insn (\"add\\t%0, %1, %2\", cond); + + if (which_alternative >= 3 + && which_alternative < 4) + output_asm_insn (\"mov\\t%0, %1\", operands); + else if (which_alternative >= 4) + output_asm_insn (\"str\\t%1, %0\", operands); + + switch (get_attr_length (insn) - ((which_alternative >= 3) ? 2 : 0)) + { + case 4: + return \"b%d4\\t%l5\"; + case 6: + return \"b%D4\\t.LCB%=\;b\\t%l5\\t%@long jump\\n.LCB%=:\"; + default: + return \"b%D4\\t.LCB%=\;bl\\t%l5\\t%@far jump\\n.LCB%=:\"; + } + } + " + [(set (attr "far_jump") + (if_then_else + (ior (and (lt (symbol_ref ("which_alternative")) + (const_int 3)) + (eq_attr "length" "8")) + (eq_attr "length" "10")) + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (lt (symbol_ref ("which_alternative")) + (const_int 3)) + (if_then_else + (and (ge (minus (match_dup 5) (pc)) (const_int -250)) + (le (minus (match_dup 5) (pc)) (const_int 256))) + (const_int 4) + (if_then_else + (and (ge (minus (match_dup 5) (pc)) (const_int -2040)) + (le (minus (match_dup 5) (pc)) (const_int 2048))) + (const_int 6) + (const_int 8))) + (if_then_else + (and (ge (minus (match_dup 5) (pc)) (const_int -248)) + (le (minus (match_dup 5) (pc)) (const_int 256))) + (const_int 6) + (if_then_else + (and (ge (minus (match_dup 5) (pc)) (const_int -2038)) + (le (minus (match_dup 5) (pc)) (const_int 2048))) + (const_int 8) + (const_int 10)))))] +) + +(define_insn "*addsi3_cbranch_scratch" + [(set (pc) + (if_then_else + (match_operator 3 "comparison_operator" + [(plus:SI + (match_operand:SI 1 "s_register_operand" "%l,l,l,0") + (match_operand:SI 2 "reg_or_int_operand" "J,l,L,IJ")) + (const_int 0)]) + (label_ref (match_operand 4 "" "")) + (pc))) + (clobber (match_scratch:SI 0 "=X,X,l,l"))] + "TARGET_THUMB + && (GET_CODE (operands[3]) == EQ + || GET_CODE (operands[3]) == NE + || GET_CODE (operands[3]) == GE + || GET_CODE (operands[3]) == LT)" + "* + { + switch (which_alternative) + { + case 0: + output_asm_insn (\"cmp\t%1, #%n2\", operands); + break; + case 1: + output_asm_insn (\"cmn\t%1, %2\", operands); + break; + case 2: + if (INTVAL (operands[2]) < 0) + output_asm_insn (\"sub\t%0, %1, %2\", operands); + else + output_asm_insn (\"add\t%0, %1, %2\", operands); + break; + case 3: + if (INTVAL (operands[2]) < 0) + output_asm_insn (\"sub\t%0, %0, %2\", operands); + else + output_asm_insn (\"add\t%0, %0, %2\", operands); + break; + } + + switch (get_attr_length (insn)) + { + case 4: + return \"b%d3\\t%l4\"; + case 6: + return \"b%D3\\t.LCB%=\;b\\t%l4\\t%@long jump\\n.LCB%=:\"; + default: + return \"b%D3\\t.LCB%=\;bl\\t%l4\\t%@far jump\\n.LCB%=:\"; + } + } + " + [(set (attr "far_jump") + (if_then_else + (eq_attr "length" "8") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -250)) + (le (minus (match_dup 4) (pc)) (const_int 256))) + (const_int 4) + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -2040)) + (le (minus (match_dup 4) (pc)) (const_int 2048))) + (const_int 6) + (const_int 8))))] +) + +(define_insn "*subsi3_cbranch" + [(set (pc) + (if_then_else + (match_operator 4 "comparison_operator" + [(minus:SI + (match_operand:SI 2 "s_register_operand" "l,l,1,l") + (match_operand:SI 3 "s_register_operand" "l,l,l,l")) + (const_int 0)]) + (label_ref (match_operand 5 "" "")) + (pc))) + (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,*?h,*?m,*?m") + (minus:SI (match_dup 2) (match_dup 3))) + (clobber (match_scratch:SI 1 "=X,l,&l,&l"))] + "TARGET_THUMB + && (GET_CODE (operands[4]) == EQ + || GET_CODE (operands[4]) == NE + || GET_CODE (operands[4]) == GE + || GET_CODE (operands[4]) == LT)" + "* + { + if (which_alternative == 0) + output_asm_insn (\"sub\\t%0, %2, %3\", operands); + else if (which_alternative == 1) + { + /* We must provide an alternative for a hi reg because reload + cannot handle output reloads on a jump instruction, but we + can't subtract into that. Fortunately a mov from lo to hi + does not clobber the condition codes. */ + output_asm_insn (\"sub\\t%1, %2, %3\", operands); + output_asm_insn (\"mov\\t%0, %1\", operands); + } + else + { + /* Similarly, but the target is memory. */ + output_asm_insn (\"sub\\t%1, %2, %3\", operands); + output_asm_insn (\"str\\t%1, %0\", operands); + } + + switch (get_attr_length (insn) - ((which_alternative != 0) ? 2 : 0)) + { + case 4: + return \"b%d4\\t%l5\"; + case 6: + return \"b%D4\\t.LCB%=\;b\\t%l5\\t%@long jump\\n.LCB%=:\"; + default: + return \"b%D4\\t.LCB%=\;bl\\t%l5\\t%@far jump\\n.LCB%=:\"; + } + } + " + [(set (attr "far_jump") + (if_then_else + (ior (and (eq (symbol_ref ("which_alternative")) + (const_int 0)) + (eq_attr "length" "8")) + (eq_attr "length" "10")) + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (eq (symbol_ref ("which_alternative")) + (const_int 0)) + (if_then_else + (and (ge (minus (match_dup 5) (pc)) (const_int -250)) + (le (minus (match_dup 5) (pc)) (const_int 256))) + (const_int 4) + (if_then_else + (and (ge (minus (match_dup 5) (pc)) (const_int -2040)) + (le (minus (match_dup 5) (pc)) (const_int 2048))) + (const_int 6) + (const_int 8))) + (if_then_else + (and (ge (minus (match_dup 5) (pc)) (const_int -248)) + (le (minus (match_dup 5) (pc)) (const_int 256))) + (const_int 6) + (if_then_else + (and (ge (minus (match_dup 5) (pc)) (const_int -2038)) + (le (minus (match_dup 5) (pc)) (const_int 2048))) + (const_int 8) + (const_int 10)))))] +) + +(define_insn "*subsi3_cbranch_scratch" + [(set (pc) + (if_then_else + (match_operator 0 "arm_comparison_operator" + [(minus:SI (match_operand:SI 1 "register_operand" "l") + (match_operand:SI 2 "nonmemory_operand" "l")) + (const_int 0)]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "TARGET_THUMB + && (GET_CODE (operands[0]) == EQ + || GET_CODE (operands[0]) == NE + || GET_CODE (operands[0]) == GE + || GET_CODE (operands[0]) == LT)" + "* + output_asm_insn (\"cmp\\t%1, %2\", operands); + switch (get_attr_length (insn)) + { + case 4: return \"b%d0\\t%l3\"; + case 6: return \"b%D0\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\"; + default: return \"b%D0\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\"; + } + " + [(set (attr "far_jump") + (if_then_else + (eq_attr "length" "8") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (and (ge (minus (match_dup 3) (pc)) (const_int -250)) + (le (minus (match_dup 3) (pc)) (const_int 256))) + (const_int 4) + (if_then_else + (and (ge (minus (match_dup 3) (pc)) (const_int -2040)) + (le (minus (match_dup 3) (pc)) (const_int 2048))) + (const_int 6) + (const_int 8))))] +) ;; Comparison and test insns @@ -5452,12 +6702,9 @@ (define_expand "cmpsf" [(match_operand:SF 0 "s_register_operand" "") - (match_operand:SF 1 "fpu_rhs_operand" "")] - "TARGET_ARM && TARGET_ANY_HARD_FLOAT" + (match_operand:SF 1 "arm_float_compare_operand" "")] + "TARGET_ARM && TARGET_HARD_FLOAT" " - if (TARGET_CIRRUS && !cirrus_fp_register (operands[1], SFmode)) - operands[1] = force_reg (SFmode, operands[1]); - arm_compare_op0 = operands[0]; arm_compare_op1 = operands[1]; DONE; @@ -5466,12 +6713,9 @@ (define_expand "cmpdf" [(match_operand:DF 0 "s_register_operand" "") - (match_operand:DF 1 "fpu_rhs_operand" "")] - "TARGET_ARM && TARGET_ANY_HARD_FLOAT" + (match_operand:DF 1 "arm_float_compare_operand" "")] + "TARGET_ARM && TARGET_HARD_FLOAT" " - if (TARGET_CIRRUS && !cirrus_fp_register (operands[1], DFmode)) - operands[1] = force_reg (DFmode, operands[1]); - arm_compare_op0 = operands[0]; arm_compare_op1 = operands[1]; DONE; @@ -5499,7 +6743,9 @@ "cmp%?\\t%0, %1%S3" [(set_attr "conds" "set") (set_attr "shift" "1") - ] + (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "") + (const_string "alu_shift") + (const_string "alu_shift_reg")))] ) (define_insn "*cmpsi_shiftsi_swp" @@ -5512,83 +6758,34 @@ "cmp%?\\t%0, %1%S3" [(set_attr "conds" "set") (set_attr "shift" "1") - ] + (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "") + (const_string "alu_shift") + (const_string "alu_shift_reg")))] ) -(define_insn "*cmpsi_neg_shiftsi" - [(set (reg:CC CC_REGNUM) - (compare:CC (match_operand:SI 0 "s_register_operand" "r") - (neg:SI (match_operator:SI 3 "shift_operator" - [(match_operand:SI 1 "s_register_operand" "r") - (match_operand:SI 2 "arm_rhs_operand" "rM")]))))] +(define_insn "*cmpsi_negshiftsi_si" + [(set (reg:CC_Z CC_REGNUM) + (compare:CC_Z + (neg:SI (match_operator:SI 1 "shift_operator" + [(match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 3 "reg_or_int_operand" "rM")])) + (match_operand:SI 0 "s_register_operand" "r")))] "TARGET_ARM" - "cmn%?\\t%0, %1%S3" - [(set_attr "conds" "set") - (set_attr "shift" "1") - ] -) - -(define_insn "*cmpsf_insn" - [(set (reg:CCFP CC_REGNUM) - (compare:CCFP (match_operand:SF 0 "s_register_operand" "f,f") - (match_operand:SF 1 "fpu_add_operand" "fG,H")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "@ - cmf%?\\t%0, %1 - cnf%?\\t%0, #%N1" + "cmn%?\\t%0, %2%S1" [(set_attr "conds" "set") - (set_attr "type" "f_2_r")] + (set (attr "type") (if_then_else (match_operand 3 "const_int_operand" "") + (const_string "alu_shift") + (const_string "alu_shift_reg")))] ) -(define_insn "*cmpdf_insn" - [(set (reg:CCFP CC_REGNUM) - (compare:CCFP (match_operand:DF 0 "s_register_operand" "f,f") - (match_operand:DF 1 "fpu_add_operand" "fG,H")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "@ - cmf%?\\t%0, %1 - cnf%?\\t%0, #%N1" - [(set_attr "conds" "set") - (set_attr "type" "f_2_r")] -) - -(define_insn "*cmpesfdf_df" - [(set (reg:CCFP CC_REGNUM) - (compare:CCFP (float_extend:DF - (match_operand:SF 0 "s_register_operand" "f,f")) - (match_operand:DF 1 "fpu_add_operand" "fG,H")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "@ - cmf%?\\t%0, %1 - cnf%?\\t%0, #%N1" - [(set_attr "conds" "set") - (set_attr "type" "f_2_r")] -) - -(define_insn "*cmpdf_esfdf" - [(set (reg:CCFP CC_REGNUM) - (compare:CCFP (match_operand:DF 0 "s_register_operand" "f") - (float_extend:DF - (match_operand:SF 1 "s_register_operand" "f"))))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "cmf%?\\t%0, %1" - [(set_attr "conds" "set") - (set_attr "type" "f_2_r")] -) - -;; There is no CCFPE or CCFP modes in the code below so we can have -;; one pattern to match either one. Besides, we're pretty sure we -;; have either CCFPE or CCFP because we made the patterns -;; (arm_gen_compare_reg). - ;; Cirrus SF compare instruction (define_insn "*cirrus_cmpsf" [(set (reg:CCFP CC_REGNUM) (compare:CCFP (match_operand:SF 0 "cirrus_fp_register" "v") (match_operand:SF 1 "cirrus_fp_register" "v")))] - "TARGET_ARM && TARGET_CIRRUS" + "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK" "cfcmps%?\\tr15, %V0, %V1" - [(set_attr "cirrus_type" "farith") + [(set_attr "type" "mav_farith") (set_attr "cirrus" "compare")] ) @@ -5597,9 +6794,9 @@ [(set (reg:CCFP CC_REGNUM) (compare:CCFP (match_operand:DF 0 "cirrus_fp_register" "v") (match_operand:DF 1 "cirrus_fp_register" "v")))] - "TARGET_ARM && TARGET_CIRRUS" + "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK" "cfcmpd%?\\tr15, %V0, %V1" - [(set_attr "cirrus_type" "farith") + [(set_attr "type" "mav_farith") (set_attr "cirrus" "compare")] ) @@ -5607,80 +6804,21 @@ (define_expand "cmpdi" [(match_operand:DI 0 "cirrus_fp_register" "") (match_operand:DI 1 "cirrus_fp_register" "")] - "TARGET_ARM && TARGET_CIRRUS" - "{ - arm_compare_op0 = operands[0]; - arm_compare_op1 = operands[1]; - DONE; - }") - -(define_insn "*cirrus_cmpdi" - [(set (reg:CC CC_REGNUM) - (compare:CC (match_operand:DI 0 "cirrus_fp_register" "v") - (match_operand:DI 1 "cirrus_fp_register" "v")))] - "TARGET_ARM && TARGET_CIRRUS" - "cfcmp64%?\\tr15, %V0, %V1" - [(set_attr "cirrus_type" "farith") - (set_attr "cirrus" "compare")] -) - -;; Cirrus SI compare instruction -(define_insn "*cirrus_cmpsi_1" - [(set (reg:CC CC_REGNUM) - (compare:CC (match_operand:SI 0 "cirrus_fp_register" "v") - (match_operand:SI 1 "cirrus_fp_register" "v")))] - "TARGET_ARM && TARGET_CIRRUS && 0" - "cfcmp32%?\\tr15, %V0, %V1" - [(set_attr "cirrus_type" "farith") - (set_attr "cirrus" "compare")] -) - -(define_insn "*cmpsf_trap" - [(set (reg:CCFPE CC_REGNUM) - (compare:CCFPE (match_operand:SF 0 "s_register_operand" "f,f") - (match_operand:SF 1 "fpu_add_operand" "fG,H")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "@ - cmf%?e\\t%0, %1 - cnf%?e\\t%0, #%N1" - [(set_attr "conds" "set") - (set_attr "type" "f_2_r")] -) - -(define_insn "*cmpdf_trap" - [(set (reg:CCFPE CC_REGNUM) - (compare:CCFPE (match_operand:DF 0 "s_register_operand" "f,f") - (match_operand:DF 1 "fpu_add_operand" "fG,H")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "@ - cmf%?e\\t%0, %1 - cnf%?e\\t%0, #%N1" - [(set_attr "conds" "set") - (set_attr "type" "f_2_r")] -) - -(define_insn "*cmp_esfdf_df_trap" - [(set (reg:CCFPE CC_REGNUM) - (compare:CCFPE (float_extend:DF - (match_operand:SF 0 "s_register_operand" "f,f")) - (match_operand:DF 1 "fpu_add_operand" "fG,H")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "@ - cmf%?e\\t%0, %1 - cnf%?e\\t%0, #%N1" - [(set_attr "conds" "set") - (set_attr "type" "f_2_r")] -) + "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK" + "{ + arm_compare_op0 = operands[0]; + arm_compare_op1 = operands[1]; + DONE; + }") -(define_insn "*cmp_df_esfdf_trap" - [(set (reg:CCFPE CC_REGNUM) - (compare:CCFPE (match_operand:DF 0 "s_register_operand" "f") - (float_extend:DF - (match_operand:SF 1 "s_register_operand" "f"))))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "cmf%?e\\t%0, %1" - [(set_attr "conds" "set") - (set_attr "type" "f_2_r")] +(define_insn "*cirrus_cmpdi" + [(set (reg:CC CC_REGNUM) + (compare:CC (match_operand:DI 0 "cirrus_fp_register" "v") + (match_operand:DI 1 "cirrus_fp_register" "v")))] + "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK" + "cfcmp64%?\\tr15, %V0, %V1" + [(set_attr "type" "mav_farith") + (set_attr "cirrus" "compare")] ) ; This insn allows redundant compares to be removed by cse, nothing should @@ -5795,7 +6933,7 @@ (if_then_else (unordered (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "operands[1] = arm_gen_compare_reg (UNORDERED, arm_compare_op0, arm_compare_op1);" ) @@ -5805,7 +6943,7 @@ (if_then_else (ordered (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "operands[1] = arm_gen_compare_reg (ORDERED, arm_compare_op0, arm_compare_op1);" ) @@ -5815,7 +6953,7 @@ (if_then_else (ungt (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "operands[1] = arm_gen_compare_reg (UNGT, arm_compare_op0, arm_compare_op1);" ) @@ -5824,7 +6962,7 @@ (if_then_else (unlt (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "operands[1] = arm_gen_compare_reg (UNLT, arm_compare_op0, arm_compare_op1);" ) @@ -5833,7 +6971,7 @@ (if_then_else (unge (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "operands[1] = arm_gen_compare_reg (UNGE, arm_compare_op0, arm_compare_op1);" ) @@ -5842,7 +6980,7 @@ (if_then_else (unle (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "operands[1] = arm_gen_compare_reg (UNLE, arm_compare_op0, arm_compare_op1);" ) @@ -5853,7 +6991,7 @@ (if_then_else (uneq (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "operands[1] = arm_gen_compare_reg (UNEQ, arm_compare_op0, arm_compare_op1);" ) @@ -5862,7 +7000,7 @@ (if_then_else (ltgt (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "operands[1] = arm_gen_compare_reg (LTGT, arm_compare_op0, arm_compare_op1);" ) @@ -5876,10 +7014,9 @@ (if_then_else (uneq (match_operand 1 "cc_register" "") (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "* - if (arm_ccfsm_state != 0) - abort (); + gcc_assert (!arm_ccfsm_state); return \"bvs\\t%l0\;beq\\t%l0\"; " @@ -5893,10 +7030,9 @@ (if_then_else (ltgt (match_operand 1 "cc_register" "") (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "* - if (arm_ccfsm_state != 0) - abort (); + gcc_assert (!arm_ccfsm_state); return \"bmi\\t%l0\;bgt\\t%l0\"; " @@ -5919,7 +7055,8 @@ } return \"b%d1\\t%l0\"; " - [(set_attr "conds" "use")] + [(set_attr "conds" "use") + (set_attr "type" "branch")] ) ; Special pattern to match reversed UNEQ. @@ -5928,10 +7065,9 @@ (if_then_else (uneq (match_operand 1 "cc_register" "") (const_int 0)) (pc) (label_ref (match_operand 0 "" ""))))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "* - if (arm_ccfsm_state != 0) - abort (); + gcc_assert (!arm_ccfsm_state); return \"bmi\\t%l0\;bgt\\t%l0\"; " @@ -5945,10 +7081,9 @@ (if_then_else (ltgt (match_operand 1 "cc_register" "") (const_int 0)) (pc) (label_ref (match_operand 0 "" ""))))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "* - if (arm_ccfsm_state != 0) - abort (); + gcc_assert (!arm_ccfsm_state); return \"bvs\\t%l0\;beq\\t%l0\"; " @@ -5971,7 +7106,8 @@ } return \"b%D1\\t%l0\"; " - [(set_attr "conds" "use")] + [(set_attr "conds" "use") + (set_attr "type" "branch")] ) @@ -5979,119 +7115,119 @@ ; scc insns (define_expand "seq" - [(set (match_operand:SI 0 "s_register_operand" "=r") + [(set (match_operand:SI 0 "s_register_operand" "") (eq:SI (match_dup 1) (const_int 0)))] "TARGET_ARM" "operands[1] = arm_gen_compare_reg (EQ, arm_compare_op0, arm_compare_op1);" ) (define_expand "sne" - [(set (match_operand:SI 0 "s_register_operand" "=r") + [(set (match_operand:SI 0 "s_register_operand" "") (ne:SI (match_dup 1) (const_int 0)))] "TARGET_ARM" "operands[1] = arm_gen_compare_reg (NE, arm_compare_op0, arm_compare_op1);" ) (define_expand "sgt" - [(set (match_operand:SI 0 "s_register_operand" "=r") + [(set (match_operand:SI 0 "s_register_operand" "") (gt:SI (match_dup 1) (const_int 0)))] "TARGET_ARM" "operands[1] = arm_gen_compare_reg (GT, arm_compare_op0, arm_compare_op1);" ) (define_expand "sle" - [(set (match_operand:SI 0 "s_register_operand" "=r") + [(set (match_operand:SI 0 "s_register_operand" "") (le:SI (match_dup 1) (const_int 0)))] "TARGET_ARM" "operands[1] = arm_gen_compare_reg (LE, arm_compare_op0, arm_compare_op1);" ) (define_expand "sge" - [(set (match_operand:SI 0 "s_register_operand" "=r") + [(set (match_operand:SI 0 "s_register_operand" "") (ge:SI (match_dup 1) (const_int 0)))] "TARGET_ARM" "operands[1] = arm_gen_compare_reg (GE, arm_compare_op0, arm_compare_op1);" ) (define_expand "slt" - [(set (match_operand:SI 0 "s_register_operand" "=r") + [(set (match_operand:SI 0 "s_register_operand" "") (lt:SI (match_dup 1) (const_int 0)))] "TARGET_ARM" "operands[1] = arm_gen_compare_reg (LT, arm_compare_op0, arm_compare_op1);" ) (define_expand "sgtu" - [(set (match_operand:SI 0 "s_register_operand" "=r") + [(set (match_operand:SI 0 "s_register_operand" "") (gtu:SI (match_dup 1) (const_int 0)))] "TARGET_ARM" "operands[1] = arm_gen_compare_reg (GTU, arm_compare_op0, arm_compare_op1);" ) (define_expand "sleu" - [(set (match_operand:SI 0 "s_register_operand" "=r") + [(set (match_operand:SI 0 "s_register_operand" "") (leu:SI (match_dup 1) (const_int 0)))] "TARGET_ARM" "operands[1] = arm_gen_compare_reg (LEU, arm_compare_op0, arm_compare_op1);" ) (define_expand "sgeu" - [(set (match_operand:SI 0 "s_register_operand" "=r") + [(set (match_operand:SI 0 "s_register_operand" "") (geu:SI (match_dup 1) (const_int 0)))] "TARGET_ARM" "operands[1] = arm_gen_compare_reg (GEU, arm_compare_op0, arm_compare_op1);" ) (define_expand "sltu" - [(set (match_operand:SI 0 "s_register_operand" "=r") + [(set (match_operand:SI 0 "s_register_operand" "") (ltu:SI (match_dup 1) (const_int 0)))] "TARGET_ARM" "operands[1] = arm_gen_compare_reg (LTU, arm_compare_op0, arm_compare_op1);" ) (define_expand "sunordered" - [(set (match_operand:SI 0 "s_register_operand" "=r") + [(set (match_operand:SI 0 "s_register_operand" "") (unordered:SI (match_dup 1) (const_int 0)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "operands[1] = arm_gen_compare_reg (UNORDERED, arm_compare_op0, arm_compare_op1);" ) (define_expand "sordered" - [(set (match_operand:SI 0 "s_register_operand" "=r") + [(set (match_operand:SI 0 "s_register_operand" "") (ordered:SI (match_dup 1) (const_int 0)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "operands[1] = arm_gen_compare_reg (ORDERED, arm_compare_op0, arm_compare_op1);" ) (define_expand "sungt" - [(set (match_operand:SI 0 "s_register_operand" "=r") + [(set (match_operand:SI 0 "s_register_operand" "") (ungt:SI (match_dup 1) (const_int 0)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "operands[1] = arm_gen_compare_reg (UNGT, arm_compare_op0, arm_compare_op1);" ) (define_expand "sunge" - [(set (match_operand:SI 0 "s_register_operand" "=r") + [(set (match_operand:SI 0 "s_register_operand" "") (unge:SI (match_dup 1) (const_int 0)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "operands[1] = arm_gen_compare_reg (UNGE, arm_compare_op0, arm_compare_op1);" ) (define_expand "sunlt" - [(set (match_operand:SI 0 "s_register_operand" "=r") + [(set (match_operand:SI 0 "s_register_operand" "") (unlt:SI (match_dup 1) (const_int 0)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "operands[1] = arm_gen_compare_reg (UNLT, arm_compare_op0, arm_compare_op1);" ) (define_expand "sunle" - [(set (match_operand:SI 0 "s_register_operand" "=r") + [(set (match_operand:SI 0 "s_register_operand" "") (unle:SI (match_dup 1) (const_int 0)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "operands[1] = arm_gen_compare_reg (UNLE, arm_compare_op0, arm_compare_op1);" ) @@ -6100,17 +7236,17 @@ ;;; simple ARM instructions. ; ; (define_expand "suneq" -; [(set (match_operand:SI 0 "s_register_operand" "=r") +; [(set (match_operand:SI 0 "s_register_operand" "") ; (uneq:SI (match_dup 1) (const_int 0)))] -; "TARGET_ARM && TARGET_HARD_FLOAT" -; "abort ();" +; "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" +; "gcc_unreachable ();" ; ) ; ; (define_expand "sltgt" -; [(set (match_operand:SI 0 "s_register_operand" "=r") +; [(set (match_operand:SI 0 "s_register_operand" "") ; (ltgt:SI (match_dup 1) (const_int 0)))] -; "TARGET_ARM && TARGET_HARD_FLOAT" -; "abort ();" +; "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" +; "gcc_unreachable ();" ; ) (define_insn "*mov_scc" @@ -6161,7 +7297,7 @@ FAIL; ccreg = arm_gen_compare_reg (code, arm_compare_op0, arm_compare_op1); - operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx); + operands[1] = gen_rtx_fmt_ee (code, VOIDmode, ccreg, const0_rtx); }" ) @@ -6181,12 +7317,12 @@ /* When compiling for SOFT_FLOAT, ensure both arms are in registers. Otherwise, ensure it is a valid FP add operand */ - if ((!TARGET_HARD_FLOAT) - || (!fpu_add_operand (operands[3], SFmode))) + if ((!(TARGET_HARD_FLOAT && TARGET_FPA)) + || (!arm_float_add_operand (operands[3], SFmode))) operands[3] = force_reg (SFmode, operands[3]); ccreg = arm_gen_compare_reg (code, arm_compare_op0, arm_compare_op1); - operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx); + operands[1] = gen_rtx_fmt_ee (code, VOIDmode, ccreg, const0_rtx); }" ) @@ -6194,8 +7330,8 @@ [(set (match_operand:DF 0 "s_register_operand" "") (if_then_else:DF (match_operand 1 "arm_comparison_operator" "") (match_operand:DF 2 "s_register_operand" "") - (match_operand:DF 3 "fpu_add_operand" "")))] - "TARGET_ARM && TARGET_HARD_FLOAT" + (match_operand:DF 3 "arm_float_add_operand" "")))] + "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" " { enum rtx_code code = GET_CODE (operands[1]); @@ -6205,7 +7341,7 @@ FAIL; ccreg = arm_gen_compare_reg (code, arm_compare_op0, arm_compare_op1); - operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx); + operands[1] = gen_rtx_fmt_ee (code, VOIDmode, ccreg, const0_rtx); }" ) @@ -6230,28 +7366,6 @@ (set_attr "conds" "use")] ) -(define_insn "*movsfcc_hard_insn" - [(set (match_operand:SF 0 "s_register_operand" "=f,f,f,f,f,f,f,f") - (if_then_else:SF - (match_operator 3 "arm_comparison_operator" - [(match_operand 4 "cc_register" "") (const_int 0)]) - (match_operand:SF 1 "fpu_add_operand" "0,0,fG,H,fG,fG,H,H") - (match_operand:SF 2 "fpu_add_operand" "fG,H,0,0,fG,H,fG,H")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "@ - mvf%D3s\\t%0, %2 - mnf%D3s\\t%0, #%N2 - mvf%d3s\\t%0, %1 - mnf%d3s\\t%0, #%N1 - mvf%d3s\\t%0, %1\;mvf%D3s\\t%0, %2 - mvf%d3s\\t%0, %1\;mnf%D3s\\t%0, #%N2 - mnf%d3s\\t%0, #%N1\;mvf%D3s\\t%0, %2 - mnf%d3s\\t%0, #%N1\;mnf%D3s\\t%0, #%N2" - [(set_attr "length" "4,4,4,4,8,8,8,8") - (set_attr "type" "ffarith") - (set_attr "conds" "use")] -) - (define_insn "*movsfcc_soft_insn" [(set (match_operand:SF 0 "s_register_operand" "=r,r") (if_then_else:SF (match_operator 3 "arm_comparison_operator" @@ -6265,28 +7379,6 @@ [(set_attr "conds" "use")] ) -(define_insn "*movdfcc_insn" - [(set (match_operand:DF 0 "s_register_operand" "=f,f,f,f,f,f,f,f") - (if_then_else:DF - (match_operator 3 "arm_comparison_operator" - [(match_operand 4 "cc_register" "") (const_int 0)]) - (match_operand:DF 1 "fpu_add_operand" "0,0,fG,H,fG,fG,H,H") - (match_operand:DF 2 "fpu_add_operand" "fG,H,0,0,fG,H,fG,H")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "@ - mvf%D3d\\t%0, %2 - mnf%D3d\\t%0, #%N2 - mvf%d3d\\t%0, %1 - mnf%d3d\\t%0, #%N1 - mvf%d3d\\t%0, %1\;mvf%D3d\\t%0, %2 - mvf%d3d\\t%0, %1\;mnf%D3d\\t%0, #%N2 - mnf%d3d\\t%0, #%N1\;mvf%D3d\\t%0, %2 - mnf%d3d\\t%0, #%N1\;mnf%D3d\\t%0, #%N2" - [(set_attr "length" "4,4,4,4,8,8,8,8") - (set_attr "type" "ffarith") - (set_attr "conds" "use")] -) - ;; Jump and linkage insns @@ -6330,8 +7422,8 @@ (const_string "no"))) (set (attr "length") (if_then_else - (and (ge (minus (match_dup 0) (pc)) (const_int -2048)) - (le (minus (match_dup 0) (pc)) (const_int 2044))) + (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) + (le (minus (match_dup 0) (pc)) (const_int 2048))) (const_int 2) (const_int 4)))] ) @@ -6368,12 +7460,22 @@ }" ) -(define_insn "*call_reg" +(define_insn "*call_reg_armv5" [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r")) (match_operand 1 "" "")) (use (match_operand 2 "" "")) (clobber (reg:SI LR_REGNUM))] - "TARGET_ARM" + "TARGET_ARM && arm_arch5" + "blx%?\\t%0" + [(set_attr "type" "call")] +) + +(define_insn "*call_reg_arm" + [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r")) + (match_operand 1 "" "")) + (use (match_operand 2 "" "")) + (clobber (reg:SI LR_REGNUM))] + "TARGET_ARM && !arm_arch5" "* return output_call (operands); " @@ -6395,35 +7497,33 @@ (set_attr "type" "call")] ) -(define_insn "*call_indirect" +(define_insn "*call_reg_thumb_v5" [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r")) (match_operand 1 "" "")) (use (match_operand 2 "" "")) (clobber (reg:SI LR_REGNUM))] - "TARGET_THUMB" - "* - { - if (TARGET_CALLER_INTERWORKING) - return \"bl\\t%__interwork_call_via_%0\"; - else - return \"bl\\t%__call_via_%0\"; - }" - [(set_attr "type" "call")] + "TARGET_THUMB && arm_arch5" + "blx\\t%0" + [(set_attr "length" "2") + (set_attr "type" "call")] ) -(define_insn "*call_value_indirect" - [(set (match_operand 0 "" "=l") - (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) - (match_operand 2 "" ""))) - (use (match_operand 3 "" "")) +(define_insn "*call_reg_thumb" + [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r")) + (match_operand 1 "" "")) + (use (match_operand 2 "" "")) (clobber (reg:SI LR_REGNUM))] - "TARGET_THUMB" + "TARGET_THUMB && !arm_arch5" "* { - if (TARGET_CALLER_INTERWORKING) - return \"bl\\t%__interwork_call_via_%1\"; + if (!TARGET_CALLER_INTERWORKING) + return thumb_call_via_reg (operands[0]); + else if (operands[1] == const0_rtx) + return \"bl\\t%__interwork_call_via_%0\"; + else if (frame_pointer_needed) + return \"bl\\t%__interwork_r7_call_via_%0\"; else - return \"bl\\t%__call_via_%1\"; + return \"bl\\t%__interwork_r11_call_via_%0\"; }" [(set_attr "type" "call")] ) @@ -6450,13 +7550,24 @@ }" ) -(define_insn "*call_value_reg" - [(set (match_operand 0 "" "=r,f,v") - (call (mem:SI (match_operand:SI 1 "s_register_operand" "r,r,r")) +(define_insn "*call_value_reg_armv5" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:SI 1 "s_register_operand" "r")) (match_operand 2 "" ""))) (use (match_operand 3 "" "")) (clobber (reg:SI LR_REGNUM))] - "TARGET_ARM" + "TARGET_ARM && arm_arch5" + "blx%?\\t%1" + [(set_attr "type" "call")] +) + +(define_insn "*call_value_reg_arm" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:SI 1 "s_register_operand" "r")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" "")) + (clobber (reg:SI LR_REGNUM))] + "TARGET_ARM && !arm_arch5" "* return output_call (&operands[1]); " @@ -6465,8 +7576,8 @@ ) (define_insn "*call_value_mem" - [(set (match_operand 0 "" "=r,f,v") - (call (mem:SI (match_operand:SI 1 "memory_operand" "m,m,m")) + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:SI 1 "memory_operand" "m")) (match_operand 2 "" ""))) (use (match_operand 3 "" "")) (clobber (reg:SI LR_REGNUM))] @@ -6478,11 +7589,44 @@ (set_attr "type" "call")] ) +(define_insn "*call_value_reg_thumb_v5" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" "")) + (clobber (reg:SI LR_REGNUM))] + "TARGET_THUMB && arm_arch5" + "blx\\t%1" + [(set_attr "length" "2") + (set_attr "type" "call")] +) + +(define_insn "*call_value_reg_thumb" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" "")) + (clobber (reg:SI LR_REGNUM))] + "TARGET_THUMB && !arm_arch5" + "* + { + if (!TARGET_CALLER_INTERWORKING) + return thumb_call_via_reg (operands[1]); + else if (operands[2] == const0_rtx) + return \"bl\\t%__interwork_call_via_%1\"; + else if (frame_pointer_needed) + return \"bl\\t%__interwork_r7_call_via_%1\"; + else + return \"bl\\t%__interwork_r11_call_via_%1\"; + }" + [(set_attr "type" "call")] +) + ;; Allow calls to SYMBOL_REFs specially as they are not valid general addresses ;; The 'a' causes the operand to be treated as an address, i.e. no '#' output. (define_insn "*call_symbol" - [(call (mem:SI (match_operand:SI 0 "" "X")) + [(call (mem:SI (match_operand:SI 0 "" "")) (match_operand 1 "" "")) (use (match_operand 2 "" "")) (clobber (reg:SI LR_REGNUM))] @@ -6497,8 +7641,8 @@ ) (define_insn "*call_value_symbol" - [(set (match_operand 0 "s_register_operand" "=r,f,v") - (call (mem:SI (match_operand:SI 1 "" "X,X,X")) + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:SI 1 "" "")) (match_operand:SI 2 "" ""))) (use (match_operand 3 "" "")) (clobber (reg:SI LR_REGNUM))] @@ -6513,7 +7657,7 @@ ) (define_insn "*call_insn" - [(call (mem:SI (match_operand:SI 0 "" "X")) + [(call (mem:SI (match_operand:SI 0 "" "")) (match_operand:SI 1 "" "")) (use (match_operand 2 "" "")) (clobber (reg:SI LR_REGNUM))] @@ -6526,8 +7670,8 @@ ) (define_insn "*call_value_insn" - [(set (match_operand 0 "register_operand" "=l") - (call (mem:SI (match_operand 1 "" "X")) + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand 1 "" "")) (match_operand 2 "" ""))) (use (match_operand 3 "" "")) (clobber (reg:SI LR_REGNUM))] @@ -6554,7 +7698,7 @@ ) (define_expand "sibcall_value" - [(parallel [(set (match_operand 0 "register_operand" "") + [(parallel [(set (match_operand 0 "" "") (call (match_operand 1 "memory_operand" "") (match_operand 2 "general_operand" ""))) (return) @@ -6580,8 +7724,8 @@ ) (define_insn "*sibcall_value_insn" - [(set (match_operand 0 "s_register_operand" "=r,f,v") - (call (mem:SI (match_operand:SI 1 "" "X,X,X")) + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:SI 1 "" "X")) (match_operand 2 "" ""))) (return) (use (match_operand 3 "" ""))] @@ -6605,7 +7749,8 @@ } return output_return_instruction (const_true_rtx, TRUE, FALSE); }" - [(set_attr "type" "load") + [(set_attr "type" "load1") + (set_attr "length" "12") (set_attr "predicable" "yes")] ) @@ -6626,7 +7771,8 @@ return output_return_instruction (operands[0], TRUE, FALSE); }" [(set_attr "conds" "use") - (set_attr "type" "load")] + (set_attr "length" "12") + (set_attr "type" "load1")] ) (define_insn "*cond_return_inverted" @@ -6646,7 +7792,8 @@ return output_return_instruction (operands[0], TRUE, TRUE); }" [(set_attr "conds" "use") - (set_attr "type" "load")] + (set_attr "length" "12") + (set_attr "type" "load1")] ) ;; Generate a sequence of instructions to determine if the processor is @@ -6663,7 +7810,7 @@ (const_int 67108860)))] ; 0x03fffffc "TARGET_ARM" " - operands[1] = gen_rtx_REG (CC_NOOVmode, 24); + operands[1] = gen_rtx_REG (CC_NOOVmode, CC_REGNUM); ") (define_insn "*check_arch2" @@ -6683,18 +7830,59 @@ (const_int 0)) (match_operand 1 "" "") (match_operand 2 "" "")])] - "TARGET_ARM" + "TARGET_EITHER" " { int i; + rtx par = gen_rtx_PARALLEL (VOIDmode, + rtvec_alloc (XVECLEN (operands[2], 0))); + rtx addr = gen_reg_rtx (Pmode); + rtx mem; + int size = 0; - emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx)); + emit_move_insn (addr, XEXP (operands[1], 0)); + mem = change_address (operands[1], BLKmode, addr); for (i = 0; i < XVECLEN (operands[2], 0); i++) { - rtx set = XVECEXP (operands[2], 0, i); + rtx src = SET_SRC (XVECEXP (operands[2], 0, i)); + + /* Default code only uses r0 as a return value, but we could + be using anything up to 4 registers. */ + if (REGNO (src) == R0_REGNUM) + src = gen_rtx_REG (TImode, R0_REGNUM); + + XVECEXP (par, 0, i) = gen_rtx_EXPR_LIST (VOIDmode, src, + GEN_INT (size)); + size += GET_MODE_SIZE (GET_MODE (src)); + } + + emit_call_insn (GEN_CALL_VALUE (par, operands[0], const0_rtx, NULL, + const0_rtx)); + + size = 0; + + for (i = 0; i < XVECLEN (par, 0); i++) + { + HOST_WIDE_INT offset = 0; + rtx reg = XEXP (XVECEXP (par, 0, i), 0); + + if (size != 0) + emit_move_insn (addr, plus_constant (addr, size)); - emit_move_insn (SET_DEST (set), SET_SRC (set)); + mem = change_address (mem, GET_MODE (reg), NULL); + if (REGNO (reg) == R0_REGNUM) + { + /* On thumb we have to use a write-back instruction. */ + emit_insn (arm_gen_store_multiple (R0_REGNUM, 4, addr, TRUE, + TARGET_THUMB ? TRUE : FALSE, mem, &offset)); + size = TARGET_ARM ? 16 : 0; + } + else + { + emit_move_insn (mem, reg); + size = GET_MODE_SIZE (GET_MODE (reg)); + } } /* The optimizer does not know that the call sets the function value @@ -6707,6 +7895,55 @@ }" ) +(define_expand "untyped_return" + [(match_operand:BLK 0 "memory_operand" "") + (match_operand 1 "" "")] + "TARGET_EITHER" + " + { + int i; + rtx addr = gen_reg_rtx (Pmode); + rtx mem; + int size = 0; + + emit_move_insn (addr, XEXP (operands[0], 0)); + mem = change_address (operands[0], BLKmode, addr); + + for (i = 0; i < XVECLEN (operands[1], 0); i++) + { + HOST_WIDE_INT offset = 0; + rtx reg = SET_DEST (XVECEXP (operands[1], 0, i)); + + if (size != 0) + emit_move_insn (addr, plus_constant (addr, size)); + + mem = change_address (mem, GET_MODE (reg), NULL); + if (REGNO (reg) == R0_REGNUM) + { + /* On thumb we have to use a write-back instruction. */ + emit_insn (arm_gen_load_multiple (R0_REGNUM, 4, addr, TRUE, + TARGET_THUMB ? TRUE : FALSE, mem, &offset)); + size = TARGET_ARM ? 16 : 0; + } + else + { + emit_move_insn (reg, mem); + size = GET_MODE_SIZE (GET_MODE (reg)); + } + } + + /* Emit USE insns before the return. */ + for (i = 0; i < XVECLEN (operands[1], 0); i++) + emit_insn (gen_rtx_USE (VOIDmode, + SET_DEST (XVECEXP (operands[1], 0, i)))); + + /* Construct the return. */ + expand_naked_return (); + + DONE; + }" +) + ;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and ;; all of memory. This blocks insns from being moved across this point. @@ -6775,6 +8012,7 @@ "" ) +;; NB Never uses BX. (define_insn "*arm_indirect_jump" [(set (pc) (match_operand:SI 0 "s_register_operand" "r"))] @@ -6783,19 +8021,18 @@ [(set_attr "predicable" "yes")] ) -;; Although not supported by the define_expand above, -;; cse/combine may generate this form. (define_insn "*load_indirect_jump" [(set (pc) (match_operand:SI 0 "memory_operand" "m"))] "TARGET_ARM" "ldr%?\\t%|pc, %0\\t%@ indirect memory jump" - [(set_attr "type" "load") + [(set_attr "type" "load1") (set_attr "pool_range" "4096") (set_attr "neg_pool_range" "4084") (set_attr "predicable" "yes")] ) +;; NB Never uses BX. (define_insn "*thumb_indirect_jump" [(set (pc) (match_operand:SI 0 "register_operand" "l*r"))] @@ -6836,9 +8073,29 @@ "%i1%?\\t%0, %2, %4%S3" [(set_attr "predicable" "yes") (set_attr "shift" "4") - ] + (set (attr "type") (if_then_else (match_operand 5 "const_int_operand" "") + (const_string "alu_shift") + (const_string "alu_shift_reg")))] ) +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (match_operator:SI 1 "shiftable_operator" + [(match_operator:SI 2 "shiftable_operator" + [(match_operator:SI 3 "shift_operator" + [(match_operand:SI 4 "s_register_operand" "") + (match_operand:SI 5 "reg_or_int_operand" "")]) + (match_operand:SI 6 "s_register_operand" "")]) + (match_operand:SI 7 "arm_rhs_operand" "")])) + (clobber (match_operand:SI 8 "s_register_operand" ""))] + "TARGET_ARM" + [(set (match_dup 8) + (match_op_dup 2 [(match_op_dup 3 [(match_dup 4) (match_dup 5)]) + (match_dup 6)])) + (set (match_dup 0) + (match_op_dup 1 [(match_dup 8) (match_dup 7)]))] + "") + (define_insn "*arith_shiftsi_compare0" [(set (reg:CC_NOOV CC_REGNUM) (compare:CC_NOOV (match_operator:SI 1 "shiftable_operator" @@ -6854,7 +8111,9 @@ "%i1%?s\\t%0, %2, %4%S3" [(set_attr "conds" "set") (set_attr "shift" "4") - ] + (set (attr "type") (if_then_else (match_operand 5 "const_int_operand" "") + (const_string "alu_shift") + (const_string "alu_shift_reg")))] ) (define_insn "*arith_shiftsi_compare0_scratch" @@ -6870,7 +8129,9 @@ "%i1%?s\\t%0, %2, %4%S3" [(set_attr "conds" "set") (set_attr "shift" "4") - ] + (set (attr "type") (if_then_else (match_operand 5 "const_int_operand" "") + (const_string "alu_shift") + (const_string "alu_shift_reg")))] ) (define_insn "*sub_shiftsi" @@ -6883,7 +8144,9 @@ "sub%?\\t%0, %1, %3%S2" [(set_attr "predicable" "yes") (set_attr "shift" "3") - ] + (set (attr "type") (if_then_else (match_operand 4 "const_int_operand" "") + (const_string "alu_shift") + (const_string "alu_shift_reg")))] ) (define_insn "*sub_shiftsi_compare0" @@ -6900,8 +8163,10 @@ "TARGET_ARM" "sub%?s\\t%0, %1, %3%S2" [(set_attr "conds" "set") - (set_attr "shift" "3") - ] + (set_attr "shift" "3") + (set (attr "type") (if_then_else (match_operand 4 "const_int_operand" "") + (const_string "alu_shift") + (const_string "alu_shift_reg")))] ) (define_insn "*sub_shiftsi_compare0_scratch" @@ -6916,8 +8181,10 @@ "TARGET_ARM" "sub%?s\\t%0, %1, %3%S2" [(set_attr "conds" "set") - (set_attr "shift" "3") - ] + (set_attr "shift" "3") + (set (attr "type") (if_then_else (match_operand 4 "const_int_operand" "") + (const_string "alu_shift") + (const_string "alu_shift_reg")))] ) @@ -6954,11 +8221,17 @@ (clobber (reg:CC CC_REGNUM))] "TARGET_ARM" "* - if (GET_CODE (operands[1]) == LT && operands[3] == const0_rtx) - return \"mov\\t%0, %2, lsr #31\"; + if (operands[3] == const0_rtx) + { + if (GET_CODE (operands[1]) == LT) + return \"mov\\t%0, %2, lsr #31\"; + + if (GET_CODE (operands[1]) == GE) + return \"mvn\\t%0, %2\;mov\\t%0, %0, lsr #31\"; - if (GET_CODE (operands[1]) == GE && operands[3] == const0_rtx) - return \"mvn\\t%0, %2\;mov\\t%0, %0, lsr #31\"; + if (GET_CODE (operands[1]) == EQ) + return \"rsbs\\t%0, %2, #1\;movcc\\t%0, #0\"; + } if (GET_CODE (operands[1]) == NE) { @@ -7182,12 +8455,198 @@ int swap = comparison_dominates_p (GET_CODE (operands[5]), GET_CODE (operands[4])); - return opcodes[which_alternative][swap]; -} -" - [(set_attr "conds" "set") - (set_attr "length" "8")] -) + return opcodes[which_alternative][swap]; +} +" + [(set_attr "conds" "set") + (set_attr "length" "8")] +) + +(define_insn_and_split "*ior_scc_scc" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (ior:SI (match_operator:SI 3 "arm_comparison_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_add_operand" "rIL")]) + (match_operator:SI 6 "arm_comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r") + (match_operand:SI 5 "arm_add_operand" "rIL")]))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_ARM + && (arm_select_dominance_cc_mode (operands[3], operands[6], DOM_CC_X_OR_Y) + != CCmode)" + "#" + "TARGET_ARM && reload_completed" + [(set (match_dup 7) + (compare + (ior:SI + (match_op_dup 3 [(match_dup 1) (match_dup 2)]) + (match_op_dup 6 [(match_dup 4) (match_dup 5)])) + (const_int 0))) + (set (match_dup 0) (ne:SI (match_dup 7) (const_int 0)))] + "operands[7] + = gen_rtx_REG (arm_select_dominance_cc_mode (operands[3], operands[6], + DOM_CC_X_OR_Y), + CC_REGNUM);" + [(set_attr "conds" "clob") + (set_attr "length" "16")]) + +; If the above pattern is followed by a CMP insn, then the compare is +; redundant, since we can rework the conditional instruction that follows. +(define_insn_and_split "*ior_scc_scc_cmp" + [(set (match_operand 0 "dominant_cc_register" "") + (compare (ior:SI (match_operator:SI 3 "arm_comparison_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_add_operand" "rIL")]) + (match_operator:SI 6 "arm_comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r") + (match_operand:SI 5 "arm_add_operand" "rIL")])) + (const_int 0))) + (set (match_operand:SI 7 "s_register_operand" "=r") + (ior:SI (match_op_dup 3 [(match_dup 1) (match_dup 2)]) + (match_op_dup 6 [(match_dup 4) (match_dup 5)])))] + "TARGET_ARM" + "#" + "TARGET_ARM && reload_completed" + [(set (match_dup 0) + (compare + (ior:SI + (match_op_dup 3 [(match_dup 1) (match_dup 2)]) + (match_op_dup 6 [(match_dup 4) (match_dup 5)])) + (const_int 0))) + (set (match_dup 7) (ne:SI (match_dup 0) (const_int 0)))] + "" + [(set_attr "conds" "set") + (set_attr "length" "16")]) + +(define_insn_and_split "*and_scc_scc" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (and:SI (match_operator:SI 3 "arm_comparison_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_add_operand" "rIL")]) + (match_operator:SI 6 "arm_comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r") + (match_operand:SI 5 "arm_add_operand" "rIL")]))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_ARM + && (arm_select_dominance_cc_mode (operands[3], operands[6], DOM_CC_X_AND_Y) + != CCmode)" + "#" + "TARGET_ARM && reload_completed + && (arm_select_dominance_cc_mode (operands[3], operands[6], DOM_CC_X_AND_Y) + != CCmode)" + [(set (match_dup 7) + (compare + (and:SI + (match_op_dup 3 [(match_dup 1) (match_dup 2)]) + (match_op_dup 6 [(match_dup 4) (match_dup 5)])) + (const_int 0))) + (set (match_dup 0) (ne:SI (match_dup 7) (const_int 0)))] + "operands[7] + = gen_rtx_REG (arm_select_dominance_cc_mode (operands[3], operands[6], + DOM_CC_X_AND_Y), + CC_REGNUM);" + [(set_attr "conds" "clob") + (set_attr "length" "16")]) + +; If the above pattern is followed by a CMP insn, then the compare is +; redundant, since we can rework the conditional instruction that follows. +(define_insn_and_split "*and_scc_scc_cmp" + [(set (match_operand 0 "dominant_cc_register" "") + (compare (and:SI (match_operator:SI 3 "arm_comparison_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_add_operand" "rIL")]) + (match_operator:SI 6 "arm_comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r") + (match_operand:SI 5 "arm_add_operand" "rIL")])) + (const_int 0))) + (set (match_operand:SI 7 "s_register_operand" "=r") + (and:SI (match_op_dup 3 [(match_dup 1) (match_dup 2)]) + (match_op_dup 6 [(match_dup 4) (match_dup 5)])))] + "TARGET_ARM" + "#" + "TARGET_ARM && reload_completed" + [(set (match_dup 0) + (compare + (and:SI + (match_op_dup 3 [(match_dup 1) (match_dup 2)]) + (match_op_dup 6 [(match_dup 4) (match_dup 5)])) + (const_int 0))) + (set (match_dup 7) (ne:SI (match_dup 0) (const_int 0)))] + "" + [(set_attr "conds" "set") + (set_attr "length" "16")]) + +;; If there is no dominance in the comparison, then we can still save an +;; instruction in the AND case, since we can know that the second compare +;; need only zero the value if false (if true, then the value is already +;; correct). +(define_insn_and_split "*and_scc_scc_nodom" + [(set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r") + (and:SI (match_operator:SI 3 "arm_comparison_operator" + [(match_operand:SI 1 "s_register_operand" "r,r,0") + (match_operand:SI 2 "arm_add_operand" "rIL,0,rIL")]) + (match_operator:SI 6 "arm_comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r,r,r") + (match_operand:SI 5 "arm_add_operand" "rIL,rIL,rIL")]))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_ARM + && (arm_select_dominance_cc_mode (operands[3], operands[6], DOM_CC_X_AND_Y) + == CCmode)" + "#" + "TARGET_ARM && reload_completed" + [(parallel [(set (match_dup 0) + (match_op_dup 3 [(match_dup 1) (match_dup 2)])) + (clobber (reg:CC CC_REGNUM))]) + (set (match_dup 7) (match_op_dup 8 [(match_dup 4) (match_dup 5)])) + (set (match_dup 0) + (if_then_else:SI (match_op_dup 6 [(match_dup 7) (const_int 0)]) + (match_dup 0) + (const_int 0)))] + "operands[7] = gen_rtx_REG (SELECT_CC_MODE (GET_CODE (operands[6]), + operands[4], operands[5]), + CC_REGNUM); + operands[8] = gen_rtx_COMPARE (GET_MODE (operands[7]), operands[4], + operands[5]);" + [(set_attr "conds" "clob") + (set_attr "length" "20")]) + +(define_split + [(set (reg:CC_NOOV CC_REGNUM) + (compare:CC_NOOV (ior:SI + (and:SI (match_operand:SI 0 "s_register_operand" "") + (const_int 1)) + (match_operator:SI 1 "comparison_operator" + [(match_operand:SI 2 "s_register_operand" "") + (match_operand:SI 3 "arm_add_operand" "")])) + (const_int 0))) + (clobber (match_operand:SI 4 "s_register_operand" ""))] + "TARGET_ARM" + [(set (match_dup 4) + (ior:SI (match_op_dup 1 [(match_dup 2) (match_dup 3)]) + (match_dup 0))) + (set (reg:CC_NOOV CC_REGNUM) + (compare:CC_NOOV (and:SI (match_dup 4) (const_int 1)) + (const_int 0)))] + "") + +(define_split + [(set (reg:CC_NOOV CC_REGNUM) + (compare:CC_NOOV (ior:SI + (match_operator:SI 1 "comparison_operator" + [(match_operand:SI 2 "s_register_operand" "") + (match_operand:SI 3 "arm_add_operand" "")]) + (and:SI (match_operand:SI 0 "s_register_operand" "") + (const_int 1))) + (const_int 0))) + (clobber (match_operand:SI 4 "s_register_operand" ""))] + "TARGET_ARM" + [(set (match_dup 4) + (ior:SI (match_op_dup 1 [(match_dup 2) (match_dup 3)]) + (match_dup 0))) + (set (reg:CC_NOOV CC_REGNUM) + (compare:CC_NOOV (and:SI (match_dup 4) (const_int 1)) + (const_int 0)))] + "") (define_insn "*negscc" [(set (match_operand:SI 0 "s_register_operand" "=r") @@ -7241,7 +8700,7 @@ return \"bics\\t%0, %2, %3, asr #32\;movcs\\t%0, %1\"; } /* The only case that falls through to here is when both ops 1 & 2 - are constants */ + are constants. */ } if (GET_CODE (operands[5]) == GE @@ -7260,7 +8719,7 @@ return \"ands\\t%0, %2, %3, asr #32\;movcc\\t%0, %1\"; } /* The only case that falls through to here is when both ops 1 & 2 - are constants */ + are constants. */ } if (GET_CODE (operands[4]) == CONST_INT && !const_ok_for_arm (INTVAL (operands[4]))) @@ -7397,7 +8856,7 @@ "* /* If we have an operation where (op x 0) is the identity operation and the conditional operator is LT or GE and we are comparing against zero and - everything is in registers then we can do this in two instructions */ + everything is in registers then we can do this in two instructions. */ if (operands[3] == const0_rtx && GET_CODE (operands[7]) != AND && GET_CODE (operands[5]) == REG @@ -7598,7 +9057,10 @@ mvn%D5\\t%0, #%B1\;mov%d5\\t%0, %2%S4" [(set_attr "conds" "use") (set_attr "shift" "2") - (set_attr "length" "4,8,8")] + (set_attr "length" "4,8,8") + (set (attr "type") (if_then_else (match_operand 3 "const_int_operand" "") + (const_string "alu_shift") + (const_string "alu_shift_reg")))] ) (define_insn "*ifcompare_move_shift" @@ -7634,7 +9096,10 @@ mvn%d5\\t%0, #%B1\;mov%D5\\t%0, %2%S4" [(set_attr "conds" "use") (set_attr "shift" "2") - (set_attr "length" "4,8,8")] + (set_attr "length" "4,8,8") + (set (attr "type") (if_then_else (match_operand 3 "const_int_operand" "") + (const_string "alu_shift") + (const_string "alu_shift_reg")))] ) (define_insn "*ifcompare_shift_shift" @@ -7671,7 +9136,12 @@ "mov%d5\\t%0, %1%S6\;mov%D5\\t%0, %3%S7" [(set_attr "conds" "use") (set_attr "shift" "1") - (set_attr "length" "8")] + (set_attr "length" "8") + (set (attr "type") (if_then_else + (and (match_operand 2 "const_int_operand" "") + (match_operand 4 "const_int_operand" "")) + (const_string "alu_shift") + (const_string "alu_shift_reg")))] ) (define_insn "*ifcompare_not_arith" @@ -7811,7 +9281,8 @@ { rtx ldm[3]; rtx arith[4]; - int val1 = 0, val2 = 0; + rtx base_reg; + HOST_WIDE_INT val1 = 0, val2 = 0; if (REGNO (operands[0]) > REGNO (operands[4])) { @@ -7823,12 +9294,21 @@ ldm[1] = operands[0]; ldm[2] = operands[4]; } - if (GET_CODE (XEXP (operands[2], 0)) != REG) - val1 = INTVAL (XEXP (XEXP (operands[2], 0), 1)); - if (GET_CODE (XEXP (operands[3], 0)) != REG) + + base_reg = XEXP (operands[2], 0); + + if (!REG_P (base_reg)) + { + val1 = INTVAL (XEXP (base_reg, 1)); + base_reg = XEXP (base_reg, 0); + } + + if (!REG_P (XEXP (operands[3], 0))) val2 = INTVAL (XEXP (XEXP (operands[3], 0), 1)); + arith[0] = operands[0]; arith[3] = operands[1]; + if (val1 < val2) { arith[1] = ldm[1]; @@ -7839,21 +9319,30 @@ arith[1] = ldm[2]; arith[2] = ldm[1]; } - if (val1 && val2) + + ldm[0] = base_reg; + if (val1 !=0 && val2 != 0) { - rtx ops[3]; - ldm[0] = ops[0] = operands[4]; - ops[1] = XEXP (XEXP (operands[2], 0), 0); - ops[2] = XEXP (XEXP (operands[2], 0), 1); - output_add_immediate (ops); - if (val1 < val2) - output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm); + if (val1 == 4 || val2 == 4) + /* Other val must be 8, since we know they are adjacent and neither + is zero. */ + output_asm_insn (\"ldm%?ib\\t%0, {%1, %2}\", ldm); else - output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm); + { + rtx ops[3]; + + ldm[0] = ops[0] = operands[4]; + ops[1] = base_reg; + ops[2] = GEN_INT (val1); + output_add_immediate (ops); + if (val1 < val2) + output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm); + else + output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm); + } } - else if (val1) + else if (val1 != 0) { - ldm[0] = XEXP (operands[3], 0); if (val1 < val2) output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm); else @@ -7861,7 +9350,6 @@ } else { - ldm[0] = XEXP (operands[2], 0); if (val1 < val2) output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm); else @@ -7872,516 +9360,17 @@ }" [(set_attr "length" "12") (set_attr "predicable" "yes") - (set_attr "type" "load")] -) - -;; the arm can support extended pre-inc instructions - -;; In all these cases, we use operands 0 and 1 for the register being -;; incremented because those are the operands that local-alloc will -;; tie and these are the pair most likely to be tieable (and the ones -;; that will benefit the most). - -;; We reject the frame pointer if it occurs anywhere in these patterns since -;; elimination will cause too many headaches. - -(define_insn "*strqi_preinc" - [(set (mem:QI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") - (match_operand:SI 2 "index_operand" "rJ"))) - (match_operand:QI 3 "s_register_operand" "r")) - (set (match_operand:SI 0 "s_register_operand" "=r") - (plus:SI (match_dup 1) (match_dup 2)))] - "TARGET_ARM - && REGNO (operands[0]) != FRAME_POINTER_REGNUM - && REGNO (operands[1]) != FRAME_POINTER_REGNUM - && (GET_CODE (operands[2]) != REG - || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" - "str%?b\\t%3, [%0, %2]!" - [(set_attr "type" "store1") - (set_attr "predicable" "yes")] -) - -(define_insn "*strqi_predec" - [(set (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0") - (match_operand:SI 2 "s_register_operand" "r"))) - (match_operand:QI 3 "s_register_operand" "r")) - (set (match_operand:SI 0 "s_register_operand" "=r") - (minus:SI (match_dup 1) (match_dup 2)))] - "TARGET_ARM - && REGNO (operands[0]) != FRAME_POINTER_REGNUM - && REGNO (operands[1]) != FRAME_POINTER_REGNUM - && (GET_CODE (operands[2]) != REG - || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" - "str%?b\\t%3, [%0, -%2]!" - [(set_attr "type" "store1") - (set_attr "predicable" "yes")] -) - -(define_insn "*loadqi_preinc" - [(set (match_operand:QI 3 "s_register_operand" "=r") - (mem:QI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") - (match_operand:SI 2 "index_operand" "rJ")))) - (set (match_operand:SI 0 "s_register_operand" "=r") - (plus:SI (match_dup 1) (match_dup 2)))] - "TARGET_ARM - && REGNO (operands[0]) != FRAME_POINTER_REGNUM - && REGNO (operands[1]) != FRAME_POINTER_REGNUM - && (GET_CODE (operands[2]) != REG - || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" - "ldr%?b\\t%3, [%0, %2]!" - [(set_attr "type" "load") - (set_attr "predicable" "yes")] -) - -(define_insn "*loadqi_predec" - [(set (match_operand:QI 3 "s_register_operand" "=r") - (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0") - (match_operand:SI 2 "s_register_operand" "r")))) - (set (match_operand:SI 0 "s_register_operand" "=r") - (minus:SI (match_dup 1) (match_dup 2)))] - "TARGET_ARM - && REGNO (operands[0]) != FRAME_POINTER_REGNUM - && REGNO (operands[1]) != FRAME_POINTER_REGNUM - && (GET_CODE (operands[2]) != REG - || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" - "ldr%?b\\t%3, [%0, -%2]!" - [(set_attr "type" "load") - (set_attr "predicable" "yes")] -) - -(define_insn "*loadqisi_preinc" - [(set (match_operand:SI 3 "s_register_operand" "=r") - (zero_extend:SI - (mem:QI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") - (match_operand:SI 2 "index_operand" "rJ"))))) - (set (match_operand:SI 0 "s_register_operand" "=r") - (plus:SI (match_dup 1) (match_dup 2)))] - "TARGET_ARM - && REGNO (operands[0]) != FRAME_POINTER_REGNUM - && REGNO (operands[1]) != FRAME_POINTER_REGNUM - && (GET_CODE (operands[2]) != REG - || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" - "ldr%?b\\t%3, [%0, %2]!\\t%@ z_extendqisi" - [(set_attr "type" "load") - (set_attr "predicable" "yes")] -) - -(define_insn "*loadqisi_predec" - [(set (match_operand:SI 3 "s_register_operand" "=r") - (zero_extend:SI - (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0") - (match_operand:SI 2 "s_register_operand" "r"))))) - (set (match_operand:SI 0 "s_register_operand" "=r") - (minus:SI (match_dup 1) (match_dup 2)))] - "TARGET_ARM - && REGNO (operands[0]) != FRAME_POINTER_REGNUM - && REGNO (operands[1]) != FRAME_POINTER_REGNUM - && (GET_CODE (operands[2]) != REG - || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" - "ldr%?b\\t%3, [%0, -%2]!\\t%@ z_extendqisi" - [(set_attr "type" "load") - (set_attr "predicable" "yes")] -) - -(define_insn "*strsi_preinc" - [(set (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") - (match_operand:SI 2 "index_operand" "rJ"))) - (match_operand:SI 3 "s_register_operand" "r")) - (set (match_operand:SI 0 "s_register_operand" "=r") - (plus:SI (match_dup 1) (match_dup 2)))] - "TARGET_ARM - && REGNO (operands[0]) != FRAME_POINTER_REGNUM - && REGNO (operands[1]) != FRAME_POINTER_REGNUM - && (GET_CODE (operands[2]) != REG - || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" - "str%?\\t%3, [%0, %2]!" - [(set_attr "type" "store1") - (set_attr "predicable" "yes")] -) - -(define_insn "*strsi_predec" - [(set (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0") - (match_operand:SI 2 "s_register_operand" "r"))) - (match_operand:SI 3 "s_register_operand" "r")) - (set (match_operand:SI 0 "s_register_operand" "=r") - (minus:SI (match_dup 1) (match_dup 2)))] - "TARGET_ARM - && REGNO (operands[0]) != FRAME_POINTER_REGNUM - && REGNO (operands[1]) != FRAME_POINTER_REGNUM - && (GET_CODE (operands[2]) != REG - || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" - "str%?\\t%3, [%0, -%2]!" - [(set_attr "type" "store1") - (set_attr "predicable" "yes")] -) - -(define_insn "*loadsi_preinc" - [(set (match_operand:SI 3 "s_register_operand" "=r") - (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") - (match_operand:SI 2 "index_operand" "rJ")))) - (set (match_operand:SI 0 "s_register_operand" "=r") - (plus:SI (match_dup 1) (match_dup 2)))] - "TARGET_ARM - && REGNO (operands[0]) != FRAME_POINTER_REGNUM - && REGNO (operands[1]) != FRAME_POINTER_REGNUM - && (GET_CODE (operands[2]) != REG - || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" - "ldr%?\\t%3, [%0, %2]!" - [(set_attr "type" "load") - (set_attr "predicable" "yes")] -) - -(define_insn "*loadsi_predec" - [(set (match_operand:SI 3 "s_register_operand" "=r") - (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0") - (match_operand:SI 2 "s_register_operand" "r")))) - (set (match_operand:SI 0 "s_register_operand" "=r") - (minus:SI (match_dup 1) (match_dup 2)))] - "TARGET_ARM - && REGNO (operands[0]) != FRAME_POINTER_REGNUM - && REGNO (operands[1]) != FRAME_POINTER_REGNUM - && (GET_CODE (operands[2]) != REG - || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" - "ldr%?\\t%3, [%0, -%2]!" - [(set_attr "type" "load") - (set_attr "predicable" "yes")] -) - -(define_insn "*loadhi_preinc" - [(set (match_operand:HI 3 "s_register_operand" "=r") - (mem:HI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") - (match_operand:SI 2 "index_operand" "rJ")))) - (set (match_operand:SI 0 "s_register_operand" "=r") - (plus:SI (match_dup 1) (match_dup 2)))] - "TARGET_ARM - && !BYTES_BIG_ENDIAN - && !TARGET_MMU_TRAPS - && !arm_arch4 - && REGNO (operands[0]) != FRAME_POINTER_REGNUM - && REGNO (operands[1]) != FRAME_POINTER_REGNUM - && (GET_CODE (operands[2]) != REG - || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" - "ldr%?\\t%3, [%0, %2]!\\t%@ loadhi" - [(set_attr "type" "load") - (set_attr "predicable" "yes")] -) - -(define_insn "*loadhi_predec" - [(set (match_operand:HI 3 "s_register_operand" "=r") - (mem:HI (minus:SI (match_operand:SI 1 "s_register_operand" "0") - (match_operand:SI 2 "s_register_operand" "r")))) - (set (match_operand:SI 0 "s_register_operand" "=r") - (minus:SI (match_dup 1) (match_dup 2)))] - "TARGET_ARM - && !BYTES_BIG_ENDIAN - && !TARGET_MMU_TRAPS - && !arm_arch4 - && REGNO (operands[0]) != FRAME_POINTER_REGNUM - && REGNO (operands[1]) != FRAME_POINTER_REGNUM - && (GET_CODE (operands[2]) != REG - || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" - "ldr%?\\t%3, [%0, -%2]!\\t%@ loadhi" - [(set_attr "type" "load") - (set_attr "predicable" "yes")] -) - -(define_insn "*strqi_shiftpreinc" - [(set (mem:QI (plus:SI (match_operator:SI 2 "shift_operator" - [(match_operand:SI 3 "s_register_operand" "r") - (match_operand:SI 4 "const_shift_operand" "n")]) - (match_operand:SI 1 "s_register_operand" "0"))) - (match_operand:QI 5 "s_register_operand" "r")) - (set (match_operand:SI 0 "s_register_operand" "=r") - (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) - (match_dup 1)))] - "TARGET_ARM - && REGNO (operands[0]) != FRAME_POINTER_REGNUM - && REGNO (operands[1]) != FRAME_POINTER_REGNUM - && REGNO (operands[3]) != FRAME_POINTER_REGNUM" - "str%?b\\t%5, [%0, %3%S2]!" - [(set_attr "type" "store1") - (set_attr "predicable" "yes")] -) - -(define_insn "*strqi_shiftpredec" - [(set (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0") - (match_operator:SI 2 "shift_operator" - [(match_operand:SI 3 "s_register_operand" "r") - (match_operand:SI 4 "const_shift_operand" "n")]))) - (match_operand:QI 5 "s_register_operand" "r")) - (set (match_operand:SI 0 "s_register_operand" "=r") - (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) - (match_dup 4)])))] - "TARGET_ARM - && REGNO (operands[0]) != FRAME_POINTER_REGNUM - && REGNO (operands[1]) != FRAME_POINTER_REGNUM - && REGNO (operands[3]) != FRAME_POINTER_REGNUM" - "str%?b\\t%5, [%0, -%3%S2]!" - [(set_attr "type" "store1") - (set_attr "predicable" "yes")] -) - -(define_insn "*loadqi_shiftpreinc" - [(set (match_operand:QI 5 "s_register_operand" "=r") - (mem:QI (plus:SI (match_operator:SI 2 "shift_operator" - [(match_operand:SI 3 "s_register_operand" "r") - (match_operand:SI 4 "const_shift_operand" "n")]) - (match_operand:SI 1 "s_register_operand" "0")))) - (set (match_operand:SI 0 "s_register_operand" "=r") - (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) - (match_dup 1)))] - "TARGET_ARM - && REGNO (operands[0]) != FRAME_POINTER_REGNUM - && REGNO (operands[1]) != FRAME_POINTER_REGNUM - && REGNO (operands[3]) != FRAME_POINTER_REGNUM" - "ldr%?b\\t%5, [%0, %3%S2]!" - [(set_attr "type" "load") - (set_attr "predicable" "yes")] -) - -(define_insn "*loadqi_shiftpredec" - [(set (match_operand:QI 5 "s_register_operand" "=r") - (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0") - (match_operator:SI 2 "shift_operator" - [(match_operand:SI 3 "s_register_operand" "r") - (match_operand:SI 4 "const_shift_operand" "n")])))) - (set (match_operand:SI 0 "s_register_operand" "=r") - (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) - (match_dup 4)])))] - "TARGET_ARM - && REGNO (operands[0]) != FRAME_POINTER_REGNUM - && REGNO (operands[1]) != FRAME_POINTER_REGNUM - && REGNO (operands[3]) != FRAME_POINTER_REGNUM" - "ldr%?b\\t%5, [%0, -%3%S2]!" - [(set_attr "type" "load") - (set_attr "predicable" "yes")] -) - -(define_insn "*strsi_shiftpreinc" - [(set (mem:SI (plus:SI (match_operator:SI 2 "shift_operator" - [(match_operand:SI 3 "s_register_operand" "r") - (match_operand:SI 4 "const_shift_operand" "n")]) - (match_operand:SI 1 "s_register_operand" "0"))) - (match_operand:SI 5 "s_register_operand" "r")) - (set (match_operand:SI 0 "s_register_operand" "=r") - (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) - (match_dup 1)))] - "TARGET_ARM - && REGNO (operands[0]) != FRAME_POINTER_REGNUM - && REGNO (operands[1]) != FRAME_POINTER_REGNUM - && REGNO (operands[3]) != FRAME_POINTER_REGNUM" - "str%?\\t%5, [%0, %3%S2]!" - [(set_attr "type" "store1") - (set_attr "predicable" "yes")] -) - -(define_insn "*strsi_shiftpredec" - [(set (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0") - (match_operator:SI 2 "shift_operator" - [(match_operand:SI 3 "s_register_operand" "r") - (match_operand:SI 4 "const_shift_operand" "n")]))) - (match_operand:SI 5 "s_register_operand" "r")) - (set (match_operand:SI 0 "s_register_operand" "=r") - (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) - (match_dup 4)])))] - "TARGET_ARM - && REGNO (operands[0]) != FRAME_POINTER_REGNUM - && REGNO (operands[1]) != FRAME_POINTER_REGNUM - && REGNO (operands[3]) != FRAME_POINTER_REGNUM" - "str%?\\t%5, [%0, -%3%S2]!" - [(set_attr "type" "store1") - (set_attr "predicable" "yes")] -) - -(define_insn "*loadsi_shiftpreinc" - [(set (match_operand:SI 5 "s_register_operand" "=r") - (mem:SI (plus:SI (match_operator:SI 2 "shift_operator" - [(match_operand:SI 3 "s_register_operand" "r") - (match_operand:SI 4 "const_shift_operand" "n")]) - (match_operand:SI 1 "s_register_operand" "0")))) - (set (match_operand:SI 0 "s_register_operand" "=r") - (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) - (match_dup 1)))] - "TARGET_ARM - && REGNO (operands[0]) != FRAME_POINTER_REGNUM - && REGNO (operands[1]) != FRAME_POINTER_REGNUM - && REGNO (operands[3]) != FRAME_POINTER_REGNUM" - "ldr%?\\t%5, [%0, %3%S2]!" - [(set_attr "type" "load") - (set_attr "predicable" "yes")] -) - -(define_insn "*loadsi_shiftpredec" - [(set (match_operand:SI 5 "s_register_operand" "=r") - (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0") - (match_operator:SI 2 "shift_operator" - [(match_operand:SI 3 "s_register_operand" "r") - (match_operand:SI 4 "const_shift_operand" "n")])))) - (set (match_operand:SI 0 "s_register_operand" "=r") - (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) - (match_dup 4)])))] - "TARGET_ARM - && REGNO (operands[0]) != FRAME_POINTER_REGNUM - && REGNO (operands[1]) != FRAME_POINTER_REGNUM - && REGNO (operands[3]) != FRAME_POINTER_REGNUM" - "ldr%?\\t%5, [%0, -%3%S2]!" - [(set_attr "type" "load") - (set_attr "predicable" "yes")]) - -(define_insn "*loadhi_shiftpreinc" - [(set (match_operand:HI 5 "s_register_operand" "=r") - (mem:HI (plus:SI (match_operator:SI 2 "shift_operator" - [(match_operand:SI 3 "s_register_operand" "r") - (match_operand:SI 4 "const_shift_operand" "n")]) - (match_operand:SI 1 "s_register_operand" "0")))) - (set (match_operand:SI 0 "s_register_operand" "=r") - (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) - (match_dup 1)))] - "TARGET_ARM - && !BYTES_BIG_ENDIAN - && !TARGET_MMU_TRAPS - && !arm_arch4 - && REGNO (operands[0]) != FRAME_POINTER_REGNUM - && REGNO (operands[1]) != FRAME_POINTER_REGNUM - && REGNO (operands[3]) != FRAME_POINTER_REGNUM" - "ldr%?\\t%5, [%0, %3%S2]!\\t%@ loadhi" - [(set_attr "type" "load") - (set_attr "predicable" "yes")] -) - -(define_insn "*loadhi_shiftpredec" - [(set (match_operand:HI 5 "s_register_operand" "=r") - (mem:HI (minus:SI (match_operand:SI 1 "s_register_operand" "0") - (match_operator:SI 2 "shift_operator" - [(match_operand:SI 3 "s_register_operand" "r") - (match_operand:SI 4 "const_shift_operand" "n")])))) - (set (match_operand:SI 0 "s_register_operand" "=r") - (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) - (match_dup 4)])))] - "TARGET_ARM - && !BYTES_BIG_ENDIAN - && !TARGET_MMU_TRAPS - && !arm_arch4 - && REGNO (operands[0]) != FRAME_POINTER_REGNUM - && REGNO (operands[1]) != FRAME_POINTER_REGNUM - && REGNO (operands[3]) != FRAME_POINTER_REGNUM" - "ldr%?\\t%5, [%0, -%3%S2]!\\t%@ loadhi" - [(set_attr "type" "load") - (set_attr "predicable" "yes")] -) - -; It can also support extended post-inc expressions, but combine doesn't -; try these.... -; It doesn't seem worth adding peepholes for anything but the most common -; cases since, unlike combine, the increment must immediately follow the load -; for this pattern to match. -; We must watch to see that the source/destination register isn't also the -; same as the base address register, and that if the index is a register, -; that it is not the same as the base address register. In such cases the -; instruction that we would generate would have UNPREDICTABLE behavior so -; we cannot use it. - -(define_peephole - [(set (mem:QI (match_operand:SI 0 "s_register_operand" "+r")) - (match_operand:QI 2 "s_register_operand" "r")) - (set (match_dup 0) - (plus:SI (match_dup 0) (match_operand:SI 1 "index_operand" "rJ")))] - "TARGET_ARM - && (REGNO (operands[2]) != REGNO (operands[0])) - && (GET_CODE (operands[1]) != REG - || (REGNO (operands[1]) != REGNO (operands[0])))" - "str%?b\\t%2, [%0], %1" -) - -(define_peephole - [(set (match_operand:QI 0 "s_register_operand" "=r") - (mem:QI (match_operand:SI 1 "s_register_operand" "+r"))) - (set (match_dup 1) - (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))] - "TARGET_ARM - && REGNO (operands[0]) != REGNO(operands[1]) - && (GET_CODE (operands[2]) != REG - || REGNO(operands[0]) != REGNO (operands[2]))" - "ldr%?b\\t%0, [%1], %2" -) - -(define_peephole - [(set (mem:SI (match_operand:SI 0 "s_register_operand" "+r")) - (match_operand:SI 2 "s_register_operand" "r")) - (set (match_dup 0) - (plus:SI (match_dup 0) (match_operand:SI 1 "index_operand" "rJ")))] - "TARGET_ARM - && (REGNO (operands[2]) != REGNO (operands[0])) - && (GET_CODE (operands[1]) != REG - || (REGNO (operands[1]) != REGNO (operands[0])))" - "str%?\\t%2, [%0], %1" -) - -(define_peephole - [(set (match_operand:HI 0 "s_register_operand" "=r") - (mem:HI (match_operand:SI 1 "s_register_operand" "+r"))) - (set (match_dup 1) - (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))] - "TARGET_ARM - && !BYTES_BIG_ENDIAN - && !TARGET_MMU_TRAPS - && !arm_arch4 - && REGNO (operands[0]) != REGNO(operands[1]) - && (GET_CODE (operands[2]) != REG - || REGNO(operands[0]) != REGNO (operands[2]))" - "ldr%?\\t%0, [%1], %2\\t%@ loadhi" -) - -(define_peephole - [(set (match_operand:SI 0 "s_register_operand" "=r") - (mem:SI (match_operand:SI 1 "s_register_operand" "+r"))) - (set (match_dup 1) - (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))] - "TARGET_ARM - && REGNO (operands[0]) != REGNO(operands[1]) - && (GET_CODE (operands[2]) != REG - || REGNO(operands[0]) != REGNO (operands[2]))" - "ldr%?\\t%0, [%1], %2" -) - -(define_peephole - [(set (mem:QI (plus:SI (match_operand:SI 0 "s_register_operand" "+r") - (match_operand:SI 1 "index_operand" "rJ"))) - (match_operand:QI 2 "s_register_operand" "r")) - (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))] - "TARGET_ARM - && (REGNO (operands[2]) != REGNO (operands[0])) - && (GET_CODE (operands[1]) != REG - || (REGNO (operands[1]) != REGNO (operands[0])))" - "str%?b\\t%2, [%0, %1]!" -) - -(define_peephole - [(set (mem:QI (plus:SI (match_operator:SI 4 "shift_operator" - [(match_operand:SI 0 "s_register_operand" "r") - (match_operand:SI 1 "const_int_operand" "n")]) - (match_operand:SI 2 "s_register_operand" "+r"))) - (match_operand:QI 3 "s_register_operand" "r")) - (set (match_dup 2) (plus:SI (match_op_dup 4 [(match_dup 0) (match_dup 1)]) - (match_dup 2)))] - "TARGET_ARM - && (REGNO (operands[3]) != REGNO (operands[2])) - && (REGNO (operands[0]) != REGNO (operands[2]))" - "str%?b\\t%3, [%2, %0%S4]!" + (set_attr "type" "load1")] ) ; This pattern is never tried by combine, so do it as a peephole (define_peephole2 - [(set (match_operand:SI 0 "s_register_operand" "") - (match_operand:SI 1 "s_register_operand" "")) + [(set (match_operand:SI 0 "arm_general_register_operand" "") + (match_operand:SI 1 "arm_general_register_operand" "")) (set (reg:CC CC_REGNUM) (compare:CC (match_dup 1) (const_int 0)))] - "TARGET_ARM - && (!TARGET_CIRRUS - || (!cirrus_fp_register (operands[0], SImode) - && !cirrus_fp_register (operands[1], SImode))) - " + "TARGET_ARM" [(parallel [(set (reg:CC CC_REGNUM) (compare:CC (match_dup 1) (const_int 0))) (set (match_dup 0) (match_dup 1))])] "" @@ -8516,9 +9505,11 @@ ) (define_expand "epilogue" - [(unspec_volatile [(return)] VUNSPEC_EPILOGUE)] + [(clobber (const_int 0))] "TARGET_EITHER" " + if (current_function_calls_eh_return) + emit_insn (gen_prologue_use (gen_rtx_REG (Pmode, 2))); if (TARGET_THUMB) thumb_expand_epilogue (); else if (USE_RETURN_INSN (FALSE)) @@ -8544,9 +9535,9 @@ (unspec_volatile [(return)] VUNSPEC_EPILOGUE)])] "TARGET_ARM" "* - if (USE_RETURN_INSN (FALSE)) + if (use_return_insn (FALSE, next_nonnote_insn (insn))) return output_return_instruction (const_true_rtx, FALSE, FALSE); - return arm_output_epilogue (FALSE); + return arm_output_epilogue (next_nonnote_insn (insn)); " ;; Length is absolute worst case [(set_attr "length" "44") @@ -8562,7 +9553,7 @@ "TARGET_EITHER" "* if (TARGET_ARM) - return arm_output_epilogue (TRUE); + return arm_output_epilogue (NULL); else /* TARGET_THUMB */ return thumb_unexpanded_epilogue (); " @@ -8576,9 +9567,9 @@ ) (define_expand "eh_epilogue" - [(use (match_operand:SI 0 "register_operand" "r")) - (use (match_operand:SI 1 "register_operand" "r")) - (use (match_operand:SI 2 "register_operand" "r"))] + [(use (match_operand:SI 0 "register_operand" "")) + (use (match_operand:SI 1 "register_operand" "")) + (use (match_operand:SI 2 "register_operand" ""))] "TARGET_EITHER" " { @@ -8704,7 +9695,7 @@ enum rtx_code rc = GET_CODE (operands[1]); operands[6] = gen_rtx_REG (mode, CC_REGNUM); - operands[7] = gen_rtx (COMPARE, mode, operands[2], operands[3]); + operands[7] = gen_rtx_COMPARE (mode, operands[2], operands[3]); if (mode == CCFPmode || mode == CCFPEmode) rc = reverse_condition_maybe_unordered (rc); else @@ -8822,7 +9813,7 @@ [(set (match_operand:BLK 0 "memory_operand" "=m") (unspec:BLK [(match_operand:XF 1 "f_register_operand" "f")] UNSPEC_PUSH_MULT))])] - "TARGET_ARM" + "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA" "* { char pattern[100]; @@ -8845,6 +9836,15 @@ " ) +(define_insn "align_8" + [(unspec_volatile [(const_int 0)] VUNSPEC_ALIGN8)] + "TARGET_EITHER" + "* + assemble_align (64); + return \"\"; + " +) + (define_insn "consttable_end" [(unspec_volatile [(const_int 0)] VUNSPEC_POOL_END)] "TARGET_EITHER" @@ -8929,7 +9929,7 @@ ;; Miscellaneous Thumb patterns (define_expand "tablejump" - [(parallel [(set (pc) (match_operand:SI 0 "register_operand" "l*r")) + [(parallel [(set (pc) (match_operand:SI 0 "register_operand" "")) (use (label_ref (match_operand 1 "" "")))])] "TARGET_THUMB" " @@ -8945,6 +9945,7 @@ " ) +;; NB never uses BX. (define_insn "*thumb_tablejump" [(set (pc) (match_operand:SI 0 "register_operand" "l*r")) (use (label_ref (match_operand 1 "" "")))] @@ -8959,7 +9960,8 @@ [(set (match_operand:SI 0 "s_register_operand" "=r") (clz:SI (match_operand:SI 1 "s_register_operand" "r")))] "TARGET_ARM && arm_arch5" - "clz\\t%0, %1") + "clz%?\\t%0, %1" + [(set_attr "predicable" "yes")]) (define_expand "ffssi2" [(set (match_operand:SI 0 "s_register_operand" "") @@ -9025,3 +10027,60 @@ "" "%@ %0 needed for prologue" ) + + +;; Patterns for exception handling + +(define_expand "eh_return" + [(use (match_operand 0 "general_operand" ""))] + "TARGET_EITHER" + " + { + if (TARGET_ARM) + emit_insn (gen_arm_eh_return (operands[0])); + else + emit_insn (gen_thumb_eh_return (operands[0])); + DONE; + }" +) + +;; We can't expand this before we know where the link register is stored. +(define_insn_and_split "arm_eh_return" + [(unspec_volatile [(match_operand:SI 0 "s_register_operand" "r")] + VUNSPEC_EH_RETURN) + (clobber (match_scratch:SI 1 "=&r"))] + "TARGET_ARM" + "#" + "&& reload_completed" + [(const_int 0)] + " + { + arm_set_return_address (operands[0], operands[1]); + DONE; + }" +) + +(define_insn_and_split "thumb_eh_return" + [(unspec_volatile [(match_operand:SI 0 "s_register_operand" "l")] + VUNSPEC_EH_RETURN) + (clobber (match_scratch:SI 1 "=&l"))] + "TARGET_THUMB" + "#" + "&& reload_completed" + [(const_int 0)] + " + { + thumb_set_return_address (operands[0], operands[1]); + DONE; + }" +) + +;; Load the FPA co-processor patterns +(include "fpa.md") +;; Load the Maverick co-processor patterns +(include "cirrus.md") +;; Load the Intel Wireless Multimedia Extension patterns +(include "iwmmxt.md") +;; Load the VFP co-processor patterns +(include "vfp.md") +