X-Git-Url: https://oss.titaniummirror.com/gitweb?a=blobdiff_plain;f=gcc%2Fconfig%2Farm%2Farm.md;fp=gcc%2Fconfig%2Farm%2Farm.md;h=f2b7a7d1b8205d47ecf9ed3a96bf2a06230dd30b;hb=6fed43773c9b0ce596dca5686f37ac3fc0fa11c0;hp=5180c75933a2efd3cd2c9cac84b2dff646f38b06;hpb=27b11d56b743098deb193d510b337ba22dc52e5c;p=msp430-gcc.git diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 5180c759..f2b7a7d1 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -1,49 +1,57 @@ ;;- Machine description for ARM for GNU compiler ;; Copyright 1991, 1993, 1994, 1995, 1996, 1996, 1997, 1998, 1999, 2000, -;; 2001, 2002 Free Software Foundation, Inc. +;; 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +;; 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 3, 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 COPYING3. If not see +;; . ;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. -;; There are patterns in this file to support XFmode arithmetic. -;; Unfortunately RISC iX doesn't work well with these so they are disabled. -;; (See arm.h) ;;--------------------------------------------------------------------------- ;; Constants ;; 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) ] ) ;; UNSPEC Usage: ;; Note: sin and cos are no-longer used. +;; Unspec constants for Neon are defined in neon.md. (define_constants [(UNSPEC_SIN 0) ; `sin' operation (MODE_FLOAT): @@ -59,16 +67,38 @@ (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) ; Add PC and all but the last operand together, + ; The last operand is the number of a PIC_LABEL + ; that points at the containing instruction. + (UNSPEC_PRLG_STK 5) ; A special barrier that prevents frame accesses ; being scheduled before the stack adjustment insn. - (UNSPEC_CLZ 5) ; `clz' instruction, count leading zeros (SImode): - ; operand 0 is the result, - ; operand 1 is the parameter. (UNSPEC_PROLOGUE_USE 6) ; As USE insns are not meaningful after reload, ; this unspec is used to prevent the deletion of ; instructions setting registers for EH handling ; 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. + (UNSPEC_TLS 20) ; A symbol that has been treated properly for TLS usage. + (UNSPEC_PIC_LABEL 21) ; A label used for PIC access that does not appear in the + ; instruction stream. + (UNSPEC_STACK_ALIGN 22) ; Doubleword aligned stack pointer. Used to + ; generate correct unwind information. + (UNSPEC_PIC_OFFSET 23) ; A symbolic 12-bit OFFSET that has been treated + ; correctly for PIC usage. + (UNSPEC_GOTSYM_OFF 24) ; The offset of the start of the the GOT from a + ; a given symbolic address. ] ) @@ -93,6 +123,16 @@ ; a 32-bit object. (VUNSPEC_POOL_8 7) ; `pool-entry(8)'. An entry in the constant pool for ; a 64-bit object. + (VUNSPEC_POOL_16 8) ; `pool-entry(16)'. An entry in the constant pool for + ; a 128-bit object. + (VUNSPEC_TMRC 9) ; Used by the iWMMXt TMRC instruction. + (VUNSPEC_TMCR 10) ; Used by the iWMMXt TMCR instruction. + (VUNSPEC_ALIGN8 11) ; 8-byte alignment version of VUNSPEC_ALIGN + (VUNSPEC_WCMP_EQ 12) ; Used by the iWMMXt WCMPEQ instructions + (VUNSPEC_WCMP_GTU 13) ; Used by the iWMMXt WCMPGTU instructions + (VUNSPEC_WCMP_GT 14) ; Used by the iwMMXT WCMPGT instructions + (VUNSPEC_EH_RETURN 20); Use to override the return address for exception + ; handling. ] ) @@ -104,24 +144,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,vfpv3d16,vfpv3,neon" + (const (symbol_ref "arm_fpu_attr"))) ; LENGTH of an instruction (in bytes) (define_attr "length" "" (const_int 4)) @@ -142,17 +180,31 @@ (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" + "mov,mvn,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,smmla,umaal,smlald,smlsld,clz,mrs,msr,xtab,sdiv,udiv,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 +; Note: vfp.md has different meanings for some of these, and some further +; types as well. See that file for details. +; 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) -; fdivx XFmode floating point division ; fdivd DFmode floating point division ; fdivs SFmode floating point division ; fmul Floating point multiply @@ -163,25 +215,110 @@ ; 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,fmuls,fmuld,fmacs,fmacd,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,fconsts,fconstd,fadds,faddd,ffariths,ffarithd,fcmps,fcmpd,fcpys" + (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 -; initialised by arm_override_options() +; initialized by arm_override_options() (define_attr "ldsched" "no,yes" (const (symbol_ref "arm_ld_sched"))) +;; Classification of NEON instructions for scheduling purposes. +;; Do not set this attribute and the "type" attribute together in +;; any one instruction pattern. +(define_attr "neon_type" + "neon_int_1,\ + neon_int_2,\ + neon_int_3,\ + neon_int_4,\ + neon_int_5,\ + neon_vqneg_vqabs,\ + neon_vmov,\ + neon_vaba,\ + neon_vsma,\ + neon_vaba_qqq,\ + neon_mul_ddd_8_16_qdd_16_8_long_32_16_long,\ + neon_mul_qqq_8_16_32_ddd_32,\ + neon_mul_qdd_64_32_long_qqd_16_ddd_32_scalar_64_32_long_scalar,\ + neon_mla_ddd_8_16_qdd_16_8_long_32_16_long,\ + neon_mla_qqq_8_16,\ + neon_mla_ddd_32_qqd_16_ddd_32_scalar_qdd_64_32_long_scalar_qdd_64_32_long,\ + neon_mla_qqq_32_qqd_32_scalar,\ + neon_mul_ddd_16_scalar_32_16_long_scalar,\ + neon_mul_qqd_32_scalar,\ + neon_mla_ddd_16_scalar_qdd_32_16_long_scalar,\ + neon_shift_1,\ + neon_shift_2,\ + neon_shift_3,\ + neon_vshl_ddd,\ + neon_vqshl_vrshl_vqrshl_qqq,\ + neon_vsra_vrsra,\ + neon_fp_vadd_ddd_vabs_dd,\ + neon_fp_vadd_qqq_vabs_qq,\ + neon_fp_vsum,\ + neon_fp_vmul_ddd,\ + neon_fp_vmul_qqd,\ + neon_fp_vmla_ddd,\ + neon_fp_vmla_qqq,\ + neon_fp_vmla_ddd_scalar,\ + neon_fp_vmla_qqq_scalar,\ + neon_fp_vrecps_vrsqrts_ddd,\ + neon_fp_vrecps_vrsqrts_qqq,\ + neon_bp_simple,\ + neon_bp_2cycle,\ + neon_bp_3cycle,\ + neon_ldr,\ + neon_str,\ + neon_vld1_1_2_regs,\ + neon_vld1_3_4_regs,\ + neon_vld2_2_regs_vld1_vld2_all_lanes,\ + neon_vld2_4_regs,\ + neon_vld3_vld4,\ + neon_vst1_1_2_regs_vst2_2_regs,\ + neon_vst1_3_4_regs,\ + neon_vst2_4_regs_vst3_vst4,\ + neon_vst3_vst4,\ + neon_vld1_vld2_lane,\ + neon_vld3_vld4_lane,\ + neon_vst1_vst2_lane,\ + neon_vst3_vst4_lane,\ + neon_vld3_vld4_all_lanes,\ + neon_mcr,\ + neon_mcr_2_mcrr,\ + neon_mrc,\ + neon_mrrc,\ + neon_ldm_2,\ + neon_stm_2,\ + none" + (const_string "none")) + ; condition codes: this one is used by final_prescan_insn to speed up ; conditionalizing instructions. It saves having to scan the rtl to see if ; it uses or alters the condition codes. @@ -199,14 +336,17 @@ ; JUMP_CLOB is used when the condition cannot be represented by a single ; instruction (UNEQ and LTGT). These cannot be predicated. ; +; UNCONDITIONAL means the instions can not be conditionally executed. +; ; NOCOND means that the condition codes are neither altered nor affect the ; output of this insn -(define_attr "conds" "use,set,clob,jump_clob,nocond" +(define_attr "conds" "use,set,clob,jump_clob,unconditional,nocond" (if_then_else (eq_attr "type" "call") - (if_then_else (eq_attr "prog_mode" "prog32") - (const_string "clob") (const_string "nocond")) - (const_string "nocond"))) + (const_string "clob") + (if_then_else (eq_attr "neon_type" "none") + (const_string "nocond") + (const_string "unconditional")))) ; Predicable means that the insn can be conditionally executed based on ; an automatically added predicate (additional patterns are generated by @@ -216,15 +356,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"))) @@ -232,7 +372,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"))) @@ -240,157 +380,65 @@ ;; 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) - -(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") - (eq_attr "type" "fdivs")) 31 29) - -(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") - (eq_attr "type" "fmul")) 9 7) - -(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") - (eq_attr "type" "ffmul")) 6 4) -(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") - (eq_attr "type" "farith")) 4 2) +;; The number of machine instructions this pattern expands to. +;; Used for Thumb-2 conditional execution. +(define_attr "ce_count" "" (const_int 1)) -(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") - (eq_attr "type" "ffarith")) 2 2) +;;--------------------------------------------------------------------------- +;; Mode iterators -(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") - (eq_attr "type" "r_2_f")) 5 3) +; 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_iterator ANY64 [DI DF V8QI V4HI V2SI V2SF]) -(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") - (eq_attr "type" "f_2_r")) 1 2) +;;--------------------------------------------------------------------------- +;; Predicates -; 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). +(include "predicates.md") +(include "constraints.md") -(define_function_unit "fpa_mem" 1 0 (and (eq_attr "fpu" "fpa") - (eq_attr "type" "f_load")) 3 1) +;;--------------------------------------------------------------------------- +;; Pipeline descriptions + +;; Processor type. This is created automatically from arm-cores.def. +(include "arm-tune.md") + +(define_attr "tune_cortexr4" "yes,no" + (const (if_then_else + (eq_attr "tune" "cortexr4,cortexr4f") + (const_string "yes") + (const_string "no")))) + +;; True if the generic scheduling description should be used. + +(define_attr "generic_sched" "yes,no" + (const (if_then_else + (ior (eq_attr "tune" "arm926ejs,arm1020e,arm1026ejs,arm1136js,arm1136jfs,cortexa8,cortexa9") + (eq_attr "tune_cortexr4" "yes")) + (const_string "no") + (const_string "yes")))) + +(define_attr "generic_vfp" "yes,no" + (const (if_then_else + (and (eq_attr "fpu" "vfp") + (eq_attr "tune" "!arm1020e,arm1022e,cortexa8,cortexa9") + (eq_attr "tune_cortexr4" "no")) + (const_string "yes") + (const_string "no")))) + +(include "arm-generic.md") +(include "arm926ejs.md") +(include "arm1020e.md") +(include "arm1026ejs.md") +(include "arm1136jfs.md") +(include "cortex-a8.md") +(include "cortex-a9.md") +(include "cortex-r4.md") +(include "cortex-r4f.md") +(include "vfp11.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) ;;--------------------------------------------------------------------------- ;; Insn patterns @@ -400,6 +448,8 @@ ;; Note: For DImode insns, there is normally no reason why operands should ;; not be in the same register, what we don't want is for something being ;; written to partially overlap something that is an input. +;; Cirrus 64bit additions should not be split because we have a native +;; 64bit addition instructions. (define_expand "adddi3" [(parallel @@ -409,23 +459,33 @@ (clobber (reg:CC CC_REGNUM))])] "TARGET_EITHER" " - if (TARGET_THUMB) + if (TARGET_HARD_FLOAT && TARGET_MAVERICK) + { + if (!cirrus_fp_register (operands[0], DImode)) + operands[0] = force_reg (DImode, operands[0]); + if (!cirrus_fp_register (operands[1], DImode)) + operands[1] = force_reg (DImode, operands[1]); + emit_insn (gen_cirrus_adddi3 (operands[0], operands[1], operands[2])); + DONE; + } + + if (TARGET_THUMB1) { if (GET_CODE (operands[1]) != REG) - operands[1] = force_reg (SImode, operands[1]); + operands[1] = force_reg (DImode, operands[1]); if (GET_CODE (operands[2]) != REG) - operands[2] = force_reg (SImode, operands[2]); + operands[2] = force_reg (DImode, operands[2]); } " ) -(define_insn "*thumb_adddi3" +(define_insn "*thumb1_adddi3" [(set (match_operand:DI 0 "register_operand" "=l") (plus:DI (match_operand:DI 1 "register_operand" "%0") (match_operand:DI 2 "register_operand" "l"))) (clobber (reg:CC CC_REGNUM)) ] - "TARGET_THUMB" + "TARGET_THUMB1" "add\\t%Q0, %Q0, %Q2\;adc\\t%R0, %R0, %R2" [(set_attr "length" "4")] ) @@ -435,9 +495,9 @@ (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_32BIT && !(TARGET_HARD_FLOAT && TARGET_MAVERICK)" "#" - "TARGET_ARM && reload_completed" + "TARGET_32BIT && reload_completed" [(parallel [(set (reg:CC_C CC_REGNUM) (compare:CC_C (plus:SI (match_dup 1) (match_dup 2)) (match_dup 1))) @@ -463,9 +523,9 @@ (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_32BIT && !(TARGET_HARD_FLOAT && TARGET_MAVERICK)" "#" - "TARGET_ARM && reload_completed" + "TARGET_32BIT && reload_completed" [(parallel [(set (reg:CC_C CC_REGNUM) (compare:CC_C (plus:SI (match_dup 1) (match_dup 2)) (match_dup 1))) @@ -492,9 +552,9 @@ (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_32BIT && !(TARGET_HARD_FLOAT && TARGET_MAVERICK)" "#" - "TARGET_ARM && reload_completed" + "TARGET_32BIT && reload_completed" [(parallel [(set (reg:CC_C CC_REGNUM) (compare:CC_C (plus:SI (match_dup 1) (match_dup 2)) (match_dup 1))) @@ -519,24 +579,24 @@ (match_operand:SI 2 "reg_or_int_operand" "")))] "TARGET_EITHER" " - if (TARGET_ARM && GET_CODE (operands[2]) == CONST_INT) + if (TARGET_32BIT && 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 && can_create_pseudo_p ()); 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 && + "TARGET_32BIT && !(const_ok_for_arm (INTVAL (operands[2])) || const_ok_for_arm (-INTVAL (operands[2]))) && const_ok_for_arm (~INTVAL (operands[2]))" @@ -545,26 +605,33 @@ "" ) +;; The r/r/k alternative is required when reloading the address +;; (plus (reg rN) (reg sp)) into (reg rN). In this case reload will +;; put the duplicated register first, and not try the commutative version. (define_insn_and_split "*arm_addsi3" - [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") - (plus:SI (match_operand:SI 1 "s_register_operand" "%r,r,r") - (match_operand:SI 2 "reg_or_int_operand" "rI,L,?n")))] - "TARGET_ARM" + [(set (match_operand:SI 0 "s_register_operand" "=r, !k, r,r, !k,r") + (plus:SI (match_operand:SI 1 "s_register_operand" "%rk,!k, r,rk,!k,rk") + (match_operand:SI 2 "reg_or_int_operand" "rI, rI,!k,L, L,?n")))] + "TARGET_32BIT" "@ add%?\\t%0, %1, %2 + add%?\\t%0, %1, %2 + add%?\\t%0, %2, %1 + sub%?\\t%0, %1, #%n2 sub%?\\t%0, %1, #%n2 #" - "TARGET_ARM && + "TARGET_32BIT && GET_CODE (operands[2]) == CONST_INT && !(const_ok_for_arm (INTVAL (operands[2])) || const_ok_for_arm (-INTVAL (operands[2])))" [(clobber (const_int 0))] " - arm_split_constant (PLUS, SImode, INTVAL (operands[2]), operands[0], + arm_split_constant (PLUS, SImode, curr_insn, + INTVAL (operands[2]), operands[0], operands[1], 0); DONE; " - [(set_attr "length" "4,4,16") + [(set_attr "length" "4,4,4,4,4,16") (set_attr "predicable" "yes")] ) @@ -572,11 +639,11 @@ ;; register. Trying to reload it will always fail catastrophically, ;; so never allow those alternatives to match if reloading is needed. -(define_insn "*thumb_addsi3" - [(set (match_operand:SI 0 "register_operand" "=l,l,l,*r,*h,l,!k") +(define_insn "*thumb1_addsi3" + [(set (match_operand:SI 0 "register_operand" "=l,l,l,*rk,*hk,l,!k") (plus:SI (match_operand:SI 1 "register_operand" "%0,0,l,*0,*0,!k,!k") - (match_operand:SI 2 "nonmemory_operand" "I,J,lL,*h,*r,!M,!O")))] - "TARGET_THUMB" + (match_operand:SI 2 "nonmemory_operand" "I,J,lL,*hk,*rk,!M,!O")))] + "TARGET_THUMB1" "* static const char * const asms[] = { @@ -600,18 +667,18 @@ ;; Reloading and elimination of the frame pointer can ;; sometimes cause this optimization to be missed. (define_peephole2 - [(set (match_operand:SI 0 "register_operand" "=l") - (match_operand:SI 1 "const_int_operand" "M")) + [(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" "k")))] - "TARGET_THUMB - && REGNO (operands[2]) == STACK_POINTER_REGNUM + (plus:SI (match_dup 0) (reg:SI SP_REGNUM)))] + "TARGET_THUMB1 && (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)))] "" ) +;; ??? Make Thumb-2 variants which prefer low regs (define_insn "*addsi3_compare0" [(set (reg:CC_NOOV CC_REGNUM) (compare:CC_NOOV @@ -620,10 +687,10 @@ (const_int 0))) (set (match_operand:SI 0 "s_register_operand" "=r,r") (plus:SI (match_dup 1) (match_dup 2)))] - "TARGET_ARM" + "TARGET_32BIT" "@ - add%?s\\t%0, %1, %2 - sub%?s\\t%0, %1, #%n2" + add%.\\t%0, %1, %2 + sub%.\\t%0, %1, #%n2" [(set_attr "conds" "set")] ) @@ -633,40 +700,75 @@ (plus:SI (match_operand:SI 0 "s_register_operand" "r, r") (match_operand:SI 1 "arm_add_operand" "rI,L")) (const_int 0)))] - "TARGET_ARM" + "TARGET_32BIT" "@ cmn%?\\t%0, %1 cmp%?\\t%0, #%n1" [(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" +(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_32BIT" + "cmn%?\\t%1, %0" + [(set_attr "conds" "set")] +) + +;; 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 1 "s_register_operand" "r,r") - (neg:SI (match_operand:SI 2 "arm_add_operand" "rI,L")))) + (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_dup 2)))] - "TARGET_ARM" + (plus:SI (match_dup 1) + (match_operand:SI 3 "arm_addimm_operand" "L,I")))] + "TARGET_32BIT && INTVAL (operands[2]) == -INTVAL (operands[3])" "@ - add%?s\\t%0, %1, %2 - sub%?s\\t%0, %1, #%n2" + sub%.\\t%0, %1, %2 + add%.\\t%0, %1, #%n2" [(set_attr "conds" "set")] ) -(define_insn "*addsi3_compare0_scratch_for_combiner" - [(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" - "@ - cmn%?\\t%0, %1 - cmp%?\\t%0, #%n1" - [(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_32BIT && 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 @@ -681,10 +783,10 @@ (match_dup 1))) (set (match_operand:SI 0 "s_register_operand" "=r,r") (plus:SI (match_dup 1) (match_dup 2)))] - "TARGET_ARM" + "TARGET_32BIT" "@ - add%?s\\t%0, %1, %2 - sub%?s\\t%0, %1, #%n2" + add%.\\t%0, %1, %2 + sub%.\\t%0, %1, #%n2" [(set_attr "conds" "set")] ) @@ -696,10 +798,10 @@ (match_dup 2))) (set (match_operand:SI 0 "s_register_operand" "=r,r") (plus:SI (match_dup 1) (match_dup 2)))] - "TARGET_ARM" + "TARGET_32BIT" "@ - add%?s\\t%0, %1, %2 - sub%?s\\t%0, %1, #%n2" + add%.\\t%0, %1, %2 + sub%.\\t%0, %1, #%n2" [(set_attr "conds" "set")] ) @@ -709,7 +811,7 @@ (plus:SI (match_operand:SI 0 "s_register_operand" "r,r") (match_operand:SI 1 "arm_add_operand" "rI,L")) (match_dup 0)))] - "TARGET_ARM" + "TARGET_32BIT" "@ cmn%?\\t%0, %1 cmp%?\\t%0, #%n1" @@ -722,7 +824,7 @@ (plus:SI (match_operand:SI 0 "s_register_operand" "r,r") (match_operand:SI 1 "arm_add_operand" "rI,L")) (match_dup 1)))] - "TARGET_ARM" + "TARGET_32BIT" "@ cmn%?\\t%0, %1 cmp%?\\t%0, #%n1" @@ -734,22 +836,25 @@ (plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0)) (plus:SI (match_operand:SI 1 "s_register_operand" "r") (match_operand:SI 2 "arm_rhs_operand" "rI"))))] - "TARGET_ARM" + "TARGET_32BIT" "adc%?\\t%0, %1, %2" [(set_attr "conds" "use")] ) (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" ""))))] - "TARGET_ARM" + [(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_32BIT" "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" @@ -757,7 +862,7 @@ (plus:SI (plus:SI (match_operand:SI 1 "s_register_operand" "r") (match_operand:SI 2 "arm_rhs_operand" "rI")) (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))] - "TARGET_ARM" + "TARGET_32BIT" "adc%?\\t%0, %1, %2" [(set_attr "conds" "use")] ) @@ -767,7 +872,7 @@ (plus:SI (plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0)) (match_operand:SI 1 "s_register_operand" "r")) (match_operand:SI 2 "arm_rhs_operand" "rI")))] - "TARGET_ARM" + "TARGET_32BIT" "adc%?\\t%0, %1, %2" [(set_attr "conds" "use")] ) @@ -777,12 +882,21 @@ (plus:SI (plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0)) (match_operand:SI 2 "arm_rhs_operand" "rI")) (match_operand:SI 1 "s_register_operand" "r")))] - "TARGET_ARM" + "TARGET_32BIT" "adc%?\\t%0, %1, %2" [(set_attr "conds" "use")] ) -(define_insn "incscc" +(define_expand "incscc" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (plus:SI (match_operator:SI 2 "arm_comparison_operator" + [(match_operand:CC 3 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "s_register_operand" "0,?r")))] + "TARGET_32BIT" + "" +) + +(define_insn "*arm_incscc" [(set (match_operand:SI 0 "s_register_operand" "=r,r") (plus:SI (match_operator:SI 2 "arm_comparison_operator" [(match_operand:CC 3 "cc_register" "") (const_int 0)]) @@ -795,77 +909,41 @@ (set_attr "length" "4,8")] ) -(define_insn "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 "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")] -) - -(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"))))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "adf%?d\\t%0, %1, %2" - [(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_32BIT" + [(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_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"))))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "adf%?d\\t%0, %1, %2" - [(set_attr "type" "farith") - (set_attr "predicable" "yes")] -) +(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_32BIT && TARGET_HARD_FLOAT" + " + if (TARGET_MAVERICK + && !cirrus_fp_register (operands[2], SFmode)) + operands[2] = force_reg (SFmode, operands[2]); +") -(define_insn "addxf3" - [(set (match_operand:XF 0 "s_register_operand" "=f,f") - (plus:XF (match_operand:XF 1 "s_register_operand" "f,f") - (match_operand:XF 2 "fpu_add_operand" "fG,H")))] - "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" - "@ - adf%?e\\t%0, %1, %2 - suf%?e\\t%0, %1, #%N2" - [(set_attr "type" "farith") - (set_attr "predicable" "yes")] -) +(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_32BIT && TARGET_HARD_FLOAT" + " + if (TARGET_MAVERICK + && !cirrus_fp_register (operands[2], DFmode)) + operands[2] = force_reg (DFmode, operands[2]); +") (define_expand "subdi3" [(parallel @@ -875,7 +953,16 @@ (clobber (reg:CC CC_REGNUM))])] "TARGET_EITHER" " - if (TARGET_THUMB) + if (TARGET_HARD_FLOAT && TARGET_MAVERICK + && TARGET_32BIT + && cirrus_fp_register (operands[0], DImode) + && cirrus_fp_register (operands[1], DImode)) + { + emit_insn (gen_cirrus_subdi3 (operands[0], operands[1], operands[2])); + DONE; + } + + if (TARGET_THUMB1) { if (GET_CODE (operands[1]) != REG) operands[1] = force_reg (SImode, operands[1]); @@ -890,7 +977,7 @@ (minus:DI (match_operand:DI 1 "s_register_operand" "0,r,0") (match_operand:DI 2 "s_register_operand" "r,0,0"))) (clobber (reg:CC CC_REGNUM))] - "TARGET_ARM" + "TARGET_32BIT" "subs\\t%Q0, %Q1, %Q2\;sbc\\t%R0, %R1, %R2" [(set_attr "conds" "clob") (set_attr "length" "8")] @@ -901,7 +988,7 @@ (minus:DI (match_operand:DI 1 "register_operand" "0") (match_operand:DI 2 "register_operand" "l"))) (clobber (reg:CC CC_REGNUM))] - "TARGET_THUMB" + "TARGET_THUMB1" "sub\\t%Q0, %Q0, %Q2\;sbc\\t%R0, %R0, %R2" [(set_attr "length" "4")] ) @@ -912,7 +999,7 @@ (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")))) (clobber (reg:CC CC_REGNUM))] - "TARGET_ARM" + "TARGET_32BIT" "subs\\t%Q0, %Q1, %2\;sbc\\t%R0, %R1, #0" [(set_attr "conds" "clob") (set_attr "length" "8")] @@ -924,7 +1011,7 @@ (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")))) (clobber (reg:CC CC_REGNUM))] - "TARGET_ARM" + "TARGET_32BIT" "subs\\t%Q0, %Q1, %2\;sbc\\t%R0, %R1, %2, asr #31" [(set_attr "conds" "clob") (set_attr "length" "8")] @@ -961,8 +1048,8 @@ (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r")))) (clobber (reg:CC CC_REGNUM))] - "TARGET_ARM" - "subs\\t%Q0, %1, %2\;rsc\\t%R0, %1, %1" + "TARGET_32BIT" + "subs\\t%Q0, %1, %2\;sbc\\t%R0, %1, %1" [(set_attr "conds" "clob") (set_attr "length" "8")] ) @@ -975,56 +1062,57 @@ " if (GET_CODE (operands[1]) == CONST_INT) { - if (TARGET_ARM) + if (TARGET_32BIT) { - 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 && can_create_pseudo_p ()); DONE; } - else /* TARGET_THUMB */ + else /* TARGET_THUMB1 */ operands[1] = force_reg (SImode, operands[1]); } " ) -(define_insn "*thumb_subsi3_insn" +(define_insn "*thumb1_subsi3_insn" [(set (match_operand:SI 0 "register_operand" "=l") (minus:SI (match_operand:SI 1 "register_operand" "l") (match_operand:SI 2 "register_operand" "l")))] - "TARGET_THUMB" + "TARGET_THUMB1" "sub\\t%0, %1, %2" [(set_attr "length" "2")] ) +; ??? Check Thumb-2 split length (define_insn_and_split "*arm_subsi3_insn" - [(set (match_operand:SI 0 "s_register_operand" "=r,r") - (minus:SI (match_operand:SI 1 "reg_or_int_operand" "rI,?n") - (match_operand:SI 2 "s_register_operand" "r,r")))] - "TARGET_ARM" + [(set (match_operand:SI 0 "s_register_operand" "=r,rk,r") + (minus:SI (match_operand:SI 1 "reg_or_int_operand" "rI,!k,?n") + (match_operand:SI 2 "s_register_operand" "r, r, r")))] + "TARGET_32BIT" "@ rsb%?\\t%0, %2, %1 + sub%?\\t%0, %1, %2 #" - "TARGET_ARM + "TARGET_32BIT && GET_CODE (operands[1]) == CONST_INT && !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") + [(set_attr "length" "4,4,16") (set_attr "predicable" "yes")] ) (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" "")))] - "TARGET_ARM + (match_operand:SI 2 "arm_general_register_operand" "")))] + "TARGET_32BIT && !const_ok_for_arm (INTVAL (operands[1])) && const_ok_for_arm (~INTVAL (operands[1]))" [(set (match_dup 3) (match_dup 1)) @@ -1040,14 +1128,23 @@ (const_int 0))) (set (match_operand:SI 0 "s_register_operand" "=r,r") (minus:SI (match_dup 1) (match_dup 2)))] - "TARGET_ARM" + "TARGET_32BIT" "@ - sub%?s\\t%0, %1, %2 - rsb%?s\\t%0, %2, %1" + sub%.\\t%0, %1, %2 + rsb%.\\t%0, %2, %1" [(set_attr "conds" "set")] ) -(define_insn "decscc" +(define_expand "decscc" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (minus:SI (match_operand:SI 1 "s_register_operand" "0,?r") + (match_operator:SI 2 "arm_comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)])))] + "TARGET_32BIT" + "" +) + +(define_insn "*arm_decscc" [(set (match_operand:SI 0 "s_register_operand" "=r,r") (minus:SI (match_operand:SI 1 "s_register_operand" "0,?r") (match_operator:SI 2 "arm_comparison_operator" @@ -1060,76 +1157,36 @@ (set_attr "length" "*,8")] ) -(define_insn "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 "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")))] - "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")] -) - -(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"))))] - "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_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_32BIT && TARGET_HARD_FLOAT" + " + 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_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")] -) +(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_32BIT && TARGET_HARD_FLOAT" + " + 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 "subxf3" - [(set (match_operand:XF 0 "s_register_operand" "=f,f") - (minus:XF (match_operand:XF 1 "fpu_rhs_operand" "f,G") - (match_operand:XF 2 "fpu_rhs_operand" "fG,f")))] - "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" - "@ - suf%?e\\t%0, %1, %2 - rsf%?e\\t%0, %2, %1" - [(set_attr "type" "farith") - (set_attr "predicable" "yes")] -) ;; Multiplication insns @@ -1146,9 +1203,19 @@ [(set (match_operand:SI 0 "s_register_operand" "=&r,&r") (mult:SI (match_operand:SI 2 "s_register_operand" "r,r") (match_operand:SI 1 "s_register_operand" "%?r,0")))] - "TARGET_ARM" + "TARGET_32BIT && !arm_arch6" "mul%?\\t%0, %2, %1" - [(set_attr "type" "mult") + [(set_attr "insn" "mul") + (set_attr "predicable" "yes")] +) + +(define_insn "*arm_mulsi3_v6" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (mult:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "s_register_operand" "r")))] + "TARGET_32BIT && arm_arch6" + "mul%?\\t%0, %1, %2" + [(set_attr "insn" "mul") (set_attr "predicable" "yes")] ) @@ -1161,15 +1228,28 @@ [(set (match_operand:SI 0 "register_operand" "=&l,&l,&l") (mult:SI (match_operand:SI 1 "register_operand" "%l,*h,0") (match_operand:SI 2 "register_operand" "l,l,l")))] - "TARGET_THUMB" + "TARGET_THUMB1 && !arm_arch6" "* 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 "*thumb_mulsi3_v6" + [(set (match_operand:SI 0 "register_operand" "=l,l,l") + (mult:SI (match_operand:SI 1 "register_operand" "0,l,0") + (match_operand:SI 2 "register_operand" "l,0,0")))] + "TARGET_THUMB1 && arm_arch6" + "@ + mul\\t%0, %2 + mul\\t%0, %1 + mul\\t%0, %1" + [(set_attr "length" "2") + (set_attr "insn" "mul")] ) (define_insn "*mulsi3_compare0" @@ -1180,10 +1260,24 @@ (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" - "mul%?s\\t%0, %2, %1" + "TARGET_ARM && !arm_arch6" + "mul%.\\t%0, %2, %1" + [(set_attr "conds" "set") + (set_attr "insn" "muls")] +) + +(define_insn "*mulsi3_compare0_v6" + [(set (reg:CC_NOOV CC_REGNUM) + (compare:CC_NOOV (mult:SI + (match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 1 "s_register_operand" "r")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (mult:SI (match_dup 2) (match_dup 1)))] + "TARGET_ARM && arm_arch6 && optimize_size" + "mul%.\\t%0, %2, %1" [(set_attr "conds" "set") - (set_attr "type" "mult")] + (set_attr "insn" "muls")] ) (define_insn "*mulsi_compare0_scratch" @@ -1193,10 +1287,23 @@ (match_operand:SI 1 "s_register_operand" "%?r,0")) (const_int 0))) (clobber (match_scratch:SI 0 "=&r,&r"))] - "TARGET_ARM && !arm_is_xscale" - "mul%?s\\t%0, %2, %1" + "TARGET_ARM && !arm_arch6" + "mul%.\\t%0, %2, %1" + [(set_attr "conds" "set") + (set_attr "insn" "muls")] +) + +(define_insn "*mulsi_compare0_scratch_v6" + [(set (reg:CC_NOOV CC_REGNUM) + (compare:CC_NOOV (mult:SI + (match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 1 "s_register_operand" "r")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "TARGET_ARM && arm_arch6 && optimize_size" + "mul%.\\t%0, %2, %1" [(set_attr "conds" "set") - (set_attr "type" "mult")] + (set_attr "insn" "muls")] ) ;; Unnamed templates to match MLA instruction. @@ -1207,9 +1314,21 @@ (mult:SI (match_operand:SI 2 "s_register_operand" "r,r,r,r") (match_operand:SI 1 "s_register_operand" "%r,0,r,0")) (match_operand:SI 3 "s_register_operand" "?r,r,0,0")))] - "TARGET_ARM" + "TARGET_32BIT && !arm_arch6" + "mla%?\\t%0, %2, %1, %3" + [(set_attr "insn" "mla") + (set_attr "predicable" "yes")] +) + +(define_insn "*mulsi3addsi_v6" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI + (mult:SI (match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 1 "s_register_operand" "r")) + (match_operand:SI 3 "s_register_operand" "r")))] + "TARGET_32BIT && arm_arch6" "mla%?\\t%0, %2, %1, %3" - [(set_attr "type" "mult") + [(set_attr "insn" "mla") (set_attr "predicable" "yes")] ) @@ -1224,10 +1343,27 @@ (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" - "mla%?s\\t%0, %2, %1, %3" + "TARGET_ARM && arm_arch6" + "mla%.\\t%0, %2, %1, %3" + [(set_attr "conds" "set") + (set_attr "insn" "mlas")] +) + +(define_insn "*mulsi3addsi_compare0_v6" + [(set (reg:CC_NOOV CC_REGNUM) + (compare:CC_NOOV + (plus:SI (mult:SI + (match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 1 "s_register_operand" "r")) + (match_operand:SI 3 "s_register_operand" "r")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (mult:SI (match_dup 2) (match_dup 1)) + (match_dup 3)))] + "TARGET_ARM && arm_arch6 && optimize_size" + "mla%.\\t%0, %2, %1, %3" [(set_attr "conds" "set") - (set_attr "type" "mult")] + (set_attr "insn" "mlas")] ) (define_insn "*mulsi3addsi_compare0_scratch" @@ -1239,13 +1375,40 @@ (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" - "mla%?s\\t%0, %2, %1, %3" + "TARGET_ARM && !arm_arch6" + "mla%.\\t%0, %2, %1, %3" + [(set_attr "conds" "set") + (set_attr "insn" "mlas")] +) + +(define_insn "*mulsi3addsi_compare0_scratch_v6" + [(set (reg:CC_NOOV CC_REGNUM) + (compare:CC_NOOV + (plus:SI (mult:SI + (match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 1 "s_register_operand" "r")) + (match_operand:SI 3 "s_register_operand" "r")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "TARGET_ARM && arm_arch6 && optimize_size" + "mla%.\\t%0, %2, %1, %3" [(set_attr "conds" "set") - (set_attr "type" "mult")] + (set_attr "insn" "mlas")] +) + +(define_insn "*mulsi3subsi" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI + (match_operand:SI 3 "s_register_operand" "r") + (mult:SI (match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 1 "s_register_operand" "r"))))] + "TARGET_32BIT && arm_arch_thumb2" + "mls%?\\t%0, %2, %1, %3" + [(set_attr "insn" "mla") + (set_attr "predicable" "yes")] ) -;; 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") @@ -1254,35 +1417,94 @@ (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_32BIT && arm_arch3m && !arm_arch6" + "smlal%?\\t%Q0, %R0, %3, %2" + [(set_attr "insn" "smlal") + (set_attr "predicable" "yes")] +) + +(define_insn "*mulsidi3adddi_v6" + [(set (match_operand:DI 0 "s_register_operand" "=r") + (plus:DI + (mult:DI + (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_32BIT && arm_arch6" "smlal%?\\t%Q0, %R0, %3, %2" - [(set_attr "type" "mult") + [(set_attr "insn" "smlal") (set_attr "predicable" "yes")] ) -(define_insn "mulsidi3" +;; 32x32->64 widening multiply. +;; As with mulsi3, the only difference between the v3-5 and v6+ +;; versions of these patterns is the requirement that the output not +;; overlap the inputs, but that still means we have to have a named +;; expander and two different starred insns. + +(define_expand "mulsidi3" + [(set (match_operand:DI 0 "s_register_operand" "") + (mult:DI + (sign_extend:DI (match_operand:SI 1 "s_register_operand" "")) + (sign_extend:DI (match_operand:SI 2 "s_register_operand" ""))))] + "TARGET_32BIT && arm_arch3m" + "" +) + +(define_insn "*mulsidi3_nov6" [(set (match_operand:DI 0 "s_register_operand" "=&r") (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_32BIT && arm_arch3m && !arm_arch6" "smull%?\\t%Q0, %R0, %1, %2" - [(set_attr "type" "mult") + [(set_attr "insn" "smull") (set_attr "predicable" "yes")] ) -(define_insn "umulsidi3" +(define_insn "*mulsidi3_v6" + [(set (match_operand:DI 0 "s_register_operand" "=r") + (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_32BIT && arm_arch6" + "smull%?\\t%Q0, %R0, %1, %2" + [(set_attr "insn" "smull") + (set_attr "predicable" "yes")] +) + +(define_expand "umulsidi3" + [(set (match_operand:DI 0 "s_register_operand" "") + (mult:DI + (zero_extend:DI (match_operand:SI 1 "s_register_operand" "")) + (zero_extend:DI (match_operand:SI 2 "s_register_operand" ""))))] + "TARGET_32BIT && arm_arch3m" + "" +) + +(define_insn "*umulsidi3_nov6" [(set (match_operand:DI 0 "s_register_operand" "=&r") (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_32BIT && arm_arch3m && !arm_arch6" + "umull%?\\t%Q0, %R0, %1, %2" + [(set_attr "insn" "umull") + (set_attr "predicable" "yes")] +) + +(define_insn "*umulsidi3_v6" + [(set (match_operand:DI 0 "s_register_operand" "=r") + (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_32BIT && arm_arch6" "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") @@ -1291,13 +1513,40 @@ (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_32BIT && arm_arch3m && !arm_arch6" + "umlal%?\\t%Q0, %R0, %3, %2" + [(set_attr "insn" "umlal") + (set_attr "predicable" "yes")] +) + +(define_insn "*umulsidi3adddi_v6" + [(set (match_operand:DI 0 "s_register_operand" "=r") + (plus:DI + (mult:DI + (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_32BIT && arm_arch6" "umlal%?\\t%Q0, %R0, %3, %2" - [(set_attr "type" "mult") + [(set_attr "insn" "umlal") (set_attr "predicable" "yes")] ) -(define_insn "smulsi3_highpart" +(define_expand "smulsi3_highpart" + [(parallel + [(set (match_operand:SI 0 "s_register_operand" "") + (truncate:SI + (lshiftrt:DI + (mult:DI + (sign_extend:DI (match_operand:SI 1 "s_register_operand" "")) + (sign_extend:DI (match_operand:SI 2 "s_register_operand" ""))) + (const_int 32)))) + (clobber (match_scratch:SI 3 ""))])] + "TARGET_32BIT && arm_arch3m" + "" +) + +(define_insn "*smulsi3_highpart_nov6" [(set (match_operand:SI 0 "s_register_operand" "=&r,&r") (truncate:SI (lshiftrt:DI @@ -1306,14 +1555,43 @@ (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_32BIT && arm_arch3m && !arm_arch6" "smull%?\\t%3, %0, %2, %1" - [(set_attr "type" "mult") + [(set_attr "insn" "smull") (set_attr "predicable" "yes")] ) -(define_insn "umulsi3_highpart" - [(set (match_operand:SI 0 "s_register_operand" "=&r,&r") +(define_insn "*smulsi3_highpart_v6" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (truncate:SI + (lshiftrt:DI + (mult:DI + (sign_extend:DI (match_operand:SI 1 "s_register_operand" "r")) + (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r"))) + (const_int 32)))) + (clobber (match_scratch:SI 3 "=r"))] + "TARGET_32BIT && arm_arch6" + "smull%?\\t%3, %0, %2, %1" + [(set_attr "insn" "smull") + (set_attr "predicable" "yes")] +) + +(define_expand "umulsi3_highpart" + [(parallel + [(set (match_operand:SI 0 "s_register_operand" "") + (truncate:SI + (lshiftrt:DI + (mult:DI + (zero_extend:DI (match_operand:SI 1 "s_register_operand" "")) + (zero_extend:DI (match_operand:SI 2 "s_register_operand" ""))) + (const_int 32)))) + (clobber (match_scratch:SI 3 ""))])] + "TARGET_32BIT && arm_arch3m" + "" +) + +(define_insn "*umulsi3_highpart_nov6" + [(set (match_operand:SI 0 "s_register_operand" "=&r,&r") (truncate:SI (lshiftrt:DI (mult:DI @@ -1321,9 +1599,24 @@ (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_32BIT && arm_arch3m && !arm_arch6" + "umull%?\\t%3, %0, %2, %1" + [(set_attr "insn" "umull") + (set_attr "predicable" "yes")] +) + +(define_insn "*umulsi3_highpart_v6" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (truncate:SI + (lshiftrt:DI + (mult:DI + (zero_extend:DI (match_operand:SI 1 "s_register_operand" "r")) + (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r"))) + (const_int 32)))) + (clobber (match_scratch:SI 3 "=r"))] + "TARGET_32BIT && arm_arch6" "umull%?\\t%3, %0, %2, %1" - [(set_attr "type" "mult") + [(set_attr "insn" "umull") (set_attr "predicable" "yes")] ) @@ -1333,9 +1626,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_DSP_MULTIPLY" "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_DSP_MULTIPLY" + "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_DSP_MULTIPLY" + "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_DSP_MULTIPLY" + "smultt%?\\t%0, %1, %2" + [(set_attr "insn" "smulxy") + (set_attr "predicable" "yes")] ) (define_insn "*mulhisi3addsi" @@ -1345,9 +1679,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_DSP_MULTIPLY" "smlabb%?\\t%0, %2, %3, %1" - [(set_attr "type" "mult")] + [(set_attr "insn" "smlaxy") + (set_attr "predicable" "yes")] ) (define_insn "*mulhidi3adddi" @@ -1358,210 +1693,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_DSP_MULTIPLY" "smlalbb%?\\t%Q0, %R0, %2, %3" -[(set_attr "type" "mult")]) - -(define_insn "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 "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")] -) - -(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"))))] - "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_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"))))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "muf%?d\\t%0, %1, %2" - [(set_attr "type" "fmul") - (set_attr "predicable" "yes")] -) +(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_32BIT && TARGET_HARD_FLOAT" + " + if (TARGET_MAVERICK + && !cirrus_fp_register (operands[2], SFmode)) + operands[2] = force_reg (SFmode, operands[2]); +") -(define_insn "mulxf3" - [(set (match_operand:XF 0 "s_register_operand" "=f") - (mult:XF (match_operand:XF 1 "s_register_operand" "f") - (match_operand:XF 2 "fpu_rhs_operand" "fG")))] - "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" - "muf%?e\\t%0, %1, %2" - [(set_attr "type" "fmul") - (set_attr "predicable" "yes")] -) +(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_32BIT && TARGET_HARD_FLOAT" + " + 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_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 "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_32BIT && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" + "") -(define_insn "divxf3" - [(set (match_operand:XF 0 "s_register_operand" "=f,f") - (div:XF (match_operand:XF 1 "fpu_rhs_operand" "f,G") - (match_operand:XF 2 "fpu_rhs_operand" "fG,f")))] - "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" - "@ - dvf%?e\\t%0, %1, %2 - rdf%?e\\t%0, %2, %1" - [(set_attr "type" "fdivx") - (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_32BIT && 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_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 "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_32BIT && TARGET_HARD_FLOAT && TARGET_FPA" + "") -(define_insn "modxf3" - [(set (match_operand:XF 0 "s_register_operand" "=f") - (mod:XF (match_operand:XF 1 "s_register_operand" "f") - (match_operand:XF 2 "fpu_rhs_operand" "fG")))] - "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" - "rmf%?e\\t%0, %1, %2" - [(set_attr "type" "fdivx") - (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_32BIT && TARGET_HARD_FLOAT && TARGET_FPA" + "") ;; Boolean and,ior,xor insns @@ -1574,7 +1763,8 @@ (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_32BIT && 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)]))] " @@ -1593,7 +1783,7 @@ (match_operator:DI 6 "logical_binary_operator" [(sign_extend:DI (match_operand:SI 2 "s_register_operand" "")) (match_operand:DI 1 "s_register_operand" "")]))] - "TARGET_ARM && reload_completed" + "TARGET_32BIT && reload_completed" [(set (match_dup 0) (match_op_dup:SI 6 [(match_dup 1) (match_dup 2)])) (set (match_dup 3) (match_op_dup:SI 6 [(ashiftrt:SI (match_dup 2) (const_int 31)) @@ -1616,7 +1806,7 @@ (ior:DI (zero_extend:DI (match_operand:SI 2 "s_register_operand" "")) (match_operand:DI 1 "s_register_operand" "")))] - "TARGET_ARM && operands[0] != operands[1] && reload_completed" + "TARGET_32BIT && operands[0] != operands[1] && reload_completed" [(set (match_dup 0) (ior:SI (match_dup 1) (match_dup 2))) (set (match_dup 3) (match_dup 4))] " @@ -1635,7 +1825,7 @@ (xor:DI (zero_extend:DI (match_operand:SI 2 "s_register_operand" "")) (match_operand:DI 1 "s_register_operand" "")))] - "TARGET_ARM && operands[0] != operands[1] && reload_completed" + "TARGET_32BIT && operands[0] != operands[1] && reload_completed" [(set (match_dup 0) (xor:SI (match_dup 1) (match_dup 2))) (set (match_dup 3) (match_dup 4))] " @@ -1651,7 +1841,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_32BIT && ! TARGET_IWMMXT" "#" [(set_attr "length" "8")] ) @@ -1661,9 +1851,9 @@ (and:DI (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")) (match_operand:DI 1 "s_register_operand" "?r,0")))] - "TARGET_ARM" + "TARGET_32BIT" "#" - "TARGET_ARM && reload_completed" + "TARGET_32BIT && reload_completed" ; The zero extend of operand 2 clears the high word of the output ; operand. [(set (match_dup 0) (and:SI (match_dup 1) (match_dup 2))) @@ -1682,7 +1872,7 @@ (and:DI (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")) (match_operand:DI 1 "s_register_operand" "?r,0")))] - "TARGET_ARM" + "TARGET_32BIT" "#" [(set_attr "length" "8")] ) @@ -1693,18 +1883,18 @@ (match_operand:SI 2 "reg_or_int_operand" "")))] "TARGET_EITHER" " - if (TARGET_ARM) + if (TARGET_32BIT) { 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 && can_create_pseudo_p ()); + DONE; } } - else /* TARGET_THUMB */ + else /* TARGET_THUMB1 */ { if (GET_CODE (operands[2]) != CONST_INT) operands[2] = force_reg (SImode, operands[2]); @@ -1749,34 +1939,35 @@ " ) +; ??? Check split length for Thumb-2 (define_insn_and_split "*arm_andsi3_insn" [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") (and:SI (match_operand:SI 1 "s_register_operand" "r,r,r") (match_operand:SI 2 "reg_or_int_operand" "rI,K,?n")))] - "TARGET_ARM" + "TARGET_32BIT" "@ and%?\\t%0, %1, %2 bic%?\\t%0, %1, #%B2 #" - "TARGET_ARM + "TARGET_32BIT && GET_CODE (operands[2]) == CONST_INT && !(const_ok_for_arm (INTVAL (operands[2])) || 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") (set_attr "predicable" "yes")] ) -(define_insn "*thumb_andsi3_insn" +(define_insn "*thumb1_andsi3_insn" [(set (match_operand:SI 0 "register_operand" "=l") (and:SI (match_operand:SI 1 "register_operand" "%0") (match_operand:SI 2 "register_operand" "l")))] - "TARGET_THUMB" + "TARGET_THUMB1" "and\\t%0, %0, %2" [(set_attr "length" "2")] ) @@ -1789,10 +1980,10 @@ (const_int 0))) (set (match_operand:SI 0 "s_register_operand" "=r,r") (and:SI (match_dup 1) (match_dup 2)))] - "TARGET_ARM" + "TARGET_32BIT" "@ - and%?s\\t%0, %1, %2 - bic%?s\\t%0, %1, #%B2" + and%.\\t%0, %1, %2 + bic%.\\t%0, %1, #%B2" [(set_attr "conds" "set")] ) @@ -1803,10 +1994,10 @@ (match_operand:SI 1 "arm_not_operand" "rI,K")) (const_int 0))) (clobber (match_scratch:SI 2 "=X,r"))] - "TARGET_ARM" + "TARGET_32BIT" "@ tst%?\\t%0, %1 - bic%?s\\t%2, %0, #%B1" + bic%.\\t%2, %0, #%B1" [(set_attr "conds" "set")] ) @@ -1817,7 +2008,7 @@ (match_operand 1 "const_int_operand" "n") (match_operand 2 "const_int_operand" "n")) (const_int 0)))] - "TARGET_ARM + "TARGET_32BIT && (INTVAL (operands[2]) >= 0 && INTVAL (operands[2]) < 32 && INTVAL (operands[1]) > 0 && INTVAL (operands[1]) + (INTVAL (operands[2]) & 1) <= 8 @@ -1831,7 +2022,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") @@ -1839,27 +2030,209 @@ (match_operand:SI 3 "const_int_operand" "n")) (const_int 0))) (clobber (reg:CC CC_REGNUM))] - "TARGET_ARM + "TARGET_32BIT && (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)" - "* + "#" + "TARGET_32BIT + && (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])); + " + [(set_attr "conds" "clob") + (set (attr "length") + (if_then_else (eq_attr "is_thumb" "yes") + (const_int 12) + (const_int 8)))] +) + +(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)))] + " + operands[2] = GEN_INT (32 - INTVAL (operands[2])); + " + [(set_attr "conds" "clob") + (set_attr "length" "8")] +) + +(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])); - 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")] +) + +(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_THUMB1" + [(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); + }" +) + +;; ??? Use Thumb-2 has bitfield insert/extract instructions. +(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_THUMB1" + [(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 bitfield insert instruction, the truncation happens -;;; in the bitfield insert instruction itself. Since arm does not have a -;;; bitfield insert instruction, we would have to emit code here to truncate +;;; 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. @@ -1867,8 +2240,8 @@ [(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 "nonmemory_operand" ""))] - "TARGET_ARM" + (match_operand:SI 3 "reg_or_int_operand" ""))] + "TARGET_ARM || arm_arch_thumb2" " { int start_bit = INTVAL (operands[2]); @@ -1876,6 +2249,37 @@ HOST_WIDE_INT mask = (((HOST_WIDE_INT)1) << width) - 1; rtx target, subtarget; + if (arm_arch_thumb2) + { + bool use_bfi = TRUE; + + if (GET_CODE (operands[3]) == CONST_INT) + { + HOST_WIDE_INT val = INTVAL (operands[3]) & mask; + + if (val == 0) + { + emit_insn (gen_insv_zero (operands[0], operands[1], + operands[2])); + DONE; + } + + /* See if the set can be done with a single orr instruction. */ + if (val == mask && const_ok_for_arm (val << start_bit)) + use_bfi = FALSE; + } + + if (use_bfi) + { + if (GET_CODE (operands[3]) != REG) + operands[3] = force_reg (SImode, operands[3]); + + emit_insn (gen_insv_t2 (operands[0], operands[1], operands[2], + operands[3])); + DONE; + } + } + target = operands[0]; /* Avoid using a subreg as a subtarget, and avoid writing a paradoxical subreg as the final target. */ @@ -1902,9 +2306,10 @@ 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_andsi3 (op1, operands[0], + gen_int_mode (~mask2, SImode))); emit_insn (gen_iorsi3 (subtarget, op1, - GEN_INT (op3_value << start_bit))); + gen_int_mode (op3_value << start_bit, SImode))); } else if (start_bit == 0 && !(const_ok_for_arm (mask) @@ -1913,7 +2318,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); @@ -1940,7 +2345,7 @@ } else { - rtx op0 = GEN_INT (mask); + rtx op0 = gen_int_mode (mask, SImode); rtx op1 = gen_reg_rtx (SImode); rtx op2 = gen_reg_rtx (SImode); @@ -1959,7 +2364,7 @@ && (const_ok_for_arm (mask << start_bit) || const_ok_for_arm (~(mask << start_bit)))) { - op0 = GEN_INT (~(mask << start_bit)); + op0 = gen_int_mode (~(mask << start_bit), SImode); emit_insn (gen_andsi3 (op2, operands[0], op0)); } else @@ -1998,14 +2403,36 @@ }" ) +(define_insn "insv_zero" + [(set (zero_extract:SI (match_operand:SI 0 "s_register_operand" "+r") + (match_operand:SI 1 "const_int_operand" "M") + (match_operand:SI 2 "const_int_operand" "M")) + (const_int 0))] + "arm_arch_thumb2" + "bfc%?\t%0, %2, %1" + [(set_attr "length" "4") + (set_attr "predicable" "yes")] +) + +(define_insn "insv_t2" + [(set (zero_extract:SI (match_operand:SI 0 "s_register_operand" "+r") + (match_operand:SI 1 "const_int_operand" "M") + (match_operand:SI 2 "const_int_operand" "M")) + (match_operand:SI 3 "s_register_operand" "r"))] + "arm_arch_thumb2" + "bfi%?\t%0, %3, %2, %1" + [(set_attr "length" "4") + (set_attr "predicable" "yes")] +) + ; constants for op 2 will never be given to these patterns. (define_insn_and_split "*anddi_notdi_di" [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") (and:DI (not:DI (match_operand:DI 1 "s_register_operand" "r,0")) (match_operand:DI 2 "s_register_operand" "0,r")))] - "TARGET_ARM" + "TARGET_32BIT" "#" - "TARGET_ARM && reload_completed" + "TARGET_32BIT && 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)))] " @@ -2026,16 +2453,16 @@ (and:DI (not:DI (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r,r"))) (match_operand:DI 1 "s_register_operand" "0,?r")))] - "TARGET_ARM" + "TARGET_32BIT" "@ bic%?\\t%Q0, %Q1, %2 #" ; (not (zero_extend ...)) allows us to just copy the high word from ; operand1 to operand0. - "TARGET_ARM + "TARGET_32BIT && reload_completed && operands[0] != operands[1]" - [(set (match_dup 0) (and:SI (not:SI (match_dup 1)) (match_dup 2))) + [(set (match_dup 0) (and:SI (not:SI (match_dup 2)) (match_dup 1))) (set (match_dup 3) (match_dup 4))] " { @@ -2052,11 +2479,11 @@ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") (and:DI (not:DI (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r,r"))) - (match_operand:DI 1 "s_register_operand" "?r,0")))] - "TARGET_ARM" + (match_operand:DI 1 "s_register_operand" "0,r")))] + "TARGET_32BIT" "#" - "TARGET_ARM && reload_completed" - [(set (match_dup 0) (and:SI (not:SI (match_dup 1)) (match_dup 2))) + "TARGET_32BIT && reload_completed" + [(set (match_dup 0) (and:SI (not:SI (match_dup 2)) (match_dup 1))) (set (match_dup 3) (and:SI (not:SI (ashiftrt:SI (match_dup 2) (const_int 31))) (match_dup 4)))] @@ -2075,7 +2502,7 @@ [(set (match_operand:SI 0 "s_register_operand" "=r") (and:SI (not:SI (match_operand:SI 2 "s_register_operand" "r")) (match_operand:SI 1 "s_register_operand" "r")))] - "TARGET_ARM" + "TARGET_32BIT" "bic%?\\t%0, %1, %2" [(set_attr "predicable" "yes")] ) @@ -2084,22 +2511,24 @@ [(set (match_operand:SI 0 "register_operand" "=l") (and:SI (not:SI (match_operand:SI 1 "register_operand" "l")) (match_operand:SI 2 "register_operand" "0")))] - "TARGET_THUMB" + "TARGET_THUMB1" "bic\\t%0, %0, %1" [(set_attr "length" "2")] ) (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" @@ -2110,8 +2539,8 @@ (const_int 0))) (set (match_operand:SI 0 "s_register_operand" "=r") (and:SI (not:SI (match_dup 2)) (match_dup 1)))] - "TARGET_ARM" - "bic%?s\\t%0, %1, %2" + "TARGET_32BIT" + "bic%.\\t%0, %1, %2" [(set_attr "conds" "set")] ) @@ -2122,8 +2551,8 @@ (match_operand:SI 1 "s_register_operand" "r")) (const_int 0))) (clobber (match_scratch:SI 0 "=r"))] - "TARGET_ARM" - "bic%?s\\t%0, %1, %2" + "TARGET_32BIT" + "bic%.\\t%0, %1, %2" [(set_attr "conds" "set")] ) @@ -2131,7 +2560,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_32BIT && ! TARGET_IWMMXT" "#" [(set_attr "length" "8") (set_attr "predicable" "yes")] @@ -2142,7 +2571,7 @@ (ior:DI (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")) (match_operand:DI 1 "s_register_operand" "0,?r")))] - "TARGET_ARM" + "TARGET_32BIT" "@ orr%?\\t%Q0, %Q1, %2 #" @@ -2155,7 +2584,7 @@ (ior:DI (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")) (match_operand:DI 1 "s_register_operand" "?r,0")))] - "TARGET_ARM" + "TARGET_32BIT" "#" [(set_attr "length" "8") (set_attr "predicable" "yes")] @@ -2169,15 +2598,14 @@ " if (GET_CODE (operands[2]) == CONST_INT) { - if (TARGET_ARM) + if (TARGET_32BIT) { - 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 && can_create_pseudo_p ()); DONE; } - else /* TARGET_THUMB */ + else /* TARGET_THUMB1 */ operands [2] = force_reg (SImode, operands [2]); } " @@ -2187,38 +2615,38 @@ [(set (match_operand:SI 0 "s_register_operand" "=r,r") (ior:SI (match_operand:SI 1 "s_register_operand" "r,r") (match_operand:SI 2 "reg_or_int_operand" "rI,?n")))] - "TARGET_ARM" + "TARGET_32BIT" "@ orr%?\\t%0, %1, %2 #" - "TARGET_ARM + "TARGET_32BIT && GET_CODE (operands[2]) == CONST_INT && !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") (set_attr "predicable" "yes")] ) -(define_insn "*thumb_iorsi3" +(define_insn "*thumb1_iorsi3" [(set (match_operand:SI 0 "register_operand" "=l") (ior:SI (match_operand:SI 1 "register_operand" "%0") (match_operand:SI 2 "register_operand" "l")))] - "TARGET_THUMB" + "TARGET_THUMB1" "orr\\t%0, %0, %2" [(set_attr "length" "2")] ) (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 + "TARGET_32BIT && !const_ok_for_arm (INTVAL (operands[2])) && const_ok_for_arm (~INTVAL (operands[2]))" [(set (match_dup 3) (match_dup 2)) @@ -2233,8 +2661,8 @@ (const_int 0))) (set (match_operand:SI 0 "s_register_operand" "=r") (ior:SI (match_dup 1) (match_dup 2)))] - "TARGET_ARM" - "orr%?s\\t%0, %1, %2" + "TARGET_32BIT" + "orr%.\\t%0, %1, %2" [(set_attr "conds" "set")] ) @@ -2244,8 +2672,8 @@ (match_operand:SI 2 "arm_rhs_operand" "rI")) (const_int 0))) (clobber (match_scratch:SI 0 "=r"))] - "TARGET_ARM" - "orr%?s\\t%0, %1, %2" + "TARGET_32BIT" + "orr%.\\t%0, %1, %2" [(set_attr "conds" "set")] ) @@ -2253,7 +2681,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_32BIT && !TARGET_IWMMXT" "#" [(set_attr "length" "8") (set_attr "predicable" "yes")] @@ -2264,7 +2692,7 @@ (xor:DI (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")) (match_operand:DI 1 "s_register_operand" "0,?r")))] - "TARGET_ARM" + "TARGET_32BIT" "@ eor%?\\t%Q0, %Q1, %2 #" @@ -2277,7 +2705,7 @@ (xor:DI (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")) (match_operand:DI 1 "s_register_operand" "?r,0")))] - "TARGET_ARM" + "TARGET_32BIT" "#" [(set_attr "length" "8") (set_attr "predicable" "yes")] @@ -2288,7 +2716,7 @@ (xor:SI (match_operand:SI 1 "s_register_operand" "") (match_operand:SI 2 "arm_rhs_operand" "")))] "TARGET_EITHER" - "if (TARGET_THUMB) + "if (TARGET_THUMB1) if (GET_CODE (operands[2]) == CONST_INT) operands[2] = force_reg (SImode, operands[2]); " @@ -2298,16 +2726,16 @@ [(set (match_operand:SI 0 "s_register_operand" "=r") (xor:SI (match_operand:SI 1 "s_register_operand" "r") (match_operand:SI 2 "arm_rhs_operand" "rI")))] - "TARGET_ARM" + "TARGET_32BIT" "eor%?\\t%0, %1, %2" [(set_attr "predicable" "yes")] ) -(define_insn "*thumb_xorsi3" +(define_insn "*thumb1_xorsi3" [(set (match_operand:SI 0 "register_operand" "=l") (xor:SI (match_operand:SI 1 "register_operand" "%0") (match_operand:SI 2 "register_operand" "l")))] - "TARGET_THUMB" + "TARGET_THUMB1" "eor\\t%0, %0, %2" [(set_attr "length" "2")] ) @@ -2319,8 +2747,8 @@ (const_int 0))) (set (match_operand:SI 0 "s_register_operand" "=r") (xor:SI (match_dup 1) (match_dup 2)))] - "TARGET_ARM" - "eor%?s\\t%0, %1, %2" + "TARGET_32BIT" + "eor%.\\t%0, %1, %2" [(set_attr "conds" "set")] ) @@ -2329,7 +2757,7 @@ (compare:CC_NOOV (xor:SI (match_operand:SI 0 "s_register_operand" "r") (match_operand:SI 1 "arm_rhs_operand" "rI")) (const_int 0)))] - "TARGET_ARM" + "TARGET_32BIT" "teq%?\\t%0, %1" [(set_attr "conds" "set")] ) @@ -2339,12 +2767,12 @@ ; insns. (define_split - [(set (match_operand:SI 0 "s_register_operand" "=r") - (ior:SI (and:SI (not:SI (match_operand:SI 1 "s_register_operand" "r")) - (not:SI (match_operand:SI 2 "arm_rhs_operand" "rI"))) - (match_operand:SI 3 "arm_rhs_operand" "rI"))) - (clobber (match_operand:SI 4 "s_register_operand" "=r"))] - "TARGET_ARM" + [(set (match_operand:SI 0 "s_register_operand" "") + (ior:SI (and:SI (not:SI (match_operand:SI 1 "s_register_operand" "")) + (not:SI (match_operand:SI 2 "arm_rhs_operand" ""))) + (match_operand:SI 3 "arm_rhs_operand" ""))) + (clobber (match_operand:SI 4 "s_register_operand" ""))] + "TARGET_32BIT" [(set (match_dup 4) (and:SI (ior:SI (match_dup 1) (match_dup 2)) (not:SI (match_dup 3)))) (set (match_dup 0) (not:SI (match_dup 4)))] @@ -2356,45 +2784,222 @@ (and:SI (ior:SI (match_operand:SI 1 "s_register_operand" "r,r,0") (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")) (not:SI (match_operand:SI 3 "arm_rhs_operand" "rI,rI,rI"))))] - "TARGET_ARM" + "TARGET_32BIT" "orr%?\\t%0, %1, %2\;bic%?\\t%0, %0, %3" [(set_attr "length" "8") + (set_attr "ce_count" "2") (set_attr "predicable" "yes")] ) +; ??? Are these four splitters still beneficial when the Thumb-2 bitfield +; insns are available? +(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_32BIT + && 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_32BIT + && 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_32BIT + && 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_32BIT + && 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 -(define_insn "smaxsi3" - [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") - (smax:SI (match_operand:SI 1 "s_register_operand" "0,r,?r") - (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))) +(define_expand "smaxsi3" + [(parallel [ + (set (match_operand:SI 0 "s_register_operand" "") + (smax:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "arm_rhs_operand" ""))) + (clobber (reg:CC CC_REGNUM))])] + "TARGET_32BIT" + " + if (operands[2] == const0_rtx || operands[2] == constm1_rtx) + { + /* No need for a clobber of the condition code register here. */ + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_SMAX (SImode, operands[1], + operands[2]))); + DONE; + } +") + +(define_insn "*smax_0" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (smax:SI (match_operand:SI 1 "s_register_operand" "r") + (const_int 0)))] + "TARGET_32BIT" + "bic%?\\t%0, %1, %1, asr #31" + [(set_attr "predicable" "yes")] +) + +(define_insn "*smax_m1" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (smax:SI (match_operand:SI 1 "s_register_operand" "r") + (const_int -1)))] + "TARGET_32BIT" + "orr%?\\t%0, %1, %1, asr #31" + [(set_attr "predicable" "yes")] +) + +(define_insn "*arm_smax_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (smax:SI (match_operand:SI 1 "s_register_operand" "%0,?r") + (match_operand:SI 2 "arm_rhs_operand" "rI,rI"))) (clobber (reg:CC CC_REGNUM))] "TARGET_ARM" "@ cmp\\t%1, %2\;movlt\\t%0, %2 - cmp\\t%1, %2\;movge\\t%0, %1 cmp\\t%1, %2\;movge\\t%0, %1\;movlt\\t%0, %2" [(set_attr "conds" "clob") - (set_attr "length" "8,8,12")] + (set_attr "length" "8,12")] ) -(define_insn "sminsi3" - [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") - (smin:SI (match_operand:SI 1 "s_register_operand" "0,r,?r") - (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))) +(define_expand "sminsi3" + [(parallel [ + (set (match_operand:SI 0 "s_register_operand" "") + (smin:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "arm_rhs_operand" ""))) + (clobber (reg:CC CC_REGNUM))])] + "TARGET_32BIT" + " + if (operands[2] == const0_rtx) + { + /* No need for a clobber of the condition code register here. */ + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_SMIN (SImode, operands[1], + operands[2]))); + DONE; + } +") + +(define_insn "*smin_0" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (smin:SI (match_operand:SI 1 "s_register_operand" "r") + (const_int 0)))] + "TARGET_32BIT" + "and%?\\t%0, %1, %1, asr #31" + [(set_attr "predicable" "yes")] +) + +(define_insn "*arm_smin_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (smin:SI (match_operand:SI 1 "s_register_operand" "%0,?r") + (match_operand:SI 2 "arm_rhs_operand" "rI,rI"))) (clobber (reg:CC CC_REGNUM))] "TARGET_ARM" "@ cmp\\t%1, %2\;movge\\t%0, %2 - cmp\\t%1, %2\;movlt\\t%0, %1 cmp\\t%1, %2\;movlt\\t%0, %1\;movge\\t%0, %2" [(set_attr "conds" "clob") - (set_attr "length" "8,8,12")] + (set_attr "length" "8,12")] +) + +(define_expand "umaxsi3" + [(parallel [ + (set (match_operand:SI 0 "s_register_operand" "") + (umax:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "arm_rhs_operand" ""))) + (clobber (reg:CC CC_REGNUM))])] + "TARGET_32BIT" + "" ) -(define_insn "umaxsi3" +(define_insn "*arm_umaxsi3" [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") (umax:SI (match_operand:SI 1 "s_register_operand" "0,r,?r") (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))) @@ -2408,7 +3013,17 @@ (set_attr "length" "8,8,12")] ) -(define_insn "uminsi3" +(define_expand "uminsi3" + [(parallel [ + (set (match_operand:SI 0 "s_register_operand" "") + (umin:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "arm_rhs_operand" ""))) + (clobber (reg:CC CC_REGNUM))])] + "TARGET_32BIT" + "" +) + +(define_insn "*arm_uminsi3" [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") (umin:SI (match_operand:SI 1 "s_register_operand" "0,r,?r") (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))) @@ -2428,17 +3043,22 @@ [(match_operand:SI 1 "s_register_operand" "r") (match_operand:SI 2 "s_register_operand" "r")])) (clobber (reg:CC CC_REGNUM))] - "TARGET_ARM" + "TARGET_32BIT" "* - 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); + if (TARGET_THUMB2) + output_asm_insn (\"ite\t%d3\", operands); output_asm_insn (\"str%d3\\t%1, %0\", operands); output_asm_insn (\"str%D3\\t%2, %0\", operands); return \"\"; " [(set_attr "conds" "clob") - (set_attr "length" "12") + (set (attr "length") + (if_then_else (eq_attr "is_thumb" "yes") + (const_int 14) + (const_int 12))) (set_attr "type" "store1")] ) @@ -2452,30 +3072,78 @@ (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_32BIT && !arm_eliminable_register (operands[1])" "* { enum rtx_code code = GET_CODE (operands[4]); + bool need_else; - operands[5] = gen_rtx (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 || (code != PLUS && code != MINUS && code != IOR && code != XOR)) + need_else = true; + else + need_else = false; + + operands[5] = gen_rtx_fmt_ee (minmax_code (operands[5]), SImode, + operands[2], operands[3]); + output_asm_insn (\"cmp\\t%2, %3\", operands); + if (TARGET_THUMB2) + { + if (need_else) + output_asm_insn (\"ite\\t%d5\", operands); + else + output_asm_insn (\"it\\t%d5\", operands); + } + output_asm_insn (\"%i4%d5\\t%0, %1, %2\", operands); + if (need_else) output_asm_insn (\"%i4%D5\\t%0, %1, %3\", operands); return \"\"; }" [(set_attr "conds" "clob") - (set_attr "length" "12")] + (set (attr "length") + (if_then_else (eq_attr "is_thumb" "yes") + (const_int 14) + (const_int 12)))] ) ;; 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_32BIT" + " + 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_32BIT" + "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" "") @@ -2491,15 +3159,50 @@ " ) -(define_insn "*thumb_ashlsi3" +(define_insn "*thumb1_ashlsi3" [(set (match_operand:SI 0 "register_operand" "=l,l") (ashift:SI (match_operand:SI 1 "register_operand" "l,0") (match_operand:SI 2 "nonmemory_operand" "N,l")))] - "TARGET_THUMB" + "TARGET_THUMB1" "lsl\\t%0, %1, %2" [(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_32BIT" + " + 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_32BIT" + "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" "") @@ -2512,15 +3215,50 @@ " ) -(define_insn "*thumb_ashrsi3" +(define_insn "*thumb1_ashrsi3" [(set (match_operand:SI 0 "register_operand" "=l,l") (ashiftrt:SI (match_operand:SI 1 "register_operand" "l,0") (match_operand:SI 2 "nonmemory_operand" "N,l")))] - "TARGET_THUMB" + "TARGET_THUMB1" "asr\\t%0, %1, %2" [(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_32BIT" + " + 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_32BIT" + "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" "") @@ -2536,11 +3274,11 @@ " ) -(define_insn "*thumb_lshrsi3" +(define_insn "*thumb1_lshrsi3" [(set (match_operand:SI 0 "register_operand" "=l,l") (lshiftrt:SI (match_operand:SI 1 "register_operand" "l,0") (match_operand:SI 2 "nonmemory_operand" "N,l")))] - "TARGET_THUMB" + "TARGET_THUMB1" "lsr\\t%0, %1, %2" [(set_attr "length" "2")] ) @@ -2549,7 +3287,7 @@ [(set (match_operand:SI 0 "s_register_operand" "") (rotatert:SI (match_operand:SI 1 "s_register_operand" "") (match_operand:SI 2 "reg_or_int_operand" "")))] - "TARGET_ARM" + "TARGET_32BIT" " if (GET_CODE (operands[2]) == CONST_INT) operands[2] = GEN_INT ((32 - INTVAL (operands[2])) % 32); @@ -2568,13 +3306,13 @@ (match_operand:SI 2 "arm_rhs_operand" "")))] "TARGET_EITHER" " - if (TARGET_ARM) + if (TARGET_32BIT) { if (GET_CODE (operands[2]) == CONST_INT && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31) operands[2] = GEN_INT (INTVAL (operands[2]) % 32); } - else /* TARGET_THUMB */ + else /* TARGET_THUMB1 */ { if (GET_CODE (operands [2]) == CONST_INT) operands [2] = force_reg (SImode, operands[2]); @@ -2582,11 +3320,11 @@ " ) -(define_insn "*thumb_rotrsi3" +(define_insn "*thumb1_rotrsi3" [(set (match_operand:SI 0 "register_operand" "=l") (rotatert:SI (match_operand:SI 1 "register_operand" "0") (match_operand:SI 2 "register_operand" "l")))] - "TARGET_THUMB" + "TARGET_THUMB1" "ror\\t%0, %0, %2" [(set_attr "length" "2")] ) @@ -2596,11 +3334,13 @@ (match_operator:SI 3 "shift_operator" [(match_operand:SI 1 "s_register_operand" "r") (match_operand:SI 2 "reg_or_int_operand" "rM")]))] - "TARGET_ARM" - "mov%?\\t%0, %1%S3" + "TARGET_32BIT" + "* return arm_output_shift(operands, 0);" [(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" @@ -2611,11 +3351,13 @@ (const_int 0))) (set (match_operand:SI 0 "s_register_operand" "=r") (match_op_dup 3 [(match_dup 1) (match_dup 2)]))] - "TARGET_ARM" - "mov%?s\\t%0, %1%S3" + "TARGET_32BIT" + "* return arm_output_shift(operands, 1);" [(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" @@ -2625,14 +3367,13 @@ (match_operand:SI 2 "arm_rhs_operand" "rM")]) (const_int 0))) (clobber (match_scratch:SI 0 "=r"))] - "TARGET_ARM" - "mov%?s\\t%0, %1%S3" + "TARGET_32BIT" + "* return arm_output_shift(operands, 1);" [(set_attr "conds" "set") - (set_attr "shift" "1") - ] + (set_attr "shift" "1")] ) -(define_insn "*notsi_shiftsi" +(define_insn "*arm_notsi_shiftsi" [(set (match_operand:SI 0 "s_register_operand" "=r") (not:SI (match_operator:SI 3 "shift_operator" [(match_operand:SI 1 "s_register_operand" "r") @@ -2641,10 +3382,12 @@ "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" +(define_insn "*arm_notsi_shiftsi_compare0" [(set (reg:CC_NOOV CC_REGNUM) (compare:CC_NOOV (not:SI (match_operator:SI 3 "shift_operator" [(match_operand:SI 1 "s_register_operand" "r") @@ -2653,13 +3396,15 @@ (set (match_operand:SI 0 "s_register_operand" "=r") (not:SI (match_op_dup 3 [(match_dup 1) (match_dup 2)])))] "TARGET_ARM" - "mvn%?s\\t%0, %1%S3" + "mvn%.\\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" +(define_insn "*arm_not_shiftsi_compare0_scratch" [(set (reg:CC_NOOV CC_REGNUM) (compare:CC_NOOV (not:SI (match_operator:SI 3 "shift_operator" [(match_operand:SI 1 "s_register_operand" "r") @@ -2667,10 +3412,12 @@ (const_int 0))) (clobber (match_scratch:SI 0 "=r"))] "TARGET_ARM" - "mvn%?s\\t%0, %1%S3" + "mvn%.\\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 @@ -2683,12 +3430,19 @@ (set (match_operand:SI 0 "register_operand" "") (lshiftrt:SI (match_dup 4) (match_operand:SI 3 "const_int_operand" "")))] - "TARGET_THUMB" + "TARGET_THUMB1 || arm_arch_thumb2" " { HOST_WIDE_INT lshift = 32 - INTVAL (operands[2]) - INTVAL (operands[3]); HOST_WIDE_INT rshift = 32 - INTVAL (operands[2]); + if (arm_arch_thumb2) + { + emit_insn (gen_extzv_t2 (operands[0], operands[1], operands[2], + operands[3])); + DONE; + } + operands[3] = GEN_INT (rshift); if (lshift == 0) @@ -2702,6 +3456,28 @@ }" ) +(define_insn "extv" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (sign_extract:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "const_int_operand" "M") + (match_operand:SI 3 "const_int_operand" "M")))] + "arm_arch_thumb2" + "sbfx%?\t%0, %1, %3, %2" + [(set_attr "length" "4") + (set_attr "predicable" "yes")] +) + +(define_insn "extzv_t2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (zero_extract:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "const_int_operand" "M") + (match_operand:SI 3 "const_int_operand" "M")))] + "arm_arch_thumb2" + "ubfx%?\t%0, %1, %3, %2" + [(set_attr "length" "4") + (set_attr "predicable" "yes")] +) + ;; Unary arithmetic insns @@ -2712,7 +3488,7 @@ (clobber (reg:CC CC_REGNUM))])] "TARGET_EITHER" " - if (TARGET_THUMB) + if (TARGET_THUMB1) { if (GET_CODE (operands[1]) != REG) operands[1] = force_reg (SImode, operands[1]); @@ -2732,11 +3508,11 @@ (set_attr "length" "8")] ) -(define_insn "*thumb_negdi2" +(define_insn "*thumb1_negdi2" [(set (match_operand:DI 0 "register_operand" "=&l") (neg:DI (match_operand:DI 1 "register_operand" "l"))) (clobber (reg:CC CC_REGNUM))] - "TARGET_THUMB" + "TARGET_THUMB1" "mov\\t%R0, #0\;neg\\t%Q0, %Q1\;sbc\\t%R0, %R1" [(set_attr "length" "6")] ) @@ -2751,63 +3527,52 @@ (define_insn "*arm_negsi2" [(set (match_operand:SI 0 "s_register_operand" "=r") (neg:SI (match_operand:SI 1 "s_register_operand" "r")))] - "TARGET_ARM" + "TARGET_32BIT" "rsb%?\\t%0, %1, #0" [(set_attr "predicable" "yes")] ) -(define_insn "*thumb_negsi2" +(define_insn "*thumb1_negsi2" [(set (match_operand:SI 0 "register_operand" "=l") (neg:SI (match_operand:SI 1 "register_operand" "l")))] - "TARGET_THUMB" + "TARGET_THUMB1" "neg\\t%0, %1" [(set_attr "length" "2")] ) -(define_insn "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 "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_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 "negsf2" + [(set (match_operand:SF 0 "s_register_operand" "") + (neg:SF (match_operand:SF 1 "s_register_operand" "")))] + "TARGET_32BIT && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" + "" ) -(define_insn "negxf2" - [(set (match_operand:XF 0 "s_register_operand" "=f") - (neg:XF (match_operand:XF 1 "s_register_operand" "f")))] - "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" - "mnf%?e\\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_32BIT && 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_insn "abssi2" - [(set (match_operand:SI 0 "s_register_operand" "=r,&r") +(define_expand "abssi2" + [(parallel + [(set (match_operand:SI 0 "s_register_operand" "") + (abs:SI (match_operand:SI 1 "s_register_operand" ""))) + (clobber (match_dup 2))])] + "TARGET_EITHER" + " + if (TARGET_THUMB1) + operands[2] = gen_rtx_SCRATCH (SImode); + else + operands[2] = gen_rtx_REG (CCmode, CC_REGNUM); +") + +(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"))) (clobber (reg:CC CC_REGNUM))] "TARGET_ARM" @@ -2820,7 +3585,21 @@ (set_attr "length" "8")] ) -(define_insn "*neg_abssi2" +(define_insn_and_split "*thumb1_abssi2" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (abs:SI (match_operand:SI 1 "s_register_operand" "l"))) + (clobber (match_scratch:SI 2 "=&l"))] + "TARGET_THUMB1" + "#" + "TARGET_THUMB1 && reload_completed" + [(set (match_dup 2) (ashiftrt:SI (match_dup 1) (const_int 31))) + (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2))) + (set (match_dup 0) (xor:SI (match_dup 0) (match_dup 2)))] + "" + [(set_attr "length" "6")] +) + +(define_insn "*arm_neg_abssi2" [(set (match_operand:SI 0 "s_register_operand" "=r,&r") (neg:SI (abs:SI (match_operand:SI 1 "s_register_operand" "0,r")))) (clobber (reg:CC CC_REGNUM))] @@ -2834,154 +3613,50 @@ (set_attr "length" "8")] ) -(define_insn "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 "absdf2" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (abs:DF (match_operand:DF 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 "*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 "absxf2" - [(set (match_operand:XF 0 "s_register_operand" "=f") - (abs:XF (match_operand:XF 1 "s_register_operand" "f")))] - "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" - "abs%?e\\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")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "sqt%?s\\t%0, %1" - [(set_attr "type" "float_em") - (set_attr "predicable" "yes")] +(define_insn_and_split "*thumb1_neg_abssi2" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (neg:SI (abs:SI (match_operand:SI 1 "s_register_operand" "l")))) + (clobber (match_scratch:SI 2 "=&l"))] + "TARGET_THUMB1" + "#" + "TARGET_THUMB1 && reload_completed" + [(set (match_dup 2) (ashiftrt:SI (match_dup 1) (const_int 31))) + (set (match_dup 0) (minus:SI (match_dup 2) (match_dup 1))) + (set (match_dup 0) (xor:SI (match_dup 0) (match_dup 2)))] + "" + [(set_attr "length" "6")] ) -(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 "abssf2" + [(set (match_operand:SF 0 "s_register_operand" "") + (abs:SF (match_operand:SF 1 "s_register_operand" "")))] + "TARGET_32BIT && TARGET_HARD_FLOAT" + "") -(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 "absdf2" + [(set (match_operand:DF 0 "s_register_operand" "") + (abs:DF (match_operand:DF 1 "s_register_operand" "")))] + "TARGET_32BIT && TARGET_HARD_FLOAT" + "") -(define_insn "sqrtxf2" - [(set (match_operand:XF 0 "s_register_operand" "=f") - (sqrt:XF (match_operand:XF 1 "s_register_operand" "f")))] - "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" - "sqt%?e\\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_32BIT && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" + "") -;; SIN COS TAN and family are always emulated, so it's probably better -;; to always call a library function. -;(define_insn "sinsf2" -; [(set (match_operand:SF 0 "s_register_operand" "=f") -; (unspec:SF [(match_operand:SF 1 "s_register_operand" "f")] -; UNSPEC_SIN))] -; "TARGET_ARM && TARGET_HARD_FLOAT" -; "sin%?s\\t%0, %1" -;[(set_attr "type" "float_em")]) -; -;(define_insn "sindf2" -; [(set (match_operand:DF 0 "s_register_operand" "=f") -; (unspec:DF [(match_operand:DF 1 "s_register_operand" "f")] -; UNSPEC_SIN))] -; "TARGET_ARM && TARGET_HARD_FLOAT" -; "sin%?d\\t%0, %1" -;[(set_attr "type" "float_em")]) -; -;(define_insn "*sindf_esfdf" -; [(set (match_operand:DF 0 "s_register_operand" "=f") -; (unspec:DF [(float_extend:DF -; (match_operand:SF 1 "s_register_operand" "f"))] -; UNSPEC_SIN))] -; "TARGET_ARM && TARGET_HARD_FLOAT" -; "sin%?d\\t%0, %1" -;[(set_attr "type" "float_em")]) -; -;(define_insn "sinxf2" -; [(set (match_operand:XF 0 "s_register_operand" "=f") -; (unspec:XF [(match_operand:XF 1 "s_register_operand" "f")] -; UNSPEC_SIN))] -; "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" -; "sin%?e\\t%0, %1" -;[(set_attr "type" "float_em")]) -; -;(define_insn "cossf2" -; [(set (match_operand:SF 0 "s_register_operand" "=f") -; (unspec:SF [(match_operand:SF 1 "s_register_operand" "f")] -; UNSPEC_COS))] -; "TARGET_ARM && TARGET_HARD_FLOAT" -; "cos%?s\\t%0, %1" -;[(set_attr "type" "float_em")]) -; -;(define_insn "cosdf2" -; [(set (match_operand:DF 0 "s_register_operand" "=f") -; (unspec:DF [(match_operand:DF 1 "s_register_operand" "f")] -; UNSPEC_COS))] -; "TARGET_ARM && TARGET_HARD_FLOAT" -; "cos%?d\\t%0, %1" -;[(set_attr "type" "float_em")]) -; -;(define_insn "*cosdf_esfdf" -; [(set (match_operand:DF 0 "s_register_operand" "=f") -; (unspec:DF [(float_extend:DF -; (match_operand:SF 1 "s_register_operand" "f"))] -; UNSPEC_COS))] -; "TARGET_ARM && TARGET_HARD_FLOAT" -; "cos%?d\\t%0, %1" -;[(set_attr "type" "float_em")]) -; -;(define_insn "cosxf2" -; [(set (match_operand:XF 0 "s_register_operand" "=f") -; (unspec:XF [(match_operand:XF 1 "s_register_operand" "f")] -; UNSEPC_COS))] -; "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" -; "cos%?e\\t%0, %1" -;[(set_attr "type" "float_em")]) +(define_expand "sqrtdf2" + [(set (match_operand:DF 0 "s_register_operand" "") + (sqrt:DF (match_operand:DF 1 "s_register_operand" "")))] + "TARGET_32BIT && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" + "") (define_insn_and_split "one_cmpldi2" [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") (not:DI (match_operand:DI 1 "s_register_operand" "?r,0")))] - "TARGET_ARM" + "TARGET_32BIT" "#" - "TARGET_ARM && reload_completed" + "TARGET_32BIT && reload_completed" [(set (match_dup 0) (not:SI (match_dup 1))) (set (match_dup 2) (not:SI (match_dup 3)))] " @@ -3005,15 +3680,15 @@ (define_insn "*arm_one_cmplsi2" [(set (match_operand:SI 0 "s_register_operand" "=r") (not:SI (match_operand:SI 1 "s_register_operand" "r")))] - "TARGET_ARM" + "TARGET_32BIT" "mvn%?\\t%0, %1" [(set_attr "predicable" "yes")] ) -(define_insn "*thumb_one_cmplsi2" +(define_insn "*thumb1_one_cmplsi2" [(set (match_operand:SI 0 "register_operand" "=l") (not:SI (match_operand:SI 1 "register_operand" "l")))] - "TARGET_THUMB" + "TARGET_THUMB1" "mvn\\t%0, %1" [(set_attr "length" "2")] ) @@ -3024,8 +3699,8 @@ (const_int 0))) (set (match_operand:SI 0 "s_register_operand" "=r") (not:SI (match_dup 1)))] - "TARGET_ARM" - "mvn%?s\\t%0, %1" + "TARGET_32BIT" + "mvn%.\\t%0, %1" [(set_attr "conds" "set")] ) @@ -3034,102 +3709,87 @@ (compare:CC_NOOV (not:SI (match_operand:SI 1 "s_register_operand" "r")) (const_int 0))) (clobber (match_scratch:SI 0 "=r"))] - "TARGET_ARM" - "mvn%?s\\t%0, %1" + "TARGET_32BIT" + "mvn%.\\t%0, %1" [(set_attr "conds" "set")] ) ;; Fixed <--> Floating conversion insns -(define_insn "floatsisf2" - [(set (match_operand:SF 0 "s_register_operand" "=f") - (float:SF (match_operand:SI 1 "s_register_operand" "r")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "flt%?s\\t%0, %1" - [(set_attr "type" "r_2_f") - (set_attr "predicable" "yes")] -) +(define_expand "floatsisf2" + [(set (match_operand:SF 0 "s_register_operand" "") + (float:SF (match_operand:SI 1 "s_register_operand" "")))] + "TARGET_32BIT && TARGET_HARD_FLOAT" + " + if (TARGET_MAVERICK) + { + emit_insn (gen_cirrus_floatsisf2 (operands[0], operands[1])); + DONE; + } +") -(define_insn "floatsidf2" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (float:DF (match_operand:SI 1 "s_register_operand" "r")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "flt%?d\\t%0, %1" - [(set_attr "type" "r_2_f") - (set_attr "predicable" "yes")] -) +(define_expand "floatsidf2" + [(set (match_operand:DF 0 "s_register_operand" "") + (float:DF (match_operand:SI 1 "s_register_operand" "")))] + "TARGET_32BIT && TARGET_HARD_FLOAT" + " + if (TARGET_MAVERICK) + { + emit_insn (gen_cirrus_floatsidf2 (operands[0], operands[1])); + DONE; + } +") -(define_insn "floatsixf2" - [(set (match_operand:XF 0 "s_register_operand" "=f") - (float:XF (match_operand:SI 1 "s_register_operand" "r")))] - "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" - "flt%?e\\t%0, %1" - [(set_attr "type" "r_2_f") - (set_attr "predicable" "yes")] -) +(define_expand "fix_truncsfsi2" + [(set (match_operand:SI 0 "s_register_operand" "") + (fix:SI (fix:SF (match_operand:SF 1 "s_register_operand" ""))))] + "TARGET_32BIT && TARGET_HARD_FLOAT" + " + 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 "fix_truncsfsi2" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (fix:SI (match_operand:SF 1 "s_register_operand" "f")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "fix%?z\\t%0, %1" - [(set_attr "type" "f_2_r") - (set_attr "predicable" "yes")] -) - -(define_insn "fix_truncdfsi2" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (fix:SI (match_operand:DF 1 "s_register_operand" "f")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "fix%?z\\t%0, %1" - [(set_attr "type" "f_2_r") - (set_attr "predicable" "yes")] -) - -(define_insn "fix_truncxfsi2" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (fix:SI (match_operand:XF 1 "s_register_operand" "f")))] - "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" - "fix%?z\\t%0, %1" - [(set_attr "type" "f_2_r") - (set_attr "predicable" "yes")] -) +(define_expand "fix_truncdfsi2" + [(set (match_operand:SI 0 "s_register_operand" "") + (fix:SI (fix:DF (match_operand:DF 1 "s_register_operand" ""))))] + "TARGET_32BIT && TARGET_HARD_FLOAT" + " + 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 "truncdfsf2" - [(set (match_operand:SF 0 "s_register_operand" "=f") - (float_truncate:SF - (match_operand:DF 1 "s_register_operand" "f")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "mvf%?s\\t%0, %1" - [(set_attr "type" "ffarith") - (set_attr "predicable" "yes")] -) - -(define_insn "truncxfsf2" - [(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:XF 1 "s_register_operand" "f")))] - "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" - "mvf%?s\\t%0, %1" - [(set_attr "type" "ffarith") - (set_attr "predicable" "yes")] -) - -(define_insn "truncxfdf2" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (float_truncate:DF - (match_operand:XF 1 "s_register_operand" "f")))] - "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" - "mvf%?d\\t%0, %1" - [(set_attr "type" "ffarith") - (set_attr "predicable" "yes")] + (match_operand:DF 1 "s_register_operand" "")))] + "TARGET_32BIT && TARGET_HARD_FLOAT" + "" ) ;; Zero and sign extension instructions. -(define_insn "zero_extendsidi2" +(define_expand "zero_extendsidi2" + [(set (match_operand:DI 0 "s_register_operand" "") + (zero_extend:DI (match_operand:SI 1 "s_register_operand" "")))] + "TARGET_32BIT" + "" +) + +(define_insn "*arm_zero_extendsidi2" [(set (match_operand:DI 0 "s_register_operand" "=r") (zero_extend:DI (match_operand:SI 1 "s_register_operand" "r")))] "TARGET_ARM" @@ -3143,21 +3803,35 @@ (set_attr "predicable" "yes")] ) -(define_insn "zero_extendqidi2" +(define_expand "zero_extendqidi2" + [(set (match_operand:DI 0 "s_register_operand" "") + (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "")))] + "TARGET_32BIT" + "" +) + +(define_insn "*arm_zero_extendqidi2" [(set (match_operand:DI 0 "s_register_operand" "=r,r") (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] "TARGET_ARM" "@ and%?\\t%Q0, %1, #255\;mov%?\\t%R0, #0 - ldr%?b\\t%Q0, %1\;mov%?\\t%R0, #0" + 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")] ) -(define_insn "extendsidi2" +(define_expand "extendsidi2" + [(set (match_operand:DI 0 "s_register_operand" "") + (sign_extend:DI (match_operand:SI 1 "s_register_operand" "")))] + "TARGET_32BIT" + "" +) + +(define_insn "*arm_extendsidi2" [(set (match_operand:DI 0 "s_register_operand" "=r") (sign_extend:DI (match_operand:SI 1 "s_register_operand" "r")))] "TARGET_ARM" @@ -3181,72 +3855,38 @@ "TARGET_EITHER" " { - if (TARGET_ARM) + if ((TARGET_THUMB1 || 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" +(define_insn "*thumb1_zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=l") + (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] + "TARGET_THUMB1 && !arm_arch6" "* rtx mem = XEXP (operands[1], 0); @@ -3281,49 +3921,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 "*thumb1_zero_extendhisi2_v6" + [(set (match_operand:SI 0 "register_operand" "=l,l") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "l,m")))] + "TARGET_THUMB1 && 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" - "ldr%?h\\t%0, %1" - [(set_attr "type" "load") + [(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_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_INT_SIMD" + "uxtah%?\\t%0, %2, %1" + [(set_attr "type" "alu_shift") + (set_attr "predicable" "yes")] ) (define_expand "zero_extendqisi2" @@ -3331,7 +4011,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) { @@ -3366,32 +4046,78 @@ " ) -(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" +(define_insn "*thumb1_zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=l") + (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] + "TARGET_THUMB1 && !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 "*thumb1_zero_extendqisi2_v6" + [(set (match_operand:SI 0 "register_operand" "=l,l") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "l,m")))] + "TARGET_THUMB1 && 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" - "ldr%?b\\t%0, %1\\t%@ zero_extendqisi2" - [(set_attr "type" "load") + [(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_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_INT_SIMD" + "uxtab%?\\t%0, %2, %1" + [(set_attr "predicable" "yes") + (set_attr "insn" "xtab") + (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))) (clobber (match_operand:SI 2 "s_register_operand" ""))] - "TARGET_ARM && (GET_CODE (operands[1]) != MEM) && ! BYTES_BIG_ENDIAN" + "TARGET_32BIT && (GET_CODE (operands[1]) != MEM) && ! BYTES_BIG_ENDIAN" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (and:SI (match_dup 2) (const_int 255)))] + "" +) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (zero_extend:SI (subreg:QI (match_operand:SI 1 "" "") 3))) + (clobber (match_operand:SI 2 "s_register_operand" ""))] + "TARGET_32BIT && (GET_CODE (operands[1]) != MEM) && BYTES_BIG_ENDIAN" [(set (match_dup 2) (match_dup 1)) (set (match_dup 0) (and:SI (match_dup 2) (const_int 255)))] "" @@ -3401,7 +4127,7 @@ [(set (reg:CC_Z CC_REGNUM) (compare:CC_Z (match_operand:QI 0 "s_register_operand" "r") (const_int 0)))] - "TARGET_ARM" + "TARGET_32BIT" "tst\\t%0, #255" [(set_attr "conds" "set")] ) @@ -3416,55 +4142,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_THUMB1) + { + emit_insn (gen_thumb1_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_THUMB1) + emit_insn (gen_thumb1_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 "thumb1_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_THUMB1 && !arm_arch6" "* { rtx ops[4]; @@ -3501,12 +4223,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]; @@ -3514,10 +4232,80 @@ 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 "*thumb1_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_THUMB1 && 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")] +) + +;; This pattern will only be used when ldsh is not available (define_expand "extendhisi2_mem" [(set (match_dup 2) (zero_extend:SI (match_operand:HI 1 "" ""))) (set (match_dup 3) @@ -3531,10 +4319,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); @@ -3555,49 +4341,42 @@ }" ) -(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" - "ldr%?sh\\t%0, %1" - [(set_attr "type" "load") +(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_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; - " +;; ??? Check Thumb-2 pool range +(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_32BIT && 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_INT_SIMD" + "sxtah%?\\t%0, %2, %1" ) (define_expand "extendqihi2" [(set (match_dup 2) - (ashift:SI (match_operand:QI 1 "general_operand" "") + (ashift:SI (match_operand:QI 1 "arm_reg_or_extendqisi_mem_op" "") (const_int 24))) (set (match_operand:HI 0 "s_register_operand" "") (ashiftrt:SI (match_dup 2) @@ -3620,62 +4399,20 @@ }" ) -; 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")))] +(define_insn "*arm_extendqihi_insn" + [(set (match_operand:HI 0 "s_register_operand" "=r") + (sign_extend:HI (match_operand:QI 1 "arm_extendqisi_mem_op" "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" "") + (ashift:SI (match_operand:QI 1 "arm_reg_or_extendqisi_mem_op" "") (const_int 24))) (set (match_operand:SI 0 "s_register_operand" "") (ashiftrt:SI (match_dup 2) @@ -3683,97 +4420,68 @@ "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]); + + 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); - - 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; - } - }" -) - -; 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 "arm_extendqisi_mem_op" "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 "arm_reg_or_extendqisi_mem_op" "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 "*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_INT_SIMD" + "sxtab%?\\t%0, %2, %1" + [(set_attr "type" "alu_shift") + (set_attr "insn" "xtab") + (set_attr "predicable" "yes")] ) -(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 "*thumb1_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=l,l") + (sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))] + "TARGET_THUMB1 && !arm_arch6" "* { rtx ops[3]; @@ -3815,10 +4523,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); @@ -3845,37 +4552,96 @@ 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 "extendsfdf2" - [(set (match_operand:DF 0 "s_register_operand" "=f") - (float_extend:DF (match_operand:SF 1 "s_register_operand" "f")))] - "TARGET_ARM && TARGET_HARD_FLOAT" - "mvf%?d\\t%0, %1" - [(set_attr "type" "ffarith") - (set_attr "predicable" "yes")] -) +(define_insn "*thumb1_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_THUMB1 && arm_arch6" + "* + { + rtx ops[3]; + rtx mem; -(define_insn "extendsfxf2" - [(set (match_operand:XF 0 "s_register_operand" "=f") - (float_extend:XF (match_operand:SF 1 "s_register_operand" "f")))] - "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" - "mvf%?e\\t%0, %1" - [(set_attr "type" "ffarith") - (set_attr "predicable" "yes")] -) + if (which_alternative == 0) + return \"sxtb\\t%0, %1\"; -(define_insn "extenddfxf2" - [(set (match_operand:XF 0 "s_register_operand" "=f") - (float_extend:XF (match_operand:DF 1 "s_register_operand" "f")))] - "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" - "mvf%?e\\t%0, %1" - [(set_attr "type" "ffarith") - (set_attr "predicable" "yes")] + 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_32BIT && TARGET_HARD_FLOAT" + "" +) ;; Move insns (including loads and stores) @@ -3913,7 +4679,7 @@ ;; DONE; ;;}") -;; Recognise garbage generated above. +;; Recognize garbage generated above. ;;(define_insn "" ;; [(set (match_operand:TI 0 "general_operand" "=r,r,r,<,>,m") @@ -3943,38 +4709,139 @@ (match_operand:DI 1 "general_operand" ""))] "TARGET_EITHER" " - if (TARGET_THUMB) + if (can_create_pseudo_p ()) { - if (!no_new_pseudos) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (DImode, operands[1]); - } + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (DImode, operands[1]); } " ) (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" + [(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 + && ( register_operand (operands[0], DImode) + || register_operand (operands[1], DImode))" "* - 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_32BIT + && 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. ;;; ??? This was originally identical to the movdf_insn pattern. ;;; ??? The 'i' constraint looks funny, but it should always be replaced by ;;; thumb_reorg with a memory reference. -(define_insn "*thumb_movdi_insn" +(define_insn "*thumb1_movdi_insn" [(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_THUMB1 + && !(TARGET_HARD_FLOAT && TARGET_MAVERICK) && ( register_operand (operands[0], DImode) || register_operand (operands[1], DImode))" "* @@ -3998,7 +4865,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 \"\"; @@ -4009,7 +4876,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,*,*")] ) @@ -4018,75 +4885,152 @@ (match_operand:SI 1 "general_operand" ""))] "TARGET_EITHER" " - if (TARGET_ARM) + { + rtx base, offset, tmp; + + if (TARGET_32BIT) { - /* 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 && can_create_pseudo_p ()); DONE; } + + if (TARGET_USE_MOVT && !target_word_relocations + && GET_CODE (operands[1]) == SYMBOL_REF + && !flag_pic && !arm_tls_referenced_p (operands[1])) + { + arm_emit_movpair (operands[0], operands[1]); + DONE; + } } - else /* TARGET_THUMB.... */ + else /* TARGET_THUMB1... */ { - if (!no_new_pseudos) + if (can_create_pseudo_p ()) { if (GET_CODE (operands[0]) != REG) operands[1] = force_reg (SImode, operands[1]); } } - - if (flag_pic - && (CONSTANT_P (operands[1]) - || symbol_mentioned_p (operands[1]) - || label_mentioned_p (operands[1]))) - operands[1] = legitimize_pic_address (operands[1], SImode, - (no_new_pseudos ? operands[0] : 0)); + + if (ARM_OFFSETS_MUST_BE_WITHIN_SECTIONS_P) + { + split_const (operands[1], &base, &offset); + if (GET_CODE (base) == SYMBOL_REF + && !offset_within_block_p (base, INTVAL (offset))) + { + tmp = can_create_pseudo_p () ? gen_reg_rtx (SImode) : operands[0]; + emit_move_insn (tmp, base); + emit_insn (gen_addsi3 (operands[0], tmp, offset)); + DONE; + } + } + + /* Recognize the case where operand[1] is a reference to thread-local + data and load its address to a register. */ + if (arm_tls_referenced_p (operands[1])) + { + rtx tmp = operands[1]; + rtx addend = NULL; + + if (GET_CODE (tmp) == CONST && GET_CODE (XEXP (tmp, 0)) == PLUS) + { + addend = XEXP (XEXP (tmp, 0), 1); + tmp = XEXP (XEXP (tmp, 0), 0); + } + + gcc_assert (GET_CODE (tmp) == SYMBOL_REF); + gcc_assert (SYMBOL_REF_TLS_MODEL (tmp) != 0); + + tmp = legitimize_tls_address (tmp, + !can_create_pseudo_p () ? operands[0] : 0); + if (addend) + { + tmp = gen_rtx_PLUS (SImode, tmp, addend); + tmp = force_operand (tmp, operands[0]); + } + operands[1] = tmp; + } + else if (flag_pic + && (CONSTANT_P (operands[1]) + || symbol_mentioned_p (operands[1]) + || label_mentioned_p (operands[1]))) + operands[1] = legitimize_pic_address (operands[1], SImode, + (!can_create_pseudo_p () + ? operands[0] + : 0)); + } " ) +;; The ARM LO_SUM and HIGH are backwards - HIGH sets the low bits, and +;; LO_SUM adds in the high bits. Fortunately these are opaque operations +;; so this does not matter. +(define_insn "*arm_movt" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r") + (lo_sum:SI (match_operand:SI 1 "nonimmediate_operand" "0") + (match_operand:SI 2 "general_operand" "i")))] + "TARGET_32BIT" + "movt%?\t%0, #:upper16:%c2" + [(set_attr "predicable" "yes") + (set_attr "length" "4")] +) + +(define_insn "*arm_movw" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r") + (high:SI (match_operand:SI 1 "general_operand" "i")))] + "TARGET_32BIT" + "movw%?\t%0, #:lower16:%c1" + [(set_attr "predicable" "yes") + (set_attr "length" "4")] +) + (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 + [(set (match_operand:SI 0 "nonimmediate_operand" "=rk,r,r,r,rk,m") + (match_operand:SI 1 "general_operand" "rk, I,K,N,mi,rk"))] + "TARGET_ARM && ! TARGET_IWMMXT + && !(TARGET_HARD_FLOAT && TARGET_VFP) && ( register_operand (operands[0], SImode) || register_operand (operands[1], SImode))" "@ + mov%?\\t%0, %1 mov%?\\t%0, %1 mvn%?\\t%0, #%B1 + movw%?\\t%0, %1 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,*")] + (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 + "TARGET_32BIT && (!(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; " ) -(define_insn "*thumb_movsi_insn" - [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l, m,*lh") - (match_operand:SI 1 "general_operand" "l, I,J,K,>,l,mi,l,*lh"))] - "TARGET_THUMB +(define_insn "*thumb1_movsi_insn" + [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l, m,*lhk") + (match_operand:SI 1 "general_operand" "l, I,J,K,>,l,mi,l,*lhk"))] + "TARGET_THUMB1 && ( register_operand (operands[0], SImode) || register_operand (operands[1], SImode))" "@ @@ -4100,14 +5044,14 @@ 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,*,*")] ) (define_split [(set (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "const_int_operand" ""))] - "TARGET_THUMB && CONST_OK_FOR_THUMB_LETTER (INTVAL (operands[1]), 'J')" + "TARGET_THUMB1 && satisfies_constraint_J (operands[1])" [(set (match_dup 0) (match_dup 1)) (set (match_dup 0) (neg:SI (match_dup 0)))] "operands[1] = GEN_INT (- INTVAL (operands[1]));" @@ -4116,7 +5060,7 @@ (define_split [(set (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "const_int_operand" ""))] - "TARGET_THUMB && CONST_OK_FOR_THUMB_LETTER (INTVAL (operands[1]), 'K')" + "TARGET_THUMB1 && satisfies_constraint_K (operands[1])" [(set (match_dup 0) (match_dup 1)) (set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))] " @@ -4129,6 +5073,7 @@ if ((val & (mask << i)) == val) break; + /* Shouldn't happen, but we don't want to split if the shift is zero. */ if (i == 0) FAIL; @@ -4151,85 +5096,104 @@ (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))] ) -(define_insn "pic_load_addr_thumb" +(define_insn "pic_load_addr_thumb1" [(set (match_operand:SI 0 "s_register_operand" "=l") (unspec:SI [(match_operand:SI 1 "" "mX")] UNSPEC_PIC_SYM))] - "TARGET_THUMB && flag_pic" + "TARGET_THUMB1 && 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") - (unspec:SI [(match_operand 1 "" "") (match_dup 2)] UNSPEC_PIC_SYM))] - "TARGET_ARM && flag_pic" - "operands[2] = pic_offset_table_rtx;" -) - -(define_insn "*pic_load_addr_based_insn" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (unspec:SI [(match_operand 1 "" "") - (match_operand 2 "s_register_operand" "r")] - UNSPEC_PIC_SYM))] - "TARGET_EITHER && flag_pic && operands[2] == pic_offset_table_rtx" - "* -#ifdef AOF_ASSEMBLER - operands[1] = aof_pic_entry (operands[1]); -#endif - output_asm_insn (\"ldr%?\\t%0, %a1\", operands); - return \"\"; - " - [(set_attr "type" "load") - (set (attr "pool_range") - (if_then_else (eq_attr "is_thumb" "yes") - (const_int 1024) - (const_int 4096))) - (set (attr "neg_pool_range") - (if_then_else (eq_attr "is_thumb" "yes") - (const_int 0) - (const_int 4084)))] -) - (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))))) - (use (label_ref (match_operand 1 "" "")))] - "TARGET_THUMB && flag_pic" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "register_operand" "0") + (const_int 4) + (match_operand 2 "" "")] + UNSPEC_PIC_BASE))] + "TARGET_THUMB1" "* - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", - CODE_LABEL_NUMBER (operands[1])); + (*targetm.asm_out.internal_label) (asm_out_file, \"LPIC\", + INTVAL (operands[2])); return \"add\\t%0, %|pc\"; " [(set_attr "length" "2")] ) (define_insn "pic_add_dot_plus_eight" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "register_operand" "r") + (const_int 8) + (match_operand 2 "" "")] + UNSPEC_PIC_BASE))] + "TARGET_ARM" + "* + (*targetm.asm_out.internal_label) (asm_out_file, \"LPIC\", + INTVAL (operands[2])); + return \"add%?\\t%0, %|pc, %1\"; + " + [(set_attr "predicable" "yes")] +) + +(define_insn "tls_load_dot_plus_eight" [(set (match_operand:SI 0 "register_operand" "+r") - (plus:SI (match_dup 0) (const (plus:SI (pc) (const_int 8))))) - (use (label_ref (match_operand 1 "" "")))] - "TARGET_ARM && flag_pic" + (mem:SI (unspec:SI [(match_operand:SI 1 "register_operand" "r") + (const_int 8) + (match_operand 2 "" "")] + UNSPEC_PIC_BASE)))] + "TARGET_ARM" "* - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", - CODE_LABEL_NUMBER (operands[1])); - return \"add%?\\t%0, %|pc, %0\"; + (*targetm.asm_out.internal_label) (asm_out_file, \"LPIC\", + INTVAL (operands[2])); + return \"ldr%?\\t%0, [%|pc, %1]\t\t@ tls_load_dot_plus_eight\"; " [(set_attr "predicable" "yes")] ) +;; PIC references to local variables can generate pic_add_dot_plus_eight +;; followed by a load. These sequences can be crunched down to +;; tls_load_dot_plus_eight by a peephole. + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (unspec:SI [(match_operand:SI 3 "register_operand" "") + (const_int 8) + (match_operand 1 "" "")] + UNSPEC_PIC_BASE)) + (set (match_operand:SI 2 "register_operand" "") (mem:SI (match_dup 0)))] + "TARGET_ARM && peep2_reg_dead_p (2, operands[0])" + [(set (match_dup 2) + (mem:SI (unspec:SI [(match_dup 3) + (const_int 8) + (match_dup 1)] + UNSPEC_PIC_BASE)))] + "" +) + +(define_insn "pic_offset_arm" + [(set (match_operand:SI 0 "register_operand" "=r") + (mem:SI (plus:SI (match_operand:SI 1 "register_operand" "r") + (unspec:SI [(match_operand:SI 2 "" "X")] + UNSPEC_PIC_OFFSET))))] + "TARGET_VXWORKS_RTP && TARGET_ARM && flag_pic" + "ldr%?\\t%0, [%1,%2]" + [(set_attr "type" "load1")] +) + (define_expand "builtin_setjmp_receiver" [(label_ref (match_operand 0 "" ""))] "flag_pic" " { - arm_finalize_pic (0); + /* r3 is clobbered by set/longjmp, so we can use it as a scratch + register. */ + if (arm_pic_register != INVALID_REGNUM) + arm_load_pic_register (1UL << 3); DONE; }") @@ -4243,10 +5207,10 @@ (const_int 0))) (set (match_operand:SI 0 "s_register_operand" "=r,r") (match_dup 1))] - "TARGET_ARM" + "TARGET_32BIT" "@ cmp%?\\t%0, #0 - sub%?s\\t%0, %1, #0" + sub%.\\t%0, %1, #0" [(set_attr "conds" "set")] ) @@ -4265,7 +5229,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" " { @@ -4281,7 +5245,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]); }" ) @@ -4289,7 +5254,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" " { @@ -4306,13 +5271,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" " @@ -4353,13 +5319,14 @@ 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]); }" ) (define_expand "storehi_single_op" [(set (match_operand:HI 0 "memory_operand" "") (match_operand:HI 1 "general_operand" ""))] - "TARGET_ARM && arm_arch4" + "TARGET_32BIT && arm_arch4" " if (!s_register_operand (operands[1], HImode)) operands[1] = copy_to_mode_reg (HImode, operands[1]); @@ -4373,7 +5340,7 @@ " if (TARGET_ARM) { - if (!no_new_pseudos) + if (can_create_pseudo_p ()) { if (GET_CODE (operands[0]) == MEM) { @@ -4417,115 +5384,95 @@ emit_insn (gen_movsi (reg, GEN_INT (val))); operands[1] = gen_lowpart (HImode, reg); } + else if (arm_arch4 && optimize && can_create_pseudo_p () + && GET_CODE (operands[1]) == MEM) + { + rtx reg = gen_reg_rtx (SImode); + + emit_insn (gen_zero_extendhisi2 (reg, operands[1])); + operands[1] = gen_lowpart (HImode, reg); + } 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_rtx; + + new_rtx = widen_memory_access (operands[1], SImode, + ((INTVAL (offset) & ~3) + - INTVAL (offset))); + emit_insn (gen_movsi (reg, new_rtx)); + 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])); DONE; } } - else /* TARGET_THUMB */ + else if (TARGET_THUMB2) { - if (!no_new_pseudos) - { - if (GET_CODE (operands[0]) != REG) + /* Thumb-2 can do everything except mem=mem and mem=const easily. */ + if (can_create_pseudo_p ()) + { + if (GET_CODE (operands[0]) != REG) operands[1] = force_reg (HImode, operands[1]); + /* Zero extend a constant, and keep it in an SImode reg. */ + else if (GET_CODE (operands[1]) == CONST_INT) + { + rtx reg = gen_reg_rtx (SImode); + HOST_WIDE_INT val = INTVAL (operands[1]) & 0xffff; + + emit_insn (gen_movsi (reg, GEN_INT (val))); + operands[1] = gen_lowpart (HImode, reg); + } + } + } + else /* TARGET_THUMB1 */ + { + if (can_create_pseudo_p ()) + { + 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 @@ -4548,17 +5495,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')) + && !satisfies_constraint_I (operands[1])) { + /* 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; } @@ -4566,10 +5524,10 @@ " ) -(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"))] - "TARGET_THUMB +(define_insn "*thumb1_movhi_insn" + [(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_THUMB1 && ( register_operand (operands[0], HImode) || register_operand (operands[1], HImode))" "* @@ -4580,7 +5538,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. */ @@ -4600,29 +5558,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) @@ -4635,10 +5574,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); @@ -4665,15 +5602,16 @@ (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]); " ) -;; Pattern to recognise insn generated default case above +;; Pattern to recognize insn generated default case above (define_insn "*movhi_insn_arch4" [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,m,r") (match_operand:HI 1 "general_operand" "rI,K,r,m"))] @@ -4685,86 +5623,39 @@ "@ mov%?\\t%0, %1\\t%@ movhi mvn%?\\t%0, #%B1\\t%@ movhi - str%?h\\t%1, %0\\t%@ movhi - ldr%?h\\t%0, %1\\t%@ movhi" - [(set_attr "type" "*,*,store1,load") + str%(h%)\\t%1, %0\\t%@ movhi + ldr%(h%)\\t%0, %1\\t%@ movhi" + [(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"))] - "TARGET_THUMB" - "* - abort ();" +(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_THUMB1" + " + 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 @@ -4787,7 +5678,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); @@ -4801,30 +5692,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); + /* Everything except mem = const or mem = mem can be done easily */ - emit_insn (gen_movsi (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 (can_create_pseudo_p ()) { - 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 @@ -4845,20 +5726,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 + && !satisfies_constraint_I (operands[1])) + { + /* 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; } " ) @@ -4867,22 +5760,22 @@ (define_insn "*arm_movqi_insn" [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r,m") (match_operand:QI 1 "general_operand" "rI,K,m,r"))] - "TARGET_ARM + "TARGET_32BIT && ( register_operand (operands[0], QImode) || register_operand (operands[1], QImode))" "@ mov%?\\t%0, %1 mvn%?\\t%0, #%B1 - ldr%?b\\t%0, %1 - str%?b\\t%1, %0" - [(set_attr "type" "*,*,load,store1") + ldr%(b%)\\t%0, %1 + str%(b%)\\t%1, %0" + [(set_attr "type" "*,*,load1,store1") (set_attr "predicable" "yes")] ) -(define_insn "*thumb_movqi_insn" +(define_insn "*thumb1_movqi_insn" [(set (match_operand:QI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") (match_operand:QI 1 "general_operand" "l, m,l,*h,*r,I"))] - "TARGET_THUMB + "TARGET_THUMB1 && ( register_operand (operands[0], QImode) || register_operand (operands[1], QImode))" "@ @@ -4893,7 +5786,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,*,*,*,*")] ) @@ -4902,14 +5795,14 @@ (match_operand:SF 1 "general_operand" ""))] "TARGET_EITHER" " - if (TARGET_ARM) + if (TARGET_32BIT) { if (GET_CODE (operands[0]) == MEM) operands[1] = force_reg (SFmode, operands[1]); } - else /* TARGET_THUMB */ + else /* TARGET_THUMB1 */ { - if (!no_new_pseudos) + if (can_create_pseudo_p ()) { if (GET_CODE (operands[0]) != REG) operands[1] = force_reg (SFmode, operands[1]); @@ -4918,11 +5811,12 @@ " ) +;; Transform a floating-point move of a constant into a core register into +;; an SImode operation. (define_split - [(set (match_operand:SF 0 "nonimmediate_operand" "") + [(set (match_operand:SF 0 "arm_general_register_operand" "") (match_operand:SF 1 "immediate_operand" ""))] - "TARGET_ARM - && !TARGET_HARD_FLOAT + "TARGET_32BIT && reload_completed && GET_CODE (operands[1]) == CONST_DOUBLE" [(set (match_dup 2) (match_dup 3))] @@ -4934,35 +5828,6 @@ " ) -(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"))] - "TARGET_ARM - && TARGET_HARD_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 "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"))] @@ -4976,16 +5841,16 @@ str%?\\t%1, %0\\t%@ float" [(set_attr "length" "4,4,4") (set_attr "predicable" "yes") - (set_attr "type" "*,load,store1") + (set_attr "type" "*,load1,store1") (set_attr "pool_range" "*,4096,*") (set_attr "neg_pool_range" "*,4084,*")] ) ;;; ??? This should have alternatives for constants. -(define_insn "*thumb_movsf_insn" +(define_insn "*thumb1_movsf_insn" [(set (match_operand:SF 0 "nonimmediate_operand" "=l,l,>,l, m,*r,*h") (match_operand:SF 1 "general_operand" "l, >,l,mF,l,*h,*r"))] - "TARGET_THUMB + "TARGET_THUMB1 && ( register_operand (operands[0], SFmode) || register_operand (operands[1], SFmode))" "@ @@ -4997,7 +5862,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,*,*,*")] ) @@ -5006,14 +5871,14 @@ (match_operand:DF 1 "general_operand" ""))] "TARGET_EITHER" " - if (TARGET_ARM) + if (TARGET_32BIT) { if (GET_CODE (operands[0]) == MEM) operands[1] = force_reg (DFmode, operands[1]); } else /* TARGET_THUMB */ { - if (!no_new_pseudos) + if (can_create_pseudo_p ()) { if (GET_CODE (operands[0]) != REG) operands[1] = force_reg (DFmode, operands[1]); @@ -5028,7 +5893,7 @@ [(match_operand:DF 0 "arm_reload_memory_operand" "=o") (match_operand:DF 1 "s_register_operand" "r") (match_operand:SI 2 "s_register_operand" "=&r")] - "TARGET_ARM" + "TARGET_32BIT" " { enum rtx_code code = GET_CODE (XEXP (operands[0], 0)); @@ -5055,7 +5920,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) @@ -5065,52 +5931,25 @@ }" ) -(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 +(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 + && ( register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode))" "* - { 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 " - "* 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")] ) @@ -5122,7 +5961,7 @@ (define_insn "*thumb_movdf_insn" [(set (match_operand:DF 0 "nonimmediate_operand" "=l,l,>,l, m,*r") (match_operand:DF 1 "general_operand" "l, >,l,mF,l,*r"))] - "TARGET_THUMB + "TARGET_THUMB1 && ( register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode))" "* @@ -5140,8 +5979,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: @@ -5151,43 +5990,20 @@ } " [(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,*,*")] ) - (define_expand "movxf" [(set (match_operand:XF 0 "general_operand" "") (match_operand:XF 1 "general_operand" ""))] - "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" - "") - -;; Even when the XFmode patterns aren't enabled, we enable this after -;; reloading so that we can push floating point registers in the prologue. - -(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 && (ENABLE_XF_PATTERNS || 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); - } + "TARGET_32BIT && 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,*,*,*,*")] ) + ;; load- and store-multiple insns @@ -5198,8 +6014,10 @@ [(match_par_dup 3 [(set (match_operand:SI 0 "" "") (match_operand:SI 1 "" "")) (use (match_operand:SI 2 "" ""))])] - "TARGET_ARM" - " + "TARGET_32BIT" +{ + HOST_WIDE_INT offset = 0; + /* Support only fixed point registers. */ if (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) > 14 @@ -5213,11 +6031,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 @@ -5234,12 +6049,30 @@ (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_ARM && XVECLEN (operands[0], 0) == 5" - "ldm%?ia\\t%1!, {%3, %4, %5, %6}" - [(set_attr "type" "load") + "TARGET_32BIT && XVECLEN (operands[0], 0) == 5" + "ldm%(ia%)\\t%1!, {%3, %4, %5, %6}" + [(set_attr "type" "load4") (set_attr "predicable" "yes")] ) +(define_insn "*ldmsi_postinc4_thumb1" + [(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_THUMB1 && 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") @@ -5251,9 +6084,9 @@ (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))))])] - "TARGET_ARM && XVECLEN (operands[0], 0) == 4" - "ldm%?ia\\t%1!, {%3, %4, %5}" - [(set_attr "type" "load") + "TARGET_32BIT && XVECLEN (operands[0], 0) == 4" + "ldm%(ia%)\\t%1!, {%3, %4, %5}" + [(set_attr "type" "load3") (set_attr "predicable" "yes")] ) @@ -5266,9 +6099,9 @@ (mem:SI (match_dup 2))) (set (match_operand:SI 4 "arm_hard_register_operand" "") (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") + "TARGET_32BIT && XVECLEN (operands[0], 0) == 3" + "ldm%(ia%)\\t%1!, {%3, %4}" + [(set_attr "type" "load2") (set_attr "predicable" "yes")] ) @@ -5284,9 +6117,9 @@ (mem:SI (plus:SI (match_dup 1) (const_int 8)))) (set (match_operand:SI 5 "arm_hard_register_operand" "") (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") + "TARGET_32BIT && XVECLEN (operands[0], 0) == 4" + "ldm%(ia%)\\t%1, {%2, %3, %4, %5}" + [(set_attr "type" "load4") (set_attr "predicable" "yes")] ) @@ -5298,9 +6131,9 @@ (mem:SI (plus:SI (match_dup 1) (const_int 4)))) (set (match_operand:SI 4 "arm_hard_register_operand" "") (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") + "TARGET_32BIT && XVECLEN (operands[0], 0) == 3" + "ldm%(ia%)\\t%1, {%2, %3, %4}" + [(set_attr "type" "load3") (set_attr "predicable" "yes")] ) @@ -5310,9 +6143,9 @@ (mem:SI (match_operand:SI 1 "s_register_operand" "r"))) (set (match_operand:SI 3 "arm_hard_register_operand" "") (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") + "TARGET_32BIT && XVECLEN (operands[0], 0) == 2" + "ldm%(ia%)\\t%1, {%2, %3}" + [(set_attr "type" "load2") (set_attr "predicable" "yes")] ) @@ -5320,9 +6153,11 @@ [(match_par_dup 3 [(set (match_operand:SI 0 "" "") (match_operand:SI 1 "" "")) (use (match_operand:SI 2 "" ""))])] - "TARGET_ARM" - " - /* Support only fixed point registers */ + "TARGET_32BIT" +{ + 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 @@ -5335,11 +6170,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 @@ -5356,12 +6188,30 @@ (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_ARM && XVECLEN (operands[0], 0) == 5" - "stm%?ia\\t%1!, {%3, %4, %5, %6}" + "TARGET_32BIT && XVECLEN (operands[0], 0) == 5" + "stm%(ia%)\\t%1!, {%3, %4, %5, %6}" [(set_attr "predicable" "yes") (set_attr "type" "store4")] ) +(define_insn "*stmsi_postinc4_thumb1" + [(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_THUMB1 && 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") @@ -5373,8 +6223,8 @@ (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" ""))])] - "TARGET_ARM && XVECLEN (operands[0], 0) == 4" - "stm%?ia\\t%1!, {%3, %4, %5}" + "TARGET_32BIT && XVECLEN (operands[0], 0) == 4" + "stm%(ia%)\\t%1!, {%3, %4, %5}" [(set_attr "predicable" "yes") (set_attr "type" "store3")] ) @@ -5388,8 +6238,8 @@ (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" ""))])] - "TARGET_ARM && XVECLEN (operands[0], 0) == 3" - "stm%?ia\\t%1!, {%3, %4}" + "TARGET_32BIT && XVECLEN (operands[0], 0) == 3" + "stm%(ia%)\\t%1!, {%3, %4}" [(set_attr "predicable" "yes") (set_attr "type" "store2")] ) @@ -5406,8 +6256,8 @@ (match_operand:SI 4 "arm_hard_register_operand" "")) (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) (match_operand:SI 5 "arm_hard_register_operand" ""))])] - "TARGET_ARM && XVECLEN (operands[0], 0) == 4" - "stm%?ia\\t%1, {%2, %3, %4, %5}" + "TARGET_32BIT && XVECLEN (operands[0], 0) == 4" + "stm%(ia%)\\t%1, {%2, %3, %4, %5}" [(set_attr "predicable" "yes") (set_attr "type" "store4")] ) @@ -5420,8 +6270,8 @@ (match_operand:SI 3 "arm_hard_register_operand" "")) (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) (match_operand:SI 4 "arm_hard_register_operand" ""))])] - "TARGET_ARM && XVECLEN (operands[0], 0) == 3" - "stm%?ia\\t%1, {%2, %3, %4}" + "TARGET_32BIT && XVECLEN (operands[0], 0) == 3" + "stm%(ia%)\\t%1, {%2, %3, %4}" [(set_attr "predicable" "yes") (set_attr "type" "store3")] ) @@ -5432,8 +6282,8 @@ (match_operand:SI 2 "arm_hard_register_operand" "")) (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) (match_operand:SI 3 "arm_hard_register_operand" ""))])] - "TARGET_ARM && XVECLEN (operands[0], 0) == 2" - "stm%?ia\\t%1, {%2, %3}" + "TARGET_32BIT && XVECLEN (operands[0], 0) == 2" + "stm%(ia%)\\t%1, {%2, %3}" [(set_attr "predicable" "yes") (set_attr "type" "store2")] ) @@ -5442,26 +6292,26 @@ ;; 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" "") (match_operand:SI 3 "const_int_operand" "")] "TARGET_EITHER" " - if (TARGET_ARM) + if (TARGET_32BIT) { - if (arm_gen_movstrqi (operands)) + if (arm_gen_movmemqi (operands)) DONE; FAIL; } - else /* TARGET_THUMB */ + else /* TARGET_THUMB1 */ { if ( INTVAL (operands[3]) != 4 || INTVAL (operands[2]) > 48) FAIL; - thumb_expand_movstrqi (operands); + thumb_expand_movmemqi (operands); DONE; } " @@ -5483,7 +6333,7 @@ (clobber (match_scratch:SI 4 "=&l")) (clobber (match_scratch:SI 5 "=&l")) (clobber (match_scratch:SI 6 "=&l"))] - "TARGET_THUMB" + "TARGET_THUMB1" "* return thumb_output_move_mem_multiple (3, operands);" [(set_attr "length" "4") ; This isn't entirely accurate... It loads as well, but in terms of @@ -5502,7 +6352,7 @@ (plus:SI (match_dup 3) (const_int 8))) (clobber (match_scratch:SI 4 "=&l")) (clobber (match_scratch:SI 5 "=&l"))] - "TARGET_THUMB" + "TARGET_THUMB1" "* return thumb_output_move_mem_multiple (2, operands);" [(set_attr "length" "4") ; This isn't entirely accurate... It loads as well, but in terms of @@ -5513,7 +6363,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 @@ -5529,24 +6379,616 @@ ;; 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" +(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_THUMB1" + " + if (thumb1_cmpneg_operand (operands[2], SImode)) + { + emit_jump_insn (gen_cbranchsi4_scratch (NULL, operands[1], operands[2], + operands[3], operands[0])); + DONE; + } + if (!thumb1_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 "thumb1_cmp_operand" "lI*h,*r")]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "TARGET_THUMB1" + "* + 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))))] +) + +(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 "thumb1_cmpneg_operand" "L,J")]) + (label_ref (match_operand 3 "" "")) + (pc))) + (clobber (match_scratch:SI 0 "=l,l"))] + "TARGET_THUMB1" + "* + 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_THUMB1" + "*{ + 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 "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_THUMB1" + "* + output_asm_insn (\"cmn\\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))))] +) + +(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_THUMB1" + "* + { + 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 "*tlobits_cbranch" + [(set (pc) + (if_then_else + (match_operator 0 "equality_operator" + [(zero_extract:SI (match_operand:SI 1 "s_register_operand" "l") + (match_operand:SI 2 "const_int_operand" "i") + (const_int 0)) + (const_int 0)]) + (label_ref (match_operand 3 "" "")) + (pc))) + (clobber (match_scratch:SI 4 "=l"))] + "TARGET_THUMB1" + "* + { + rtx op[3]; + op[0] = operands[4]; + op[1] = operands[1]; + op[2] = GEN_INT (32 - 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_THUMB1" + "* + { + 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_THUMB1" + "* + { + 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_THUMB1" + "* + { + 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_THUMB1" + "* + { + 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_THUMB1" + "* + { + 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_THUMB1" + "* + { + 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 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)))] - "TARGET_THUMB" + (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_THUMB1" "* - output_asm_insn (\"cmp\\t%1, %2\", operands); + { + output_asm_insn (\"bic\\t%0, %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%=:\"; + 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") @@ -5563,18 +7005,426 @@ (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_THUMB1" + "* + { + 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); + } -(define_insn "*negated_cbranchsi4" + 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_THUMB1" + "* + { + 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_THUMB1 + && (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_THUMB1 + && (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 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 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_THUMB1 + && (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" + "TARGET_THUMB1 + && (GET_CODE (operands[0]) == EQ + || GET_CODE (operands[0]) == NE + || GET_CODE (operands[0]) == GE + || GET_CODE (operands[0]) == LT)" "* - output_asm_insn (\"cmn\\t%1, %2\", operands); + output_asm_insn (\"cmp\\t%1, %2\", operands); switch (get_attr_length (insn)) { case 4: return \"b%d0\\t%l3\"; @@ -5599,13 +7449,12 @@ (const_int 8))))] ) - ;; Comparison and test insns (define_expand "cmpsi" [(match_operand:SI 0 "s_register_operand" "") (match_operand:SI 1 "arm_add_operand" "")] - "TARGET_ARM" + "TARGET_32BIT" "{ arm_compare_op0 = operands[0]; arm_compare_op1 = operands[1]; @@ -5615,8 +7464,8 @@ (define_expand "cmpsf" [(match_operand:SF 0 "s_register_operand" "") - (match_operand:SF 1 "fpu_rhs_operand" "")] - "TARGET_ARM && TARGET_HARD_FLOAT" + (match_operand:SF 1 "arm_float_compare_operand" "")] + "TARGET_32BIT && TARGET_HARD_FLOAT" " arm_compare_op0 = operands[0]; arm_compare_op1 = operands[1]; @@ -5626,19 +7475,8 @@ (define_expand "cmpdf" [(match_operand:DF 0 "s_register_operand" "") - (match_operand:DF 1 "fpu_rhs_operand" "")] - "TARGET_ARM && TARGET_HARD_FLOAT" - " - arm_compare_op0 = operands[0]; - arm_compare_op1 = operands[1]; - DONE; - " -) - -(define_expand "cmpxf" - [(match_operand:XF 0 "s_register_operand" "") - (match_operand:XF 1 "fpu_rhs_operand" "")] - "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + (match_operand:DF 1 "arm_float_compare_operand" "")] + "TARGET_32BIT && TARGET_HARD_FLOAT" " arm_compare_op0 = operands[0]; arm_compare_op1 = operands[1]; @@ -5650,14 +7488,14 @@ [(set (reg:CC CC_REGNUM) (compare:CC (match_operand:SI 0 "s_register_operand" "r,r") (match_operand:SI 1 "arm_add_operand" "rI,L")))] - "TARGET_ARM" + "TARGET_32BIT" "@ cmp%?\\t%0, %1 cmn%?\\t%0, #%n1" [(set_attr "conds" "set")] ) -(define_insn "*cmpsi_shiftsi" +(define_insn "*arm_cmpsi_shiftsi" [(set (reg:CC CC_REGNUM) (compare:CC (match_operand:SI 0 "s_register_operand" "r") (match_operator:SI 3 "shift_operator" @@ -5667,10 +7505,12 @@ "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" +(define_insn "*arm_cmpsi_shiftsi_swp" [(set (reg:CC_SWP CC_REGNUM) (compare:CC_SWP (match_operator:SI 3 "shift_operator" [(match_operand:SI 1 "s_register_operand" "r") @@ -5680,140 +7520,67 @@ "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 "*arm_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" - [(set_attr "conds" "set") - (set_attr "type" "f_2_r")] -) - -(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" + "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 "*cmpesfdf_df" +;; Cirrus SF compare instruction +(define_insn "*cirrus_cmpsf" [(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")] + (compare:CCFP (match_operand:SF 0 "cirrus_fp_register" "v") + (match_operand:SF 1 "cirrus_fp_register" "v")))] + "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK" + "cfcmps%?\\tr15, %V0, %V1" + [(set_attr "type" "mav_farith") + (set_attr "cirrus" "compare")] ) -(define_insn "*cmpxf_insn" +;; Cirrus DF compare instruction +(define_insn "*cirrus_cmpdf" [(set (reg:CCFP CC_REGNUM) - (compare:CCFP (match_operand:XF 0 "s_register_operand" "f,f") - (match_operand:XF 1 "fpu_add_operand" "fG,H")))] - "TARGET_ARM && ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" - "@ - cmf%?\\t%0, %1 - cnf%?\\t%0, #%N1" - [(set_attr "conds" "set") - (set_attr "type" "f_2_r")] -) - -(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")] -) - -(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")] -) + (compare:CCFP (match_operand:DF 0 "cirrus_fp_register" "v") + (match_operand:DF 1 "cirrus_fp_register" "v")))] + "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK" + "cfcmpd%?\\tr15, %V0, %V1" + [(set_attr "type" "mav_farith") + (set_attr "cirrus" "compare")] +) + +;; Cirrus DI compare instruction +(define_expand "cmpdi" + [(match_operand:DI 0 "cirrus_fp_register" "") + (match_operand:DI 1 "cirrus_fp_register" "")] + "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK" + "{ + arm_compare_op0 = operands[0]; + arm_compare_op1 = operands[1]; + DONE; + }") -(define_insn "*cmpxf_trap" - [(set (reg:CCFPE CC_REGNUM) - (compare:CCFPE (match_operand:XF 0 "s_register_operand" "f,f") - (match_operand:XF 1 "fpu_add_operand" "fG,H")))] - "TARGET_ARM && ENABLE_XF_PATTERNS && 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 "*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 @@ -5824,7 +7591,7 @@ (define_insn "*deleted_compare" [(set (match_operand 0 "cc_register" "") (match_dup 0))] - "TARGET_ARM" + "TARGET_32BIT" "\\t%@ deleted compare" [(set_attr "conds" "set") (set_attr "length" "0")] @@ -5838,7 +7605,7 @@ (if_then_else (eq (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM" + "TARGET_32BIT" "operands[1] = arm_gen_compare_reg (EQ, arm_compare_op0, arm_compare_op1);" ) @@ -5847,7 +7614,7 @@ (if_then_else (ne (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM" + "TARGET_32BIT" "operands[1] = arm_gen_compare_reg (NE, arm_compare_op0, arm_compare_op1);" ) @@ -5856,7 +7623,7 @@ (if_then_else (gt (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM" + "TARGET_32BIT" "operands[1] = arm_gen_compare_reg (GT, arm_compare_op0, arm_compare_op1);" ) @@ -5865,7 +7632,7 @@ (if_then_else (le (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM" + "TARGET_32BIT" "operands[1] = arm_gen_compare_reg (LE, arm_compare_op0, arm_compare_op1);" ) @@ -5874,7 +7641,7 @@ (if_then_else (ge (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM" + "TARGET_32BIT" "operands[1] = arm_gen_compare_reg (GE, arm_compare_op0, arm_compare_op1);" ) @@ -5883,7 +7650,7 @@ (if_then_else (lt (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM" + "TARGET_32BIT" "operands[1] = arm_gen_compare_reg (LT, arm_compare_op0, arm_compare_op1);" ) @@ -5892,7 +7659,7 @@ (if_then_else (gtu (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM" + "TARGET_32BIT" "operands[1] = arm_gen_compare_reg (GTU, arm_compare_op0, arm_compare_op1);" ) @@ -5901,7 +7668,7 @@ (if_then_else (leu (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM" + "TARGET_32BIT" "operands[1] = arm_gen_compare_reg (LEU, arm_compare_op0, arm_compare_op1);" ) @@ -5910,7 +7677,7 @@ (if_then_else (geu (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM" + "TARGET_32BIT" "operands[1] = arm_gen_compare_reg (GEU, arm_compare_op0, arm_compare_op1);" ) @@ -5919,7 +7686,7 @@ (if_then_else (ltu (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM" + "TARGET_32BIT" "operands[1] = arm_gen_compare_reg (LTU, arm_compare_op0, arm_compare_op1);" ) @@ -5928,7 +7695,7 @@ (if_then_else (unordered (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_32BIT && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "operands[1] = arm_gen_compare_reg (UNORDERED, arm_compare_op0, arm_compare_op1);" ) @@ -5938,7 +7705,7 @@ (if_then_else (ordered (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_32BIT && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "operands[1] = arm_gen_compare_reg (ORDERED, arm_compare_op0, arm_compare_op1);" ) @@ -5948,7 +7715,7 @@ (if_then_else (ungt (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_32BIT && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "operands[1] = arm_gen_compare_reg (UNGT, arm_compare_op0, arm_compare_op1);" ) @@ -5957,7 +7724,7 @@ (if_then_else (unlt (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_32BIT && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "operands[1] = arm_gen_compare_reg (UNLT, arm_compare_op0, arm_compare_op1);" ) @@ -5966,7 +7733,7 @@ (if_then_else (unge (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_32BIT && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "operands[1] = arm_gen_compare_reg (UNGE, arm_compare_op0, arm_compare_op1);" ) @@ -5975,7 +7742,7 @@ (if_then_else (unle (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_32BIT && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "operands[1] = arm_gen_compare_reg (UNLE, arm_compare_op0, arm_compare_op1);" ) @@ -5986,7 +7753,7 @@ (if_then_else (uneq (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_32BIT && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "operands[1] = arm_gen_compare_reg (UNEQ, arm_compare_op0, arm_compare_op1);" ) @@ -5995,7 +7762,7 @@ (if_then_else (ltgt (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_32BIT && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "operands[1] = arm_gen_compare_reg (LTGT, arm_compare_op0, arm_compare_op1);" ) @@ -6009,12 +7776,11 @@ (if_then_else (uneq (match_operand 1 "cc_register" "") (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_32BIT && 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\"; + return \"bvs\\t%l0\;beq\\t%l0\"; " [(set_attr "conds" "jump_clob") (set_attr "length" "8")] @@ -6026,12 +7792,11 @@ (if_then_else (ltgt (match_operand 1 "cc_register" "") (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM && TARGET_HARD_FLOAT" + "TARGET_32BIT && 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\"; + return \"bmi\\t%l0\;bgt\\t%l0\"; " [(set_attr "conds" "jump_clob") (set_attr "length" "8")] @@ -6043,7 +7808,7 @@ [(match_operand 2 "cc_register" "") (const_int 0)]) (label_ref (match_operand 0 "" "")) (pc)))] - "TARGET_ARM" + "TARGET_32BIT" "* if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2) { @@ -6052,7 +7817,8 @@ } return \"b%d1\\t%l0\"; " - [(set_attr "conds" "use")] + [(set_attr "conds" "use") + (set_attr "type" "branch")] ) ; Special pattern to match reversed UNEQ. @@ -6061,12 +7827,11 @@ (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\"; + return \"bmi\\t%l0\;bgt\\t%l0\"; " [(set_attr "conds" "jump_clob") (set_attr "length" "8")] @@ -6078,12 +7843,11 @@ (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\"; + return \"bvs\\t%l0\;beq\\t%l0\"; " [(set_attr "conds" "jump_clob") (set_attr "length" "8")] @@ -6095,7 +7859,7 @@ [(match_operand 2 "cc_register" "") (const_int 0)]) (pc) (label_ref (match_operand 0 "" ""))))] - "TARGET_ARM" + "TARGET_32BIT" "* if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2) { @@ -6104,7 +7868,8 @@ } return \"b%D1\\t%l0\"; " - [(set_attr "conds" "use")] + [(set_attr "conds" "use") + (set_attr "type" "branch")] ) @@ -6112,119 +7877,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" + "TARGET_32BIT" "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" + "TARGET_32BIT" "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" + "TARGET_32BIT" "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" + "TARGET_32BIT" "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" + "TARGET_32BIT" "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" + "TARGET_32BIT" "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" + "TARGET_32BIT" "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" + "TARGET_32BIT" "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" + "TARGET_32BIT" "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" + "TARGET_32BIT" "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_32BIT && 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_32BIT && 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_32BIT && 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_32BIT && 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_32BIT && 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_32BIT && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" "operands[1] = arm_gen_compare_reg (UNLE, arm_compare_op0, arm_compare_op1);" ) @@ -6233,17 +7998,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_32BIT && 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_32BIT && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" +; "gcc_unreachable ();" ; ) (define_insn "*mov_scc" @@ -6276,6 +8041,198 @@ (set_attr "length" "8")] ) +(define_expand "cstoresi4" + [(set (match_operand:SI 0 "s_register_operand" "") + (match_operator:SI 1 "arm_comparison_operator" + [(match_operand:SI 2 "s_register_operand" "") + (match_operand:SI 3 "reg_or_int_operand" "")]))] + "TARGET_THUMB1" + "{ + rtx op3, scratch, scratch2; + + if (operands[3] == const0_rtx) + { + switch (GET_CODE (operands[1])) + { + case EQ: + emit_insn (gen_cstoresi_eq0_thumb1 (operands[0], operands[2])); + break; + + case NE: + emit_insn (gen_cstoresi_ne0_thumb1 (operands[0], operands[2])); + break; + + case LE: + scratch = expand_binop (SImode, add_optab, operands[2], constm1_rtx, + NULL_RTX, 0, OPTAB_WIDEN); + scratch = expand_binop (SImode, ior_optab, operands[2], scratch, + NULL_RTX, 0, OPTAB_WIDEN); + expand_binop (SImode, lshr_optab, scratch, GEN_INT (31), + operands[0], 1, OPTAB_WIDEN); + break; + + case GE: + scratch = expand_unop (SImode, one_cmpl_optab, operands[2], + NULL_RTX, 1); + expand_binop (SImode, lshr_optab, scratch, GEN_INT (31), + NULL_RTX, 1, OPTAB_WIDEN); + break; + + case GT: + scratch = expand_binop (SImode, ashr_optab, operands[2], + GEN_INT (31), NULL_RTX, 0, OPTAB_WIDEN); + scratch = expand_binop (SImode, sub_optab, scratch, operands[2], + NULL_RTX, 0, OPTAB_WIDEN); + expand_binop (SImode, lshr_optab, scratch, GEN_INT (31), operands[0], + 0, OPTAB_WIDEN); + break; + + /* LT is handled by generic code. No need for unsigned with 0. */ + default: + FAIL; + } + DONE; + } + + switch (GET_CODE (operands[1])) + { + case EQ: + scratch = expand_binop (SImode, sub_optab, operands[2], operands[3], + NULL_RTX, 0, OPTAB_WIDEN); + emit_insn (gen_cstoresi_eq0_thumb1 (operands[0], scratch)); + break; + + case NE: + scratch = expand_binop (SImode, sub_optab, operands[2], operands[3], + NULL_RTX, 0, OPTAB_WIDEN); + emit_insn (gen_cstoresi_ne0_thumb1 (operands[0], scratch)); + break; + + case LE: + op3 = force_reg (SImode, operands[3]); + + scratch = expand_binop (SImode, lshr_optab, operands[2], GEN_INT (31), + NULL_RTX, 1, OPTAB_WIDEN); + scratch2 = expand_binop (SImode, ashr_optab, op3, GEN_INT (31), + NULL_RTX, 0, OPTAB_WIDEN); + emit_insn (gen_thumb1_addsi3_addgeu (operands[0], scratch, scratch2, + op3, operands[2])); + break; + + case GE: + op3 = operands[3]; + if (!thumb1_cmp_operand (op3, SImode)) + op3 = force_reg (SImode, op3); + scratch = expand_binop (SImode, ashr_optab, operands[2], GEN_INT (31), + NULL_RTX, 0, OPTAB_WIDEN); + scratch2 = expand_binop (SImode, lshr_optab, op3, GEN_INT (31), + NULL_RTX, 1, OPTAB_WIDEN); + emit_insn (gen_thumb1_addsi3_addgeu (operands[0], scratch, scratch2, + operands[2], op3)); + break; + + case LEU: + op3 = force_reg (SImode, operands[3]); + scratch = force_reg (SImode, const0_rtx); + emit_insn (gen_thumb1_addsi3_addgeu (operands[0], scratch, scratch, + op3, operands[2])); + break; + + case GEU: + op3 = operands[3]; + if (!thumb1_cmp_operand (op3, SImode)) + op3 = force_reg (SImode, op3); + scratch = force_reg (SImode, const0_rtx); + emit_insn (gen_thumb1_addsi3_addgeu (operands[0], scratch, scratch, + operands[2], op3)); + break; + + case LTU: + op3 = operands[3]; + if (!thumb1_cmp_operand (op3, SImode)) + op3 = force_reg (SImode, op3); + scratch = gen_reg_rtx (SImode); + emit_insn (gen_cstoresi_nltu_thumb1 (scratch, operands[2], op3)); + emit_insn (gen_negsi2 (operands[0], scratch)); + break; + + case GTU: + op3 = force_reg (SImode, operands[3]); + scratch = gen_reg_rtx (SImode); + emit_insn (gen_cstoresi_nltu_thumb1 (scratch, op3, operands[2])); + emit_insn (gen_negsi2 (operands[0], scratch)); + break; + + /* No good sequences for GT, LT. */ + default: + FAIL; + } + DONE; +}") + +(define_expand "cstoresi_eq0_thumb1" + [(parallel + [(set (match_operand:SI 0 "s_register_operand" "") + (eq:SI (match_operand:SI 1 "s_register_operand" "") + (const_int 0))) + (clobber (match_dup:SI 2))])] + "TARGET_THUMB1" + "operands[2] = gen_reg_rtx (SImode);" +) + +(define_expand "cstoresi_ne0_thumb1" + [(parallel + [(set (match_operand:SI 0 "s_register_operand" "") + (ne:SI (match_operand:SI 1 "s_register_operand" "") + (const_int 0))) + (clobber (match_dup:SI 2))])] + "TARGET_THUMB1" + "operands[2] = gen_reg_rtx (SImode);" +) + +(define_insn "*cstoresi_eq0_thumb1_insn" + [(set (match_operand:SI 0 "s_register_operand" "=&l,l") + (eq:SI (match_operand:SI 1 "s_register_operand" "l,0") + (const_int 0))) + (clobber (match_operand:SI 2 "s_register_operand" "=X,l"))] + "TARGET_THUMB1" + "@ + neg\\t%0, %1\;adc\\t%0, %0, %1 + neg\\t%2, %1\;adc\\t%0, %1, %2" + [(set_attr "length" "4")] +) + +(define_insn "*cstoresi_ne0_thumb1_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (ne:SI (match_operand:SI 1 "s_register_operand" "0") + (const_int 0))) + (clobber (match_operand:SI 2 "s_register_operand" "=l"))] + "TARGET_THUMB1" + "sub\\t%2, %1, #1\;sbc\\t%0, %1, %2" + [(set_attr "length" "4")] +) + +(define_insn "cstoresi_nltu_thumb1" + [(set (match_operand:SI 0 "s_register_operand" "=l,l") + (neg:SI (ltu:SI (match_operand:SI 1 "s_register_operand" "l,*h") + (match_operand:SI 2 "thumb1_cmp_operand" "lI*h,*r"))))] + "TARGET_THUMB1" + "cmp\\t%1, %2\;sbc\\t%0, %0, %0" + [(set_attr "length" "4")] +) + +;; Used as part of the expansion of thumb les sequence. +(define_insn "thumb1_addsi3_addgeu" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (plus:SI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "s_register_operand" "l")) + (geu:SI (match_operand:SI 3 "s_register_operand" "l") + (match_operand:SI 4 "thumb1_cmp_operand" "lI"))))] + "TARGET_THUMB1" + "cmp\\t%3, %4\;adc\\t%0, %1, %2" + [(set_attr "length" "4")] +) + ;; Conditional move insns @@ -6284,13 +8241,17 @@ (if_then_else:SI (match_operand 1 "arm_comparison_operator" "") (match_operand:SI 2 "arm_not_operand" "") (match_operand:SI 3 "arm_not_operand" "")))] - "TARGET_ARM" + "TARGET_32BIT" " { enum rtx_code code = GET_CODE (operands[1]); - rtx ccreg = arm_gen_compare_reg (code, arm_compare_op0, arm_compare_op1); + rtx ccreg; + + if (code == UNEQ || code == LTGT) + FAIL; - operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx); + ccreg = arm_gen_compare_reg (code, arm_compare_op0, arm_compare_op1); + operands[1] = gen_rtx_fmt_ee (code, VOIDmode, ccreg, const0_rtx); }" ) @@ -6299,20 +8260,23 @@ (if_then_else:SF (match_operand 1 "arm_comparison_operator" "") (match_operand:SF 2 "s_register_operand" "") (match_operand:SF 3 "nonmemory_operand" "")))] - "TARGET_ARM" + "TARGET_32BIT && TARGET_HARD_FLOAT" " { enum rtx_code code = GET_CODE (operands[1]); rtx ccreg; + if (code == UNEQ || code == LTGT) + FAIL; + /* 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); }" ) @@ -6320,14 +8284,18 @@ [(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_32BIT && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)" " { enum rtx_code code = GET_CODE (operands[1]); - rtx ccreg = arm_gen_compare_reg (code, arm_compare_op0, arm_compare_op1); + rtx ccreg; + + if (code == UNEQ || code == LTGT) + FAIL; - operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx); + ccreg = arm_gen_compare_reg (code, arm_compare_op0, arm_compare_op1); + operands[1] = gen_rtx_fmt_ee (code, VOIDmode, ccreg, const0_rtx); }" ) @@ -6352,61 +8320,17 @@ (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" [(match_operand 4 "cc_register" "") (const_int 0)]) (match_operand:SF 1 "s_register_operand" "0,r") (match_operand:SF 2 "s_register_operand" "r,0")))] - "TARGET_ARM && TARGET_SOFT_FLOAT" - "@ - mov%D3\\t%0, %2 - mov%d3\\t%0, %1" - [(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" + "TARGET_ARM && TARGET_SOFT_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")] + mov%D3\\t%0, %2 + mov%d3\\t%0, %1" + [(set_attr "conds" "use")] ) @@ -6422,7 +8346,7 @@ (define_insn "*arm_jump" [(set (pc) (label_ref (match_operand 0 "" "")))] - "TARGET_ARM" + "TARGET_32BIT" "* { if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2) @@ -6439,7 +8363,7 @@ (define_insn "*thumb_jump" [(set (pc) (label_ref (match_operand 0 "" "")))] - "TARGET_THUMB" + "TARGET_THUMB1" "* if (get_attr_length (insn) == 2) return \"b\\t%l0\"; @@ -6452,8 +8376,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)))] ) @@ -6466,36 +8390,49 @@ "TARGET_EITHER" " { - rtx callee; + rtx callee, pat; /* In an untyped call, we can get NULL for operand 2. */ if (operands[2] == NULL_RTX) operands[2] = const0_rtx; - /* This is to decide if we should generate indirect calls by loading the - 32 bit address of the callee into a register before performing the - branch and link. operand[2] encodes the long_call/short_call - attribute of the function being called. This attribute is set whenever - __attribute__((long_call/short_call)) or #pragma long_call/no_long_call - is used, and the short_call attribute can also be set if function is - declared as static or if it has already been defined in the current - compilation unit. See arm.c and arm.h for info about this. The third - parameter to arm_is_longcall_p is used to tell it which pattern - invoked it. */ - callee = XEXP (operands[0], 0); - - if (GET_CODE (callee) != REG - && arm_is_longcall_p (operands[0], INTVAL (operands[2]), 0)) + /* Decide if we should generate indirect calls by loading the + 32-bit address of the callee into a register before performing the + branch and link. */ + callee = XEXP (operands[0], 0); + if (GET_CODE (callee) == SYMBOL_REF + ? arm_is_long_call_p (SYMBOL_REF_DECL (callee)) + : !REG_P (callee)) XEXP (operands[0], 0) = force_reg (Pmode, callee); + + pat = gen_call_internal (operands[0], operands[1], operands[2]); + arm_emit_call_insn (pat, XEXP (operands[0], 0)); + DONE; }" ) -(define_insn "*call_reg" +(define_expand "call_internal" + [(parallel [(call (match_operand 0 "memory_operand" "") + (match_operand 1 "general_operand" "")) + (use (match_operand 2 "" "")) + (clobber (reg:SI LR_REGNUM))])]) + +(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); " @@ -6505,7 +8442,7 @@ ) (define_insn "*call_mem" - [(call (mem:SI (match_operand:SI 0 "memory_operand" "m")) + [(call (mem:SI (match_operand:SI 0 "call_memory_operand" "m")) (match_operand 1 "" "")) (use (match_operand 2 "" "")) (clobber (reg:SI LR_REGNUM))] @@ -6517,35 +8454,33 @@ (set_attr "type" "call")] ) -(define_insn "*call_indirect" +(define_insn "*call_reg_thumb1_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_THUMB1 && 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_thumb1" + [(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_THUMB1 && !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")] ) @@ -6559,26 +8494,53 @@ "TARGET_EITHER" " { - rtx callee = XEXP (operands[1], 0); + rtx pat, callee; /* In an untyped call, we can get NULL for operand 2. */ if (operands[3] == 0) operands[3] = const0_rtx; - /* See the comment in define_expand \"call\". */ - if (GET_CODE (callee) != REG - && arm_is_longcall_p (operands[1], INTVAL (operands[3]), 0)) + /* Decide if we should generate indirect calls by loading the + 32-bit address of the callee into a register before performing the + branch and link. */ + callee = XEXP (operands[1], 0); + if (GET_CODE (callee) == SYMBOL_REF + ? arm_is_long_call_p (SYMBOL_REF_DECL (callee)) + : !REG_P (callee)) XEXP (operands[1], 0) = force_reg (Pmode, callee); + + pat = gen_call_value_internal (operands[0], operands[1], + operands[2], operands[3]); + arm_emit_call_insn (pat, XEXP (operands[1], 0)); + DONE; }" ) -(define_insn "*call_value_reg" - [(set (match_operand 0 "" "=r,f") - (call (mem:SI (match_operand:SI 1 "s_register_operand" "r,r")) +(define_expand "call_value_internal" + [(parallel [(set (match_operand 0 "" "") + (call (match_operand 1 "memory_operand" "") + (match_operand 2 "general_operand" ""))) + (use (match_operand 3 "" "")) + (clobber (reg:SI LR_REGNUM))])]) + +(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]); " @@ -6587,8 +8549,8 @@ ) (define_insn "*call_value_mem" - [(set (match_operand 0 "" "=r,f") - (call (mem:SI (match_operand:SI 1 "memory_operand" "m,m")) + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:SI 1 "call_memory_operand" "m")) (match_operand 2 "" ""))) (use (match_operand 3 "" "")) (clobber (reg:SI LR_REGNUM))] @@ -6600,17 +8562,50 @@ (set_attr "type" "call")] ) +(define_insn "*call_value_reg_thumb1_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_THUMB1 && arm_arch5" + "blx\\t%1" + [(set_attr "length" "2") + (set_attr "type" "call")] +) + +(define_insn "*call_value_reg_thumb1" + [(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_THUMB1 && !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))] "TARGET_ARM && (GET_CODE (operands[0]) == SYMBOL_REF) - && !arm_is_longcall_p (operands[0], INTVAL (operands[2]), 1)" + && !arm_is_long_call_p (SYMBOL_REF_DECL (operands[0]))" "* { return NEED_PLT_RELOC ? \"bl%?\\t%a0(PLT)\" : \"bl%?\\t%a0\"; @@ -6619,14 +8614,14 @@ ) (define_insn "*call_value_symbol" - [(set (match_operand 0 "s_register_operand" "=r,f") - (call (mem:SI (match_operand:SI 1 "" "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))] "TARGET_ARM && (GET_CODE (operands[1]) == SYMBOL_REF) - && !arm_is_longcall_p (operands[1], INTVAL (operands[3]), 1)" + && !arm_is_long_call_p (SYMBOL_REF_DECL (operands[1]))" "* { return NEED_PLT_RELOC ? \"bl%?\\t%a1(PLT)\" : \"bl%?\\t%a1\"; @@ -6635,27 +8630,27 @@ ) (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))] "TARGET_THUMB && GET_CODE (operands[0]) == SYMBOL_REF - && !arm_is_longcall_p (operands[0], INTVAL (operands[2]), 1)" + && !arm_is_long_call_p (SYMBOL_REF_DECL (operands[0]))" "bl\\t%a0" [(set_attr "length" "4") (set_attr "type" "call")] ) (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))] "TARGET_THUMB && GET_CODE (operands[1]) == SYMBOL_REF - && !arm_is_longcall_p (operands[1], INTVAL (operands[3]), 1)" + && !arm_is_long_call_p (SYMBOL_REF_DECL (operands[1]))" "bl\\t%a1" [(set_attr "length" "4") (set_attr "type" "call")] @@ -6665,8 +8660,8 @@ (define_expand "sibcall" [(parallel [(call (match_operand 0 "memory_operand" "") (match_operand 1 "general_operand" "")) - (use (match_operand 2 "" "")) - (use (reg:SI LR_REGNUM))])] + (return) + (use (match_operand 2 "" ""))])] "TARGET_ARM" " { @@ -6676,11 +8671,11 @@ ) (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" ""))) - (use (match_operand 3 "" "")) - (use (reg:SI LR_REGNUM))])] + (return) + (use (match_operand 3 "" ""))])] "TARGET_ARM" " { @@ -6692,8 +8687,8 @@ (define_insn "*sibcall_insn" [(call (mem:SI (match_operand:SI 0 "" "X")) (match_operand 1 "" "")) - (use (match_operand 2 "" "")) - (use (reg:SI LR_REGNUM))] + (return) + (use (match_operand 2 "" ""))] "TARGET_ARM && GET_CODE (operands[0]) == SYMBOL_REF" "* return NEED_PLT_RELOC ? \"b%?\\t%a0(PLT)\" : \"b%?\\t%a0\"; @@ -6702,11 +8697,11 @@ ) (define_insn "*sibcall_value_insn" - [(set (match_operand 0 "s_register_operand" "=r,f") - (call (mem:SI (match_operand:SI 1 "" "X,X")) + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:SI 1 "" "X")) (match_operand 2 "" ""))) - (use (match_operand 3 "" "")) - (use (reg:SI LR_REGNUM))] + (return) + (use (match_operand 3 "" ""))] "TARGET_ARM && GET_CODE (operands[1]) == SYMBOL_REF" "* return NEED_PLT_RELOC ? \"b%?\\t%a1(PLT)\" : \"b%?\\t%a1\"; @@ -6725,9 +8720,10 @@ arm_ccfsm_state += 2; return \"\"; } - return output_return_instruction (NULL, TRUE, FALSE); + 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")] ) @@ -6748,7 +8744,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" @@ -6768,7 +8765,35 @@ 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 +;; in 26-bit or 32-bit mode, and return the appropriate return address +;; mask. + +(define_expand "return_addr_mask" + [(set (match_dup 1) + (compare:CC_NOOV (unspec [(const_int 0)] UNSPEC_CHECK_ARCH) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "") + (if_then_else:SI (eq (match_dup 1) (const_int 0)) + (const_int -1) + (const_int 67108860)))] ; 0x03fffffc + "TARGET_ARM" + " + operands[1] = gen_rtx_REG (CC_NOOVmode, CC_REGNUM); + ") + +(define_insn "*check_arch2" + [(set (match_operand:CC_NOOV 0 "cc_register" "") + (compare:CC_NOOV (unspec [(const_int 0)] UNSPEC_CHECK_ARCH) + (const_int 0)))] + "TARGET_ARM" + "teq\\t%|r0, %|r0\;teq\\t%|pc, %|pc" + [(set_attr "length" "8") + (set_attr "conds" "set")] ) ;; Call subroutine returning any type. @@ -6778,18 +8803,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); - emit_move_insn (SET_DEST (set), SET_SRC (set)); + 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_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 @@ -6802,6 +8868,54 @@ }" ) +(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_use (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. @@ -6819,7 +8933,7 @@ (match_operand:SI 2 "const_int_operand" "") ; total range (match_operand:SI 3 "" "") ; table label (match_operand:SI 4 "" "")] ; Out of range label - "TARGET_ARM" + "TARGET_32BIT" " { rtx reg; @@ -6835,15 +8949,28 @@ if (!const_ok_for_arm (INTVAL (operands[2]))) operands[2] = force_reg (SImode, operands[2]); - emit_jump_insn (gen_casesi_internal (operands[0], operands[2], operands[3], - operands[4])); + if (TARGET_ARM) + { + emit_jump_insn (gen_arm_casesi_internal (operands[0], operands[2], + operands[3], operands[4])); + } + else if (flag_pic) + { + emit_jump_insn (gen_thumb2_casesi_internal_pic (operands[0], + operands[2], operands[3], operands[4])); + } + else + { + emit_jump_insn (gen_thumb2_casesi_internal (operands[0], operands[2], + operands[3], operands[4])); + } DONE; }" ) ;; The USE in this pattern is needed to tell flow analysis that this is ;; a CASESI insn. It has no other purpose. -(define_insn "casesi_internal" +(define_insn "arm_casesi_internal" [(parallel [(set (pc) (if_then_else (leu (match_operand:SI 0 "s_register_operand" "r") @@ -6867,9 +8994,20 @@ [(set (pc) (match_operand:SI 0 "s_register_operand" ""))] "TARGET_EITHER" - "" + " + /* Thumb-2 doesn't have mov pc, reg. Explicitly set the low bit of the + address and use bx. */ + if (TARGET_THUMB2) + { + rtx tmp; + tmp = gen_reg_rtx (SImode); + emit_insn (gen_iorsi3 (tmp, operands[0], GEN_INT(1))); + operands[0] = tmp; + } + " ) +;; NB Never uses BX. (define_insn "*arm_indirect_jump" [(set (pc) (match_operand:SI 0 "s_register_operand" "r"))] @@ -6878,23 +9016,22 @@ [(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")] ) -(define_insn "*thumb_indirect_jump" +;; NB Never uses BX. +(define_insn "*thumb1_indirect_jump" [(set (pc) (match_operand:SI 0 "register_operand" "l*r"))] - "TARGET_THUMB" + "TARGET_THUMB1" "mov\\tpc, %0" [(set_attr "conds" "clob") (set_attr "length" "2")] @@ -6907,6 +9044,8 @@ [(const_int 0)] "TARGET_EITHER" "* + if (TARGET_UNIFIED_ASM) + return \"nop\"; if (TARGET_ARM) return \"mov%?\\t%|r0, %|r0\\t%@ nop\"; return \"mov\\tr8, r8\"; @@ -6931,9 +9070,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" @@ -6946,10 +9105,12 @@ (match_op_dup 1 [(match_op_dup 3 [(match_dup 4) (match_dup 5)]) (match_dup 2)]))] "TARGET_ARM" - "%i1%?s\\t%0, %2, %4%S3" + "%i1%.\\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" @@ -6962,10 +9123,12 @@ (const_int 0))) (clobber (match_scratch:SI 0 "=r"))] "TARGET_ARM" - "%i1%?s\\t%0, %2, %4%S3" + "%i1%.\\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" @@ -6978,7 +9141,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" @@ -6993,10 +9158,12 @@ (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) (match_dup 4)])))] "TARGET_ARM" - "sub%?s\\t%0, %1, %3%S2" + "sub%.\\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" @@ -7009,143 +9176,12 @@ (const_int 0))) (clobber (match_scratch:SI 0 "=r"))] "TARGET_ARM" - "sub%?s\\t%0, %1, %3%S2" - [(set_attr "conds" "set") - (set_attr "shift" "3") - ] -) - -;; These variants of the above insns can occur if the first operand is the -;; frame pointer and we eliminate that. This is a kludge, but there doesn't -;; seem to be a way around it. Most of the predicates have to be null -;; because the format can be generated part way through reload, so -;; if we don't match it as soon as it becomes available, reload doesn't know -;; how to reload pseudos that haven't got hard registers; the constraints will -;; sort everything out. - -(define_insn "*reload_mulsi3" - [(set (match_operand:SI 0 "" "=&r") - (plus:SI (plus:SI (match_operator:SI 5 "shift_operator" - [(match_operand:SI 3 "" "r") - (match_operand:SI 4 "" "rM")]) - (match_operand:SI 2 "" "r")) - (match_operand:SI 1 "const_int_operand" "n")))] - "TARGET_ARM && reload_in_progress" - "* - output_asm_insn (\"add%?\\t%0, %2, %3%S5\", operands); - operands[2] = operands[1]; - operands[1] = operands[0]; - return output_add_immediate (operands); - " - [ - ; we have no idea how long the add_immediate is, it could be up to 4. - (set_attr "length" "20")] -) - -(define_insn "*reload_mulsi_compare0" - [(set (reg:CC_NOOV CC_REGNUM) - (compare:CC_NOOV (plus:SI - (plus:SI - (match_operator:SI 5 "shift_operator" - [(match_operand:SI 3 "" "r") - (match_operand:SI 4 "" "rM")]) - (match_operand:SI 1 "" "r")) - (match_operand:SI 2 "const_int_operand" "n")) - (const_int 0))) - (set (match_operand:SI 0 "" "=&r") - (plus:SI (plus:SI (match_op_dup 5 [(match_dup 3) (match_dup 4)]) - (match_dup 1)) - (match_dup 2)))] - "TARGET_ARM && reload_in_progress && !arm_is_xscale" - "* - output_add_immediate (operands); - return \"add%?s\\t%0, %0, %3%S5\"; - " - [(set_attr "conds" "set") - (set_attr "shift" "3") - (set_attr "length" "20")] -) - -(define_insn "*reload_mulsi_compare0_scratch" - [(set (reg:CC_NOOV CC_REGNUM) - (compare:CC_NOOV (plus:SI - (plus:SI - (match_operator:SI 5 "shift_operator" - [(match_operand:SI 3 "" "r") - (match_operand:SI 4 "" "rM")]) - (match_operand:SI 1 "" "r")) - (match_operand:SI 2 "const_int_operand" "n")) - (const_int 0))) - (clobber (match_scratch:SI 0 "=&r"))] - "TARGET_ARM && reload_in_progress && !arm_is_xscale" - "* - output_add_immediate (operands); - return \"add%?s\\t%0, %0, %3%S5\"; - " + "sub%.\\t%0, %1, %3%S2" [(set_attr "conds" "set") (set_attr "shift" "3") - (set_attr "length" "20")] -) - -;; These are similar, but are needed when the mla pattern contains the -;; eliminated register as operand 3. - -(define_insn "*reload_muladdsi" - [(set (match_operand:SI 0 "" "=&r,&r") - (plus:SI (plus:SI (mult:SI (match_operand:SI 1 "" "%0,r") - (match_operand:SI 2 "" "r,r")) - (match_operand:SI 3 "" "r,r")) - (match_operand:SI 4 "const_int_operand" "n,n")))] - "TARGET_ARM && reload_in_progress" - "* - output_asm_insn (\"mla%?\\t%0, %2, %1, %3\", operands); - operands[2] = operands[4]; - operands[1] = operands[0]; - return output_add_immediate (operands); - " - [(set_attr "length" "20") - (set_attr "type" "mult")] -) - -(define_insn "*reload_muladdsi_compare0" - [(set (reg:CC_NOOV CC_REGNUM) - (compare:CC_NOOV (plus:SI (plus:SI (mult:SI - (match_operand:SI 3 "" "r") - (match_operand:SI 4 "" "r")) - (match_operand:SI 1 "" "r")) - (match_operand:SI 2 "const_int_operand" "n")) - (const_int 0))) - (set (match_operand:SI 0 "" "=&r") - (plus:SI (plus:SI (mult:SI (match_dup 3) (match_dup 4)) (match_dup 1)) - (match_dup 2)))] - "TARGET_ARM && reload_in_progress && !arm_is_xscale" - "* - output_add_immediate (operands); - output_asm_insn (\"mla%?s\\t%0, %3, %4, %0\", operands); - return \"\"; - " - [(set_attr "length" "20") - (set_attr "conds" "set") - (set_attr "type" "mult")] -) - -(define_insn "*reload_muladdsi_compare0_scratch" - [(set (reg:CC_NOOV CC_REGNUM) - (compare:CC_NOOV (plus:SI (plus:SI (mult:SI - (match_operand:SI 3 "" "r") - (match_operand:SI 4 "" "r")) - (match_operand:SI 1 "" "r")) - (match_operand:SI 2 "const_int_operand" "n")) - (const_int 0))) - (clobber (match_scratch:SI 0 "=&r"))] - "TARGET_ARM && reload_in_progress" - "* - output_add_immediate (operands); - return \"mla%?s\\t%0, %3, %4, %0\"; - " - [(set_attr "length" "20") - (set_attr "conds" "set") - (set_attr "type" "mult")] + (set (attr "type") (if_then_else (match_operand 4 "const_int_operand" "") + (const_string "alu_shift") + (const_string "alu_shift_reg")))] ) @@ -7182,11 +9218,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) { @@ -7276,6 +9318,7 @@ (set_attr "length" "8,12")] ) +;; ??? Is it worth using these conditional patterns in Thumb-2 mode? (define_insn "*cmp_ite0" [(set (match_operand 6 "dominant_cc_register" "") (compare @@ -7410,12 +9453,199 @@ 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)))] + "") +;; ??? The conditional patterns above need checking for Thumb-2 usefulness (define_insn "*negscc" [(set (match_operand:SI 0 "s_register_operand" "=r") @@ -7425,15 +9655,12 @@ (clobber (reg:CC CC_REGNUM))] "TARGET_ARM" "* - if (GET_CODE (operands[3]) == LT && operands[3] == const0_rtx) + if (GET_CODE (operands[3]) == LT && operands[2] == const0_rtx) return \"mov\\t%0, %1, asr #31\"; if (GET_CODE (operands[3]) == NE) return \"subs\\t%0, %1, %2\;mvnne\\t%0, #0\"; - if (GET_CODE (operands[3]) == GT) - return \"subs\\t%0, %1, %2\;mvnne\\t%0, %0, asr #31\"; - output_asm_insn (\"cmp\\t%1, %2\", operands); output_asm_insn (\"mov%D3\\t%0, #0\", operands); return \"mvn%d3\\t%0, #0\"; @@ -7469,7 +9696,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 @@ -7488,7 +9715,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]))) @@ -7505,6 +9732,8 @@ (set_attr "length" "8,8,12")] ) +;; ??? The patterns below need checking for Thumb-2 usefulness. + (define_insn "*ifcompare_plus_move" [(set (match_operand:SI 0 "s_register_operand" "=r,r") (if_then_else:SI (match_operator 6 "arm_comparison_operator" @@ -7625,7 +9854,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 @@ -7826,7 +10055,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" @@ -7862,7 +10094,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" @@ -7899,7 +10134,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" @@ -7961,652 +10201,185 @@ (match_operand:SI 3 "arm_rhs_operand" "rI")]) (not:SI (match_operand:SI 1 "s_register_operand" "r"))))] "TARGET_ARM" - "mvn%D5\\t%0, %1\;%I6%d5\\t%0, %2, %3" - [(set_attr "conds" "use") - (set_attr "length" "8")] -) - -(define_insn "*ifcompare_neg_move" - [(set (match_operand:SI 0 "s_register_operand" "=r,r") - (if_then_else:SI - (match_operator 5 "arm_comparison_operator" - [(match_operand:SI 3 "s_register_operand" "r,r") - (match_operand:SI 4 "arm_add_operand" "rIL,rIL")]) - (neg:SI (match_operand:SI 2 "s_register_operand" "r,r")) - (match_operand:SI 1 "arm_not_operand" "0,?rIK"))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ARM" - "#" - [(set_attr "conds" "clob") - (set_attr "length" "8,12")] -) - -(define_insn "*if_neg_move" - [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") - (if_then_else:SI - (match_operator 4 "arm_comparison_operator" - [(match_operand 3 "cc_register" "") (const_int 0)]) - (neg:SI (match_operand:SI 2 "s_register_operand" "r,r,r")) - (match_operand:SI 1 "arm_not_operand" "0,?rI,K")))] - "TARGET_ARM" - "@ - rsb%d4\\t%0, %2, #0 - mov%D4\\t%0, %1\;rsb%d4\\t%0, %2, #0 - mvn%D4\\t%0, #%B1\;rsb%d4\\t%0, %2, #0" - [(set_attr "conds" "use") - (set_attr "length" "4,8,8")] -) - -(define_insn "*ifcompare_move_neg" - [(set (match_operand:SI 0 "s_register_operand" "=r,r") - (if_then_else:SI - (match_operator 5 "arm_comparison_operator" - [(match_operand:SI 3 "s_register_operand" "r,r") - (match_operand:SI 4 "arm_add_operand" "rIL,rIL")]) - (match_operand:SI 1 "arm_not_operand" "0,?rIK") - (neg:SI (match_operand:SI 2 "s_register_operand" "r,r")))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ARM" - "#" - [(set_attr "conds" "clob") - (set_attr "length" "8,12")] -) - -(define_insn "*if_move_neg" - [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") - (if_then_else:SI - (match_operator 4 "arm_comparison_operator" - [(match_operand 3 "cc_register" "") (const_int 0)]) - (match_operand:SI 1 "arm_not_operand" "0,?rI,K") - (neg:SI (match_operand:SI 2 "s_register_operand" "r,r,r"))))] - "TARGET_ARM" - "@ - rsb%D4\\t%0, %2, #0 - mov%d4\\t%0, %1\;rsb%D4\\t%0, %2, #0 - mvn%d4\\t%0, #%B1\;rsb%D4\\t%0, %2, #0" - [(set_attr "conds" "use") - (set_attr "length" "4,8,8")] -) - -(define_insn "*arith_adjacentmem" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (match_operator:SI 1 "shiftable_operator" - [(match_operand:SI 2 "memory_operand" "m") - (match_operand:SI 3 "memory_operand" "m")])) - (clobber (match_scratch:SI 4 "=r"))] - "TARGET_ARM && adjacent_mem_locations (operands[2], operands[3])" - "* - { - rtx ldm[3]; - rtx arith[4]; - int val1 = 0, val2 = 0; - - if (REGNO (operands[0]) > REGNO (operands[4])) - { - ldm[1] = operands[4]; - ldm[2] = operands[0]; - } - else - { - 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) - val2 = INTVAL (XEXP (XEXP (operands[3], 0), 1)); - arith[0] = operands[0]; - arith[3] = operands[1]; - if (val1 < val2) - { - arith[1] = ldm[1]; - arith[2] = ldm[2]; - } - else - { - arith[1] = ldm[2]; - arith[2] = ldm[1]; - } - if (val1 && val2) - { - 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); - else - output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm); - } - else if (val1) - { - ldm[0] = XEXP (operands[3], 0); - if (val1 < val2) - output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm); - else - output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm); - } - else - { - ldm[0] = XEXP (operands[2], 0); - if (val1 < val2) - output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm); - else - output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm); - } - output_asm_insn (\"%I3%?\\t%0, %1, %2\", arith); - return \"\"; - }" - [(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")] + "mvn%D5\\t%0, %1\;%I6%d5\\t%0, %2, %3" + [(set_attr "conds" "use") + (set_attr "length" "8")] ) -(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 "*ifcompare_neg_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI + (match_operator 5 "arm_comparison_operator" + [(match_operand:SI 3 "s_register_operand" "r,r") + (match_operand:SI 4 "arm_add_operand" "rIL,rIL")]) + (neg:SI (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:SI 1 "arm_not_operand" "0,?rIK"))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_ARM" + "#" + [(set_attr "conds" "clob") + (set_attr "length" "8,12")] ) -(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 "*if_neg_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 4 "arm_comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (neg:SI (match_operand:SI 2 "s_register_operand" "r,r,r")) + (match_operand:SI 1 "arm_not_operand" "0,?rI,K")))] + "TARGET_ARM" + "@ + rsb%d4\\t%0, %2, #0 + mov%D4\\t%0, %1\;rsb%d4\\t%0, %2, #0 + mvn%D4\\t%0, #%B1\;rsb%d4\\t%0, %2, #0" + [(set_attr "conds" "use") + (set_attr "length" "4,8,8")] +) -(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 "*ifcompare_move_neg" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI + (match_operator 5 "arm_comparison_operator" + [(match_operand:SI 3 "s_register_operand" "r,r") + (match_operand:SI 4 "arm_add_operand" "rIL,rIL")]) + (match_operand:SI 1 "arm_not_operand" "0,?rIK") + (neg:SI (match_operand:SI 2 "s_register_operand" "r,r")))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_ARM" + "#" + [(set_attr "conds" "clob") + (set_attr "length" "8,12")] ) -(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")] +(define_insn "*if_move_neg" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 4 "arm_comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "arm_not_operand" "0,?rI,K") + (neg:SI (match_operand:SI 2 "s_register_operand" "r,r,r"))))] + "TARGET_ARM" + "@ + rsb%D4\\t%0, %2, #0 + mov%d4\\t%0, %1\;rsb%D4\\t%0, %2, #0 + mvn%d4\\t%0, #%B1\;rsb%D4\\t%0, %2, #0" + [(set_attr "conds" "use") + (set_attr "length" "4,8,8")] ) -; 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 behaviour so -; we cannot use it. +(define_insn "*arith_adjacentmem" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operator:SI 1 "shiftable_operator" + [(match_operand:SI 2 "memory_operand" "m") + (match_operand:SI 3 "memory_operand" "m")])) + (clobber (match_scratch:SI 4 "=r"))] + "TARGET_ARM && adjacent_mem_locations (operands[2], operands[3])" + "* + { + rtx ldm[3]; + rtx arith[4]; + rtx base_reg; + HOST_WIDE_INT val1 = 0, val2 = 0; -(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" -) + if (REGNO (operands[0]) > REGNO (operands[4])) + { + ldm[1] = operands[4]; + ldm[2] = operands[0]; + } + else + { + ldm[1] = operands[0]; + ldm[2] = operands[4]; + } -(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" -) + base_reg = XEXP (operands[2], 0); -(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" -) + if (!REG_P (base_reg)) + { + val1 = INTVAL (XEXP (base_reg, 1)); + base_reg = XEXP (base_reg, 0); + } -(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" -) + if (!REG_P (XEXP (operands[3], 0))) + val2 = INTVAL (XEXP (XEXP (operands[3], 0), 1)); -(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" -) + arith[0] = operands[0]; + arith[3] = operands[1]; -(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]!" -) + if (val1 < val2) + { + arith[1] = ldm[1]; + arith[2] = ldm[2]; + } + else + { + arith[1] = ldm[2]; + arith[2] = ldm[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]!" + ldm[0] = base_reg; + if (val1 !=0 && val2 != 0) + { + rtx ops[3]; + + 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 if (const_ok_for_arm (val1) || const_ok_for_arm (-val1)) + { + 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 + { + /* Offset is out of range for a single add, so use two ldr. */ + ops[0] = ldm[1]; + ops[1] = base_reg; + ops[2] = GEN_INT (val1); + output_asm_insn (\"ldr%?\\t%0, [%1, %2]\", ops); + ops[0] = ldm[2]; + ops[2] = GEN_INT (val2); + output_asm_insn (\"ldr%?\\t%0, [%1, %2]\", ops); + } + } + else if (val1 != 0) + { + if (val1 < val2) + output_asm_insn (\"ldm%(da%)\\t%0, {%1, %2}\", ldm); + else + output_asm_insn (\"ldm%(ia%)\\t%0, {%1, %2}\", ldm); + } + else + { + if (val1 < val2) + output_asm_insn (\"ldm%(ia%)\\t%0, {%1, %2}\", ldm); + else + output_asm_insn (\"ldm%(da%)\\t%0, {%1, %2}\", ldm); + } + output_asm_insn (\"%I3%?\\t%0, %1, %2\", arith); + return \"\"; + }" + [(set_attr "length" "12") + (set_attr "predicable" "yes") + (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_ARM" [(parallel [(set (reg:CC CC_REGNUM) (compare:CC (match_dup 1) (const_int 0))) (set (match_dup 0) (match_dup 1))])] "" @@ -8616,13 +10389,13 @@ ; reversed, check that the memory references aren't volatile. (define_peephole - [(set (match_operand:SI 0 "s_register_operand" "=r") + [(set (match_operand:SI 0 "s_register_operand" "=rk") (match_operand:SI 4 "memory_operand" "m")) - (set (match_operand:SI 1 "s_register_operand" "=r") + (set (match_operand:SI 1 "s_register_operand" "=rk") (match_operand:SI 5 "memory_operand" "m")) - (set (match_operand:SI 2 "s_register_operand" "=r") + (set (match_operand:SI 2 "s_register_operand" "=rk") (match_operand:SI 6 "memory_operand" "m")) - (set (match_operand:SI 3 "s_register_operand" "=r") + (set (match_operand:SI 3 "s_register_operand" "=rk") (match_operand:SI 7 "memory_operand" "m"))] "TARGET_ARM && load_multiple_sequence (operands, 4, NULL, NULL, NULL)" "* @@ -8631,11 +10404,11 @@ ) (define_peephole - [(set (match_operand:SI 0 "s_register_operand" "=r") + [(set (match_operand:SI 0 "s_register_operand" "=rk") (match_operand:SI 3 "memory_operand" "m")) - (set (match_operand:SI 1 "s_register_operand" "=r") + (set (match_operand:SI 1 "s_register_operand" "=rk") (match_operand:SI 4 "memory_operand" "m")) - (set (match_operand:SI 2 "s_register_operand" "=r") + (set (match_operand:SI 2 "s_register_operand" "=rk") (match_operand:SI 5 "memory_operand" "m"))] "TARGET_ARM && load_multiple_sequence (operands, 3, NULL, NULL, NULL)" "* @@ -8644,9 +10417,9 @@ ) (define_peephole - [(set (match_operand:SI 0 "s_register_operand" "=r") + [(set (match_operand:SI 0 "s_register_operand" "=rk") (match_operand:SI 2 "memory_operand" "m")) - (set (match_operand:SI 1 "s_register_operand" "=r") + (set (match_operand:SI 1 "s_register_operand" "=rk") (match_operand:SI 3 "memory_operand" "m"))] "TARGET_ARM && load_multiple_sequence (operands, 2, NULL, NULL, NULL)" "* @@ -8656,13 +10429,13 @@ (define_peephole [(set (match_operand:SI 4 "memory_operand" "=m") - (match_operand:SI 0 "s_register_operand" "r")) + (match_operand:SI 0 "s_register_operand" "rk")) (set (match_operand:SI 5 "memory_operand" "=m") - (match_operand:SI 1 "s_register_operand" "r")) + (match_operand:SI 1 "s_register_operand" "rk")) (set (match_operand:SI 6 "memory_operand" "=m") - (match_operand:SI 2 "s_register_operand" "r")) + (match_operand:SI 2 "s_register_operand" "rk")) (set (match_operand:SI 7 "memory_operand" "=m") - (match_operand:SI 3 "s_register_operand" "r"))] + (match_operand:SI 3 "s_register_operand" "rk"))] "TARGET_ARM && store_multiple_sequence (operands, 4, NULL, NULL, NULL)" "* return emit_stm_seq (operands, 4); @@ -8671,11 +10444,11 @@ (define_peephole [(set (match_operand:SI 3 "memory_operand" "=m") - (match_operand:SI 0 "s_register_operand" "r")) + (match_operand:SI 0 "s_register_operand" "rk")) (set (match_operand:SI 4 "memory_operand" "=m") - (match_operand:SI 1 "s_register_operand" "r")) + (match_operand:SI 1 "s_register_operand" "rk")) (set (match_operand:SI 5 "memory_operand" "=m") - (match_operand:SI 2 "s_register_operand" "r"))] + (match_operand:SI 2 "s_register_operand" "rk"))] "TARGET_ARM && store_multiple_sequence (operands, 3, NULL, NULL, NULL)" "* return emit_stm_seq (operands, 3); @@ -8684,9 +10457,9 @@ (define_peephole [(set (match_operand:SI 2 "memory_operand" "=m") - (match_operand:SI 0 "s_register_operand" "r")) + (match_operand:SI 0 "s_register_operand" "rk")) (set (match_operand:SI 3 "memory_operand" "=m") - (match_operand:SI 1 "s_register_operand" "r"))] + (match_operand:SI 1 "s_register_operand" "rk"))] "TARGET_ARM && store_multiple_sequence (operands, 2, NULL, NULL, NULL)" "* return emit_stm_seq (operands, 2); @@ -8728,24 +10501,27 @@ operands[1] = GEN_INT (((unsigned long) INTVAL (operands[1])) >> 24); " ) +;; ??? Check the patterns above for Thumb-2 usefulness (define_expand "prologue" [(clobber (const_int 0))] "TARGET_EITHER" - "if (TARGET_ARM) + "if (TARGET_32BIT) arm_expand_prologue (); else - thumb_expand_prologue (); + thumb1_expand_prologue (); DONE; " ) (define_expand "epilogue" - [(unspec_volatile [(return)] VUNSPEC_EPILOGUE)] + [(clobber (const_int 0))] "TARGET_EITHER" " - if (TARGET_THUMB) - thumb_expand_epilogue (); + if (crtl->calls_eh_return) + emit_insn (gen_prologue_use (gen_rtx_REG (Pmode, 2))); + if (TARGET_THUMB1) + thumb1_expand_epilogue (); else if (USE_RETURN_INSN (FALSE)) { emit_jump_insn (gen_return ()); @@ -8759,38 +10535,51 @@ " ) +;; Note - although unspec_volatile's USE all hard registers, +;; USEs are ignored after relaod has completed. Thus we need +;; to add an unspec of the link register to ensure that flow +;; does not think that it is unused by the sibcall branch that +;; will replace the standard function epilogue. (define_insn "sibcall_epilogue" - [(unspec_volatile [(const_int 0)] VUNSPEC_EPILOGUE)] - "TARGET_ARM" + [(parallel [(unspec:SI [(reg:SI LR_REGNUM)] UNSPEC_PROLOGUE_USE) + (unspec_volatile [(return)] VUNSPEC_EPILOGUE)])] + "TARGET_32BIT" "* - output_asm_insn (\"%@ Sibcall epilogue\", operands); - if (USE_RETURN_INSN (FALSE)) - return output_return_instruction (NULL, FALSE, FALSE); - return arm_output_epilogue (FALSE); + if (use_return_insn (FALSE, next_nonnote_insn (insn))) + return output_return_instruction (const_true_rtx, FALSE, FALSE); + return arm_output_epilogue (next_nonnote_insn (insn)); " ;; Length is absolute worst case [(set_attr "length" "44") - (set_attr "type" "block")] + (set_attr "type" "block") + ;; We don't clobber the conditions, but the potential length of this + ;; operation is sufficient to make conditionalizing the sequence + ;; unlikely to be profitable. + (set_attr "conds" "clob")] ) (define_insn "*epilogue_insns" [(unspec_volatile [(return)] VUNSPEC_EPILOGUE)] "TARGET_EITHER" "* - if (TARGET_ARM) - return arm_output_epilogue (TRUE); - else /* TARGET_THUMB */ + if (TARGET_32BIT) + return arm_output_epilogue (NULL); + else /* TARGET_THUMB1 */ return thumb_unexpanded_epilogue (); " ; Length is absolute worst case [(set_attr "length" "44") - (set_attr "type" "block")] + (set_attr "type" "block") + ;; We don't clobber the conditions, but the potential length of this + ;; operation is sufficient to make conditionalizing the sequence + ;; unlikely to be profitable. + (set_attr "conds" "clob")] ) (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" " { @@ -8815,6 +10604,9 @@ ;; some extent with the conditional data operations, so we have to split them ;; up again here. +;; ??? Need to audit these splitters for Thumb-2. Why isn't normal +;; conditional execution sufficient? + (define_split [(set (match_operand:SI 0 "s_register_operand" "") (if_then_else:SI (match_operator 1 "arm_comparison_operator" @@ -8916,7 +10708,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 @@ -8977,6 +10769,7 @@ [(set_attr "conds" "clob") (set_attr "length" "12")] ) +;; ??? The above patterns need auditing for Thumb-2 ;; Push multiple registers to the stack. Registers are in parallel (use ...) ;; expressions. For simplicity, the first register is also in the unspec @@ -8986,21 +10779,26 @@ [(set (match_operand:BLK 0 "memory_operand" "=m") (unspec:BLK [(match_operand:SI 1 "s_register_operand" "r")] UNSPEC_PUSH_MULT))])] - "TARGET_ARM" + "TARGET_32BIT" "* { int num_saves = XVECLEN (operands[2], 0); /* For the StrongARM at least it is faster to - use STR to store only a single register. */ - if (num_saves == 1) + use STR to store only a single register. + In Thumb mode always use push, and the assembler will pick + something appropriate. */ + if (num_saves == 1 && TARGET_ARM) output_asm_insn (\"str\\t%1, [%m0, #-4]!\", operands); else { int i; char pattern[100]; - strcpy (pattern, \"stmfd\\t%m0!, {%1\"); + if (TARGET_ARM) + strcpy (pattern, \"stmfd\\t%m0!, {%1\"); + else + strcpy (pattern, \"push\\t{%1\"); for (i = 1; i < num_saves; i++) { @@ -9018,13 +10816,23 @@ [(set_attr "type" "store4")] ) +(define_insn "stack_tie" + [(set (mem:BLK (scratch)) + (unspec:BLK [(match_operand:SI 0 "s_register_operand" "rk") + (match_operand:SI 1 "s_register_operand" "rk")] + UNSPEC_PRLG_STK))] + "" + "" + [(set_attr "length" "0")] +) + ;; Similarly for the floating point registers (define_insn "*push_fp_multi" [(match_parallel 2 "multi_register_push" [(set (match_operand:BLK 0 "memory_operand" "=m") (unspec:BLK [(match_operand:XF 1 "f_register_operand" "f")] UNSPEC_PUSH_MULT))])] - "TARGET_ARM" + "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_FPA" "* { char pattern[100]; @@ -9047,6 +10855,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" @@ -9058,7 +10875,7 @@ (define_insn "consttable_1" [(unspec_volatile [(match_operand 0 "" "")] VUNSPEC_POOL_1)] - "TARGET_THUMB" + "TARGET_THUMB1" "* making_const_table = TRUE; assemble_integer (operands[0], 1, BITS_PER_WORD, 1); @@ -9070,7 +10887,7 @@ (define_insn "consttable_2" [(unspec_volatile [(match_operand 0 "" "")] VUNSPEC_POOL_2)] - "TARGET_THUMB" + "TARGET_THUMB1" "* making_const_table = TRUE; assemble_integer (operands[0], 2, BITS_PER_WORD, 1); @@ -9090,13 +10907,14 @@ { case MODE_FLOAT: { - union real_extract u; - memcpy (&u, &CONST_DOUBLE_LOW (operands[0]), sizeof u); - assemble_real (u.d, GET_MODE (operands[0]), BITS_PER_WORD); + REAL_VALUE_TYPE r; + REAL_VALUE_FROM_CONST_DOUBLE (r, operands[0]); + assemble_real (r, GET_MODE (operands[0]), BITS_PER_WORD); break; } default: assemble_integer (operands[0], 4, BITS_PER_WORD, 1); + mark_symbol_refs_as_used (operands[0]); break; } return \"\"; @@ -9114,9 +10932,9 @@ { case MODE_FLOAT: { - union real_extract u; - memcpy (&u, &CONST_DOUBLE_LOW (operands[0]), sizeof u); - assemble_real (u.d, GET_MODE (operands[0]), BITS_PER_WORD); + REAL_VALUE_TYPE r; + REAL_VALUE_FROM_CONST_DOUBLE (r, operands[0]); + assemble_real (r, GET_MODE (operands[0]), BITS_PER_WORD); break; } default: @@ -9128,12 +10946,36 @@ [(set_attr "length" "8")] ) +(define_insn "consttable_16" + [(unspec_volatile [(match_operand 0 "" "")] VUNSPEC_POOL_16)] + "TARGET_EITHER" + "* + { + making_const_table = TRUE; + switch (GET_MODE_CLASS (GET_MODE (operands[0]))) + { + case MODE_FLOAT: + { + REAL_VALUE_TYPE r; + REAL_VALUE_FROM_CONST_DOUBLE (r, operands[0]); + assemble_real (r, GET_MODE (operands[0]), BITS_PER_WORD); + break; + } + default: + assemble_integer (operands[0], 16, BITS_PER_WORD, 1); + break; + } + return \"\"; + }" + [(set_attr "length" "16")] +) + ;; 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" + "TARGET_THUMB1" " if (flag_pic) { @@ -9147,42 +10989,24 @@ " ) -(define_insn "*thumb_tablejump" +;; NB never uses BX. +(define_insn "*thumb1_tablejump" [(set (pc) (match_operand:SI 0 "register_operand" "l*r")) (use (label_ref (match_operand 1 "" "")))] - "TARGET_THUMB" + "TARGET_THUMB1" "mov\\t%|pc, %0" [(set_attr "length" "2")] ) ;; V5 Instructions, -(define_insn "clz" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (unspec:SI [(match_operand:SI 1 "s_register_operand" "r")] - UNSPEC_CLZ))] - "TARGET_ARM && arm_arch5" - "clz\\t%0, %1") - -(define_expand "ffssi2" - [(set (match_operand:SI 0 "s_register_operand" "") - (ffs:SI (match_operand:SI 1 "s_register_operand" "")))] - "TARGET_ARM && arm_arch5" - " - { - rtx t1, t2, t3; - - t1 = gen_reg_rtx (SImode); - t2 = gen_reg_rtx (SImode); - t3 = gen_reg_rtx (SImode); - - emit_insn (gen_negsi2 (t1, operands[1])); - emit_insn (gen_andsi3 (t2, operands[1], t1)); - emit_insn (gen_clz (t3, t2)); - emit_insn (gen_subsi3 (operands[0], GEN_INT (32), t3)); - DONE; - }" -) +(define_insn "clzsi2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (clz:SI (match_operand:SI 1 "s_register_operand" "r")))] + "TARGET_32BIT && arm_arch5" + "clz%?\\t%0, %1" + [(set_attr "predicable" "yes") + (set_attr "insn" "clz")]) ;; V5E instructions. @@ -9190,7 +11014,7 @@ [(prefetch (match_operand:SI 0 "address_operand" "p") (match_operand:SI 1 "" "") (match_operand:SI 2 "" ""))] - "TARGET_ARM && arm_arch5e" + "TARGET_32BIT && arm_arch5e" "pld\\t%a0") ;; General predication pattern @@ -9199,7 +11023,7 @@ [(match_operator 0 "arm_comparison_operator" [(match_operand 1 "cc_register" "") (const_int 0)])] - "TARGET_ARM" + "TARGET_32BIT" "" ) @@ -9208,3 +11032,88 @@ "" "%@ %0 needed for prologue" ) + + +;; Patterns for exception handling + +(define_expand "eh_return" + [(use (match_operand 0 "general_operand" ""))] + "TARGET_EITHER" + " + { + if (TARGET_32BIT) + 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_THUMB1" + "#" + "&& reload_completed" + [(const_int 0)] + " + { + thumb_set_return_address (operands[0], operands[1]); + DONE; + }" +) + + +;; TLS support + +(define_insn "load_tp_hard" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(const_int 0)] UNSPEC_TLS))] + "TARGET_HARD_TP" + "mrc%?\\tp15, 0, %0, c13, c0, 3\\t@ load_tp_hard" + [(set_attr "predicable" "yes")] +) + +;; Doesn't clobber R1-R3. Must use r0 for the first operand. +(define_insn "load_tp_soft" + [(set (reg:SI 0) (unspec:SI [(const_int 0)] UNSPEC_TLS)) + (clobber (reg:SI LR_REGNUM)) + (clobber (reg:SI IP_REGNUM)) + (clobber (reg:CC CC_REGNUM))] + "TARGET_SOFT_TP" + "bl\\t__aeabi_read_tp\\t@ load_tp_soft" + [(set_attr "conds" "clob")] +) + +;; Load the FPA co-processor patterns +(include "fpa.md") +;; Load the Maverick co-processor patterns +(include "cirrus.md") +;; Vector bits common to IWMMXT and Neon +(include "vec-common.md") +;; Load the Intel Wireless Multimedia Extension patterns +(include "iwmmxt.md") +;; Load the VFP co-processor patterns +(include "vfp.md") +;; Thumb-2 patterns +(include "thumb2.md") +;; Neon patterns +(include "neon.md") +