;;- Machine description for ARM for GNU compiler
;; Copyright 1991, 1993, 1994, 1995, 1996, 1996, 1997, 1998, 1999, 2000,
-;; 2001, 2002, 2003 2004 Free Software Foundation, Inc.
+;; 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
;; Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl)
;; and Martin Simmons (@harleqn.co.uk).
;; More major hacks by Richard Earnshaw (rearnsha@arm.com).
;; You should have received a copy of the GNU General Public License
;; along with GCC; see the file COPYING. If not, write to
-;; the Free Software Foundation, 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
;; 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
(VUNSPEC_WCMP_EQ 11) ; Used by the iWMMXt WCMPEQ instructions
(VUNSPEC_WCMP_GTU 12) ; Used by the iWMMXt WCMPGTU instructions
(VUNSPEC_WCMP_GT 13) ; Used by the iwMMXT WCMPGT instructions
+ (VUNSPEC_EH_RETURN 20); Use to override the return address for exception
+ ; handling.
]
)
\f
; 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_tune_xscale")))
(define_attr "shift" "" (const_int 0))
; Floating Point Unit. If we only have floating point emulation, then there
; 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_byte load byte(s) from memory to arm registers
; mav_dmult Double multiplies (7 cycle)
;
(define_attr "type"
- "alu,alu_shift,alu_shift_reg,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,branch,call,load_byte,load1,load2,load3,load4,store1,store2,store3,store4,mav_farith,mav_dmult"
+ "alu,alu_shift,alu_shift_reg,mult,block,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith,f_flag,float_em,f_load,f_store,f_loads,f_loadd,f_stores,f_stored,f_mem_r,r_mem_f,f_2_r,r_2_f,f_cvt,branch,call,load_byte,load1,load2,load3,load4,store1,store2,store3,store4,mav_farith,mav_dmult"
(if_then_else
(eq_attr "insn" "smulxy,smlaxy,smlalxy,smulwy,smlawx,mul,muls,mla,mlas,umull,umulls,umlal,umlals,smull,smulls,smlal,smlals")
(const_string "mult")
(define_attr "conds" "use,set,clob,jump_clob,nocond"
(if_then_else (eq_attr "type" "call")
- (if_then_else (eq_attr "prog_mode" "prog32")
- (const_string "clob") (const_string "nocond"))
+ (const_string "clob")
(const_string "nocond")))
; Predicable means that the insn can be conditionally executed based on
; have one. Later ones, such as StrongARM, have write-back caches, so don't
; 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.
;; distant label. Only applicable to Thumb code.
(define_attr "far_jump" "yes,no" (const_string "no"))
+
+;;---------------------------------------------------------------------------
+;; Mode macros
+
+; A list of modes that are exactly 64 bits in size. We use this to expand
+; some splits that are the same for all modes when operating on ARM
+; registers.
+(define_mode_macro ANY64 [DI DF V8QI V4HI V2SI V2SF])
+
+;;---------------------------------------------------------------------------
+;; Predicates
+
+(include "predicates.md")
+
;;---------------------------------------------------------------------------
;; Pipeline descriptions
-;; Processor type. This attribute must exactly match the table in
-;; arm-cores.def.
-(define_attr "tune"
- "arm2,arm250,arm3,arm6,arm60,arm600,arm610,arm620,arm7,arm7m,arm7d,arm7dm,arm7di,arm7dmi,arm70,arm700,arm700i,arm710,arm720,arm710c,arm7100,arm7500,arm7500fe,arm7tdmi,arm710t,arm720t,arm740t,arm8,arm810,arm9,arm920,arm920t,arm940t,arm9tdmi,arm9e,ep9312,strongarm,strongarm110,strongarm1100,strongarm1110,arm10tdmi,arm1020t,arm926ejs,arm1026ejs,xscale,iwmmxt,arm1136js,arm1136jfs"
- (const (symbol_ref "arm_tune")))
+;; Processor type. This is created automatically from arm-cores.def.
+(include "arm-tune.md")
;; True if the generic scheduling description should be used.
(define_attr "generic_sched" "yes,no"
- (if_then_else
- (eq_attr "tune" "arm926ejs,arm1026ejs,arm1136js,arm1136jfs")
- (const_string "no")
- (const_string "yes")))
-
+ (const (if_then_else
+ (eq_attr "tune" "arm926ejs,arm1020e,arm1026ejs,arm1136js,arm1136jfs")
+ (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"))
+ (const_string "yes")
+ (const_string "no"))))
+
(include "arm-generic.md")
(include "arm926ejs.md")
+(include "arm1020e.md")
(include "arm1026ejs.md")
(include "arm1136jfs.md")
"
if (TARGET_ARM && GET_CODE (operands[2]) == CONST_INT)
{
- arm_split_constant (PLUS, SImode, INTVAL (operands[2]), operands[0],
- operands[1],
- (no_new_pseudos ? 0 : preserve_subexpressions_p ()));
+ arm_split_constant (PLUS, SImode, NULL_RTX,
+ INTVAL (operands[2]), operands[0], operands[1],
+ optimize && !no_new_pseudos);
DONE;
}
"
; addition.
(define_peephole2
[(match_scratch:SI 3 "r")
- (set (match_operand:SI 0 "s_register_operand" "")
- (plus:SI (match_operand:SI 1 "s_register_operand" "")
+ (set (match_operand:SI 0 "arm_general_register_operand" "")
+ (plus:SI (match_operand:SI 1 "arm_general_register_operand" "")
(match_operand:SI 2 "const_int_operand" "")))]
"TARGET_ARM &&
!(const_ok_for_arm (INTVAL (operands[2]))
|| 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;
"
;; Reloading and elimination of the frame pointer can
;; sometimes cause this optimization to be missed.
(define_peephole2
- [(set (match_operand:SI 0 "register_operand" "")
+ [(set (match_operand:SI 0 "arm_general_register_operand" "")
(match_operand:SI 1 "const_int_operand" ""))
(set (match_dup 0)
- (plus:SI (match_dup 0) (match_operand:SI 2 "register_operand" "")))]
+ (plus:SI (match_dup 0) (reg:SI SP_REGNUM)))]
"TARGET_THUMB
- && REGNO (operands[2]) == STACK_POINTER_REGNUM
&& (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) < 1024
&& (INTVAL (operands[1]) & 3) == 0"
- [(set (match_dup 0) (plus:SI (match_dup 2) (match_dup 1)))]
+ [(set (match_dup 0) (plus:SI (reg:SI SP_REGNUM) (match_dup 1)))]
""
)
[(set_attr "conds" "set")]
)
-;; These patterns are the same ones as the two regular addsi3_compare0
-;; patterns, except we write them slightly different - the combiner
-;; tends to generate them this way.
-(define_insn "*addsi3_compare0_for_combiner"
- [(set (reg:CC CC_REGNUM)
- (compare:CC
- (match_operand:SI 1 "s_register_operand" "r,r")
- (neg:SI (match_operand:SI 2 "arm_add_operand" "rI,L"))))
- (set (match_operand:SI 0 "s_register_operand" "=r,r")
- (plus:SI (match_dup 1) (match_dup 2)))]
- "TARGET_ARM"
- "@
- add%?s\\t%0, %1, %2
- sub%?s\\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"))))]
+(define_insn "*compare_negsi_si"
+ [(set (reg:CC_Z CC_REGNUM)
+ (compare:CC_Z
+ (neg:SI (match_operand:SI 0 "s_register_operand" "r"))
+ (match_operand:SI 1 "s_register_operand" "r")))]
"TARGET_ARM"
- "@
- cmn%?\\t%0, %1
- cmp%?\\t%0, #%n1"
+ "cmn%?\\t%1, %0"
[(set_attr "conds" "set")]
)
;; similarly for the beq variant using bcc.
;; This is a common looping idiom (while (n--))
(define_peephole2
- [(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" "")
(const_int -1)))
(set (match_operand 2 "cc_register" "")
(compare (match_dup 0) (const_int -1)))
{
if (TARGET_ARM)
{
- arm_split_constant (MINUS, SImode, INTVAL (operands[1]), operands[0],
- operands[2],
- (no_new_pseudos ? 0
- : preserve_subexpressions_p ()));
+ arm_split_constant (MINUS, SImode, NULL_RTX,
+ INTVAL (operands[1]), operands[0],
+ operands[2], optimize && !no_new_pseudos);
DONE;
}
else /* TARGET_THUMB */
&& !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")
(define_peephole2
[(match_scratch:SI 3 "r")
- (set (match_operand:SI 0 "s_register_operand" "")
+ (set (match_operand:SI 0 "arm_general_register_operand" "")
(minus:SI (match_operand:SI 1 "const_int_operand" "")
- (match_operand:SI 2 "s_register_operand" "")))]
+ (match_operand:SI 2 "arm_general_register_operand" "")))]
"TARGET_ARM
&& !const_ok_for_arm (INTVAL (operands[1]))
&& const_ok_for_arm (~INTVAL (operands[1]))"
"TARGET_THUMB"
"*
if (which_alternative < 2)
- return \"mov\\t%0, %1\;mul\\t%0, %0, %2\";
+ return \"mov\\t%0, %1\;mul\\t%0, %2\";
else
- return \"mul\\t%0, %0, %2\";
+ return \"mul\\t%0, %2\";
"
[(set_attr "length" "4,4,2")
(set_attr "insn" "mul")]
(const_int 0)))
(set (match_operand:SI 0 "s_register_operand" "=&r,&r")
(mult:SI (match_dup 2) (match_dup 1)))]
- "TARGET_ARM && !arm_arch_xscale"
+ "TARGET_ARM"
"mul%?s\\t%0, %2, %1"
[(set_attr "conds" "set")
(set_attr "insn" "muls")]
(match_operand:SI 1 "s_register_operand" "%?r,0"))
(const_int 0)))
(clobber (match_scratch:SI 0 "=&r,&r"))]
- "TARGET_ARM && !arm_arch_xscale"
+ "TARGET_ARM"
"mul%?s\\t%0, %2, %1"
[(set_attr "conds" "set")
(set_attr "insn" "muls")]
(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_arch_xscale"
+ "TARGET_ARM"
"mla%?s\\t%0, %2, %1, %3"
[(set_attr "conds" "set")
(set_attr "insn" "mlas")]
(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_arch_xscale"
+ "TARGET_ARM"
"mla%?s\\t%0, %2, %1, %3"
[(set_attr "conds" "set")
(set_attr "insn" "mlas")]
{
if (GET_CODE (operands[2]) == CONST_INT)
{
- arm_split_constant (AND, SImode, INTVAL (operands[2]), operands[0],
- operands[1],
- (no_new_pseudos
- ? 0 : preserve_subexpressions_p ()));
+ arm_split_constant (AND, SImode, NULL_RTX,
+ INTVAL (operands[2]), operands[0],
+ operands[1], optimize && !no_new_pseudos);
+
DONE;
}
}
|| 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 "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")
&& INTVAL (operands[2]) > 0
&& INTVAL (operands[2]) + (INTVAL (operands[3]) & 1) <= 8
&& INTVAL (operands[2]) + INTVAL (operands[3]) <= 32)"
- "*
+ "#"
+ "TARGET_ARM
+ && (INTVAL (operands[3]) >= 0 && INTVAL (operands[3]) < 32
+ && INTVAL (operands[2]) > 0
+ && INTVAL (operands[2]) + (INTVAL (operands[3]) & 1) <= 8
+ && INTVAL (operands[2]) + INTVAL (operands[3]) <= 32)"
+ [(parallel [(set (reg:CC_NOOV CC_REGNUM)
+ (compare:CC_NOOV (and:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))
+ (set (match_dup 0) (and:SI (match_dup 1) (match_dup 2)))])
+ (set (match_dup 0)
+ (if_then_else:SI (eq (reg:CC_NOOV CC_REGNUM) (const_int 0))
+ (match_dup 0) (const_int 1)))]
+ "
+ operands[2] = GEN_INT (((1 << INTVAL (operands[2])) - 1)
+ << INTVAL (operands[3]));
+ "
+ [(set_attr "conds" "clob")
+ (set_attr "length" "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")]
emit_insn (gen_andsi3 (op1, operands[0], GEN_INT (~mask2)));
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)
{
if (TARGET_ARM)
{
- arm_split_constant (IOR, SImode, INTVAL (operands[2]), operands[0],
- operands[1],
- (no_new_pseudos
- ? 0 : preserve_subexpressions_p ()));
+ arm_split_constant (IOR, SImode, NULL_RTX,
+ INTVAL (operands[2]), operands[0], operands[1],
+ optimize && !no_new_pseudos);
DONE;
}
else /* TARGET_THUMB */
&& !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")
(define_peephole2
[(match_scratch:SI 3 "r")
- (set (match_operand:SI 0 "s_register_operand" "")
- (ior:SI (match_operand:SI 1 "s_register_operand" "")
+ (set (match_operand:SI 0 "arm_general_register_operand" "")
+ (ior:SI (match_operand:SI 1 "arm_general_register_operand" "")
(match_operand:SI 2 "const_int_operand" "")))]
"TARGET_ARM
&& !const_ok_for_arm (INTVAL (operands[2]))
(match_operand:SI 3 "arm_rhs_operand" "rI,rI")])
(match_operand:SI 1 "s_register_operand" "0,?r")]))
(clobber (reg:CC CC_REGNUM))]
- "TARGET_ARM
- && (GET_CODE (operands[1]) != REG
- || (REGNO(operands[1]) != FRAME_POINTER_REGNUM
- && REGNO(operands[1]) != ARG_POINTER_REGNUM))"
+ "TARGET_ARM && !arm_eliminable_register (operands[1])"
"*
{
enum rtx_code code = GET_CODE (operands[4]);
(define_expand "negsf2"
[(set (match_operand:SF 0 "s_register_operand" "")
(neg:SF (match_operand:SF 1 "s_register_operand" "")))]
- "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
""
)
(define_expand "negdf2"
[(set (match_operand:DF 0 "s_register_operand" "")
(neg:DF (match_operand:DF 1 "s_register_operand" "")))]
- "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"")
;; abssi2 doesn't really clobber the condition codes if a different register
{
if ((TARGET_THUMB || 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_ARM && TARGET_MMU_TRAPS && GET_CODE (operands[1]) == MEM)
+ if (TARGET_ARM && GET_CODE (operands[1]) == MEM)
{
emit_insn (gen_movhi_bytes (operands[0], operands[1]));
DONE;
(set_attr "predicable" "yes")]
)
-(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_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_expand "zero_extendqisi2"
[(set (match_operand:SI 0 "s_register_operand" "")
(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))]
}
else if (arm_arch4)
{
- /* 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_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;
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];
;; 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 an abort later on when
+;; 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.
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];
if (reg_mentioned_p (operands[2], ops[1]))
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);
"sxtah%?\\t%0, %2, %1"
)
-(define_split
- [(set (match_operand:SI 0 "s_register_operand" "")
- (sign_extend:SI (match_operand:HI 1 "alignable_memory_operand" "")))
- (clobber (match_operand:SI 2 "s_register_operand" ""))]
- "TARGET_ARM && (!arm_arch4)"
- [(set (match_dup 2) (match_dup 1))
- (set (match_dup 0) (ashiftrt:SI (match_dup 2) (const_int 16)))]
- "
- if ((operands[1] = arm_gen_rotated_half_load (operands[1])) == NULL)
- FAIL;
- "
-)
-
-(define_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_expand "extendqihi2"
[(set (match_dup 2)
(ashift:SI (match_operand:QI 1 "general_operand" "")
}"
)
-; Rather than restricting all byte accesses to memory addresses that ldrsb
-; can handle, we fix up the ones that ldrsb can't grok with a split.
(define_insn "*extendqihi_insn"
- [(set (match_operand:HI 0 "s_register_operand" "=r")
- (sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))]
+ [(set (match_operand:HI 0 "s_register_operand" "=r")
+ (sign_extend:HI (match_operand:QI 1 "memory_operand" "Uq")))]
"TARGET_ARM && arm_arch4"
- "*
- /* If the address is invalid, this will split the instruction into two. */
- if (bad_signed_byte_operand (operands[1], VOIDmode))
- return \"#\";
- return \"ldr%?sb\\t%0, %1\";
- "
+ "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" "")
}"
)
-; 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"
[(set (match_operand:SI 0 "s_register_operand" "=r")
- (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
+ (sign_extend:SI (match_operand:QI 1 "memory_operand" "Uq")))]
"TARGET_ARM && arm_arch4 && !arm_arch6"
- "*
- /* 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\";
- "
+ "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_insn "*arm_extendqisi_v6"
[(set (match_operand:SI 0 "s_register_operand" "=r,r")
- (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
+ (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,Uq")))]
"TARGET_ARM && arm_arch6"
- "*
- if (which_alternative == 0)
- return \"sxtb%?\\t%0, %1\";
-
- /* 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\";
- "
+ "@
+ sxtb%?\\t%0, %1
+ ldr%?sb\\t%0, %1"
[(set_attr "type" "alu_shift,load_byte")
(set_attr "predicable" "yes")
- (set_attr "length" "4,8")
(set_attr "pool_range" "*,256")
(set_attr "neg_pool_range" "*,244")]
)
(set_attr "predicable" "yes")]
)
-(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 "*thumb_extendqisi2"
[(set (match_operand:SI 0 "register_operand" "=l,l")
(sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))]
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);
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);
)
(define_insn "*arm_movdi"
- [(set (match_operand:DI 0 "nonimmediate_di_operand" "=r, r, o<>")
- (match_operand:DI 1 "di_operand" "rIK,mi,r"))]
+ [(set (match_operand:DI 0 "nonimmediate_di_operand" "=r, r, r, r, m")
+ (match_operand:DI 1 "di_operand" "rDa,Db,Dc,mi,r"))]
"TARGET_ARM
&& !(TARGET_HARD_FLOAT && (TARGET_MAVERICK || TARGET_VFP))
&& !TARGET_IWMMXT"
"*
- return (output_move_double (operands));
+ switch (which_alternative)
+ {
+ case 0:
+ case 1:
+ case 2:
+ return \"#\";
+ default:
+ return output_move_double (operands);
+ }
+ "
+ [(set_attr "length" "8,12,16,8,8")
+ (set_attr "type" "*,*,*,load2,store2")
+ (set_attr "pool_range" "*,*,*,1020,*")
+ (set_attr "neg_pool_range" "*,*,*,1008,*")]
+)
+
+(define_split
+ [(set (match_operand:ANY64 0 "arm_general_register_operand" "")
+ (match_operand:ANY64 1 "const_double_operand" ""))]
+ "TARGET_ARM
+ && reload_completed
+ && (arm_const_double_inline_cost (operands[1])
+ <= ((optimize_size || arm_ld_sched) ? 3 : 4))"
+ [(const_int 0)]
+ "
+ arm_split_constant (SET, SImode, curr_insn,
+ INTVAL (gen_lowpart (SImode, operands[1])),
+ gen_lowpart (SImode, operands[0]), NULL_RTX, 0);
+ arm_split_constant (SET, SImode, curr_insn,
+ INTVAL (gen_highpart_mode (SImode,
+ GET_MODE (operands[0]),
+ operands[1])),
+ gen_highpart (SImode, operands[0]), NULL_RTX, 0);
+ DONE;
+ "
+)
+
+; If optimizing for size, or if we have load delay slots, then
+; we want to split the constant into two separate operations.
+; In both cases this may split a trivial part into a single data op
+; leaving a single complex constant to load. We can also get longer
+; offsets in a LDR which means we get better chances of sharing the pool
+; entries. Finally, we can normally do a better job of scheduling
+; LDR instructions than we can with LDM.
+; This pattern will only match if the one above did not.
+(define_split
+ [(set (match_operand:ANY64 0 "arm_general_register_operand" "")
+ (match_operand:ANY64 1 "const_double_operand" ""))]
+ "TARGET_ARM && reload_completed
+ && arm_const_double_by_parts (operands[1])"
+ [(set (match_dup 0) (match_dup 1))
+ (set (match_dup 2) (match_dup 3))]
+ "
+ operands[2] = gen_highpart (SImode, operands[0]);
+ operands[3] = gen_highpart_mode (SImode, GET_MODE (operands[0]),
+ operands[1]);
+ operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[1] = gen_lowpart (SImode, operands[1]);
+ "
+)
+
+(define_split
+ [(set (match_operand:ANY64 0 "arm_general_register_operand" "")
+ (match_operand:ANY64 1 "arm_general_register_operand" ""))]
+ "TARGET_EITHER && reload_completed"
+ [(set (match_dup 0) (match_dup 1))
+ (set (match_dup 2) (match_dup 3))]
+ "
+ operands[2] = gen_highpart (SImode, operands[0]);
+ operands[3] = gen_highpart (SImode, operands[1]);
+ operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[1] = gen_lowpart (SImode, operands[1]);
+
+ /* Handle a partial overlap. */
+ if (rtx_equal_p (operands[0], operands[3]))
+ {
+ rtx tmp0 = operands[0];
+ rtx tmp1 = operands[1];
+
+ operands[0] = operands[2];
+ operands[1] = operands[3];
+ operands[2] = tmp0;
+ operands[3] = tmp1;
+ }
+ "
+)
+
+;; We can't actually do base+index doubleword loads if the index and
+;; destination overlap. Split here so that we at least have chance to
+;; schedule.
+(define_split
+ [(set (match_operand:DI 0 "s_register_operand" "")
+ (mem:DI (plus:SI (match_operand:SI 1 "s_register_operand" "")
+ (match_operand:SI 2 "s_register_operand" ""))))]
+ "TARGET_LDRD
+ && reg_overlap_mentioned_p (operands[0], operands[1])
+ && reg_overlap_mentioned_p (operands[0], operands[2])"
+ [(set (match_dup 4)
+ (plus:SI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 0)
+ (mem:DI (match_dup 4)))]
+ "
+ operands[4] = gen_rtx_REG (SImode, REGNO(operands[0]));
"
- [(set_attr "length" "8")
- (set_attr "type" "*,load2,store2")
- (set_attr "pool_range" "*,1020,*")
- (set_attr "neg_pool_range" "*,1008,*")]
)
;;; ??? This should have alternatives for constants.
&& !(const_ok_for_arm (INTVAL (operands[1]))
|| const_ok_for_arm (~INTVAL (operands[1]))))
{
- arm_split_constant (SET, SImode, INTVAL (operands[1]), operands[0],
- NULL_RTX,
- (no_new_pseudos ? 0
- : preserve_subexpressions_p ()));
+ arm_split_constant (SET, SImode, NULL_RTX,
+ INTVAL (operands[1]), operands[0], NULL_RTX,
+ optimize && !no_new_pseudos);
DONE;
}
}
|| 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;
"
)
"flag_pic"
"
{
- arm_finalize_pic (0);
+ /* r3 is clobbered by set/longjmp, so we can use it as a scratch
+ register. */
+ arm_load_pic_register (3);
DONE;
}")
emit_insn (gen_movsi (reg, GEN_INT (val)));
operands[1] = gen_lowpart (HImode, reg);
}
- else if (arm_arch4 && !no_new_pseudos && optimize > 0
+ else if (arm_arch4 && optimize && !no_new_pseudos
&& GET_CODE (operands[1]) == MEM)
{
rtx reg = gen_reg_rtx (SImode);
}
else if (!arm_arch4)
{
- /* Note: We do not have to worry about TARGET_MMU_TRAPS
- for v4 and up architectures because LDRH instructions will
- be used to access the HI values, and these cannot generate
- unaligned word access faults in the MMU. */
if (GET_CODE (operands[1]) == MEM)
{
- if (TARGET_MMU_TRAPS)
- {
- rtx base;
- rtx offset = const0_rtx;
- rtx reg = gen_reg_rtx (SImode);
-
- if ((GET_CODE (base = XEXP (operands[1], 0)) == REG
- || (GET_CODE (base) == PLUS
- && (GET_CODE (offset = XEXP (base, 1))
- == CONST_INT)
- && ((INTVAL(offset) & 1) != 1)
- && GET_CODE (base = XEXP (base, 0)) == REG))
- && REGNO_POINTER_ALIGN (REGNO (base)) >= 32)
- {
- HOST_WIDE_INT new_offset = INTVAL (offset) & ~3;
- rtx new;
-
- new = gen_rtx_MEM (SImode,
- plus_constant (base, new_offset));
- MEM_COPY_ATTRIBUTES (new, operands[1]);
- emit_insn (gen_movsi (reg, new));
- if (((INTVAL (offset) & 2) != 0)
- ^ (BYTES_BIG_ENDIAN ? 1 : 0))
- {
- rtx reg2 = gen_reg_rtx (SImode);
-
- emit_insn (gen_lshrsi3 (reg2, reg,
- GEN_INT (16)));
- reg = reg2;
- }
- }
- else
- emit_insn (gen_movhi_bytes (reg, operands[1]));
-
- operands[1] = gen_lowpart (HImode, reg);
- }
- else if (BYTES_BIG_ENDIAN)
+ rtx base;
+ rtx offset = const0_rtx;
+ rtx reg = gen_reg_rtx (SImode);
+
+ if ((GET_CODE (base = XEXP (operands[1], 0)) == REG
+ || (GET_CODE (base) == PLUS
+ && (GET_CODE (offset = XEXP (base, 1))
+ == CONST_INT)
+ && ((INTVAL(offset) & 1) != 1)
+ && GET_CODE (base = XEXP (base, 0)) == REG))
+ && REGNO_POINTER_ALIGN (REGNO (base)) >= 32)
{
- rtx base;
- rtx offset = const0_rtx;
-
- if ((GET_CODE (base = XEXP (operands[1], 0)) == REG
- || (GET_CODE (base) == PLUS
- && (GET_CODE (offset = XEXP (base, 1))
- == CONST_INT)
- && GET_CODE (base = XEXP (base, 0)) == REG))
- && REGNO_POINTER_ALIGN (REGNO (base)) >= 32)
- {
- rtx reg = gen_reg_rtx (SImode);
- rtx new;
-
- if ((INTVAL (offset) & 2) == 2)
- {
- HOST_WIDE_INT new_offset = INTVAL (offset) ^ 2;
- new = gen_rtx_MEM (SImode,
- plus_constant (base,
- new_offset));
- MEM_COPY_ATTRIBUTES (new, operands[1]);
- emit_insn (gen_movsi (reg, new));
- }
- else
- {
- new = gen_rtx_MEM (SImode,
- XEXP (operands[1], 0));
- MEM_COPY_ATTRIBUTES (new, operands[1]);
- emit_insn (gen_rotated_loadsi (reg, new));
- }
-
- operands[1] = gen_lowpart (HImode, reg);
- }
- else
- {
- emit_insn (gen_movhi_bigend (operands[0],
- operands[1]));
- DONE;
- }
+ rtx new;
+
+ new = widen_memory_access (operands[1], SImode,
+ ((INTVAL (offset) & ~3)
+ - INTVAL (offset)));
+ emit_insn (gen_movsi (reg, new));
+ if (((INTVAL (offset) & 2) != 0)
+ ^ (BYTES_BIG_ENDIAN ? 1 : 0))
+ {
+ rtx reg2 = gen_reg_rtx (SImode);
+
+ emit_insn (gen_lshrsi3 (reg2, reg, GEN_INT (16)));
+ reg = reg2;
+ }
}
+ else
+ emit_insn (gen_movhi_bytes (reg, operands[1]));
+
+ operands[1] = gen_lowpart (HImode, reg);
}
}
}
{
/* 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]));
{
if (!no_new_pseudos)
{
- if (GET_CODE (operands[0]) != REG)
- operands[1] = force_reg (HImode, operands[1]);
+ if (GET_CODE (operands[1]) == CONST_INT)
+ {
+ rtx reg = gen_reg_rtx (SImode);
+
+ emit_insn (gen_movsi (reg, operands[1]));
+ operands[1] = gen_lowpart (HImode, reg);
+ }
/* ??? We shouldn't really get invalid addresses here, but this can
happen if we are passed a SP (never OK for HImode/QImode) or
operands[1]
= replace_equiv_address (operands[1],
copy_to_reg (XEXP (operands[1], 0)));
+
+ if (GET_CODE (operands[1]) == MEM && optimize > 0)
+ {
+ rtx reg = gen_reg_rtx (SImode);
+
+ emit_insn (gen_zero_extendhisi2 (reg, operands[1]));
+ operands[1] = gen_lowpart (HImode, reg);
+ }
+
+ if (GET_CODE (operands[0]) == MEM)
+ operands[1] = force_reg (HImode, operands[1]);
}
- /* Handle loading a large integer during reload. */
else if (GET_CODE (operands[1]) == CONST_INT
&& !CONST_OK_FOR_THUMB_LETTER (INTVAL (operands[1]), 'I'))
{
+ /* Handle loading a large integer during reload. */
+
/* Writing a constant to memory needs a scratch, which should
be handled with SECONDARY_RELOADs. */
- if (GET_CODE (operands[0]) != REG)
- abort ();
+ gcc_assert (GET_CODE (operands[0]) == REG);
operands[0] = gen_rtx_SUBREG (SImode, operands[0], 0);
emit_insn (gen_movsi (operands[0], operands[1]));
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. */
)
-(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" "load1")
- (set_attr "predicable" "yes")]
-)
-
-(define_expand "movhi_bytes"
- [(set (match_dup 2) (zero_extend:SI (match_operand:HI 1 "" "")))
- (set (match_dup 3)
- (zero_extend:SI (match_dup 6)))
- (set (match_operand:SI 0 "" "")
- (ior:SI (ashift:SI (match_dup 4) (const_int 8)) (match_dup 5)))]
- "TARGET_ARM"
- "
+(define_expand "movhi_bytes"
+ [(set (match_dup 2) (zero_extend:SI (match_operand:HI 1 "" "")))
+ (set (match_dup 3)
+ (zero_extend:SI (match_dup 6)))
+ (set (match_operand:SI 0 "" "")
+ (ior:SI (ashift:SI (match_dup 4) (const_int 8)) (match_dup 5)))]
+ "TARGET_ARM"
+ "
{
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);
"@
mov%?\\t%0, %1\\t%@ movhi
mvn%?\\t%0, #%B1\\t%@ movhi
- str%?h\\t%1, %0\\t%@ movhi
+ str%?h\\t%1, %0\\t%@ movhi
ldr%?h\\t%0, %1\\t%@ movhi"
[(set_attr "type" "*,*,store1,load1")
(set_attr "predicable" "yes")
(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" "*,*,load1")
- (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" "*,*,load1")
- (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" "load1")
- (set_attr "predicable" "yes")
- (set_attr "pool_range" "4096")
- (set_attr "neg_pool_range" "4084")]
-)
-
(define_insn "*movhi_bytes"
[(set (match_operand:HI 0 "s_register_operand" "=r,r")
(match_operand:HI 1 "arm_rhs_operand" "rI,K"))]
- "TARGET_ARM && TARGET_MMU_TRAPS"
+ "TARGET_ARM"
"@
mov%?\\t%0, %1\\t%@ movhi
mvn%?\\t%0, #%B1\\t%@ movhi"
[(set_attr "predicable" "yes")]
)
-(define_insn "thumb_movhi_clobber"
- [(set (match_operand:HI 0 "memory_operand" "=m")
- (match_operand:HI 1 "register_operand" "l"))
- (clobber (match_operand:SI 2 "register_operand" "=&l"))]
+(define_expand "thumb_movhi_clobber"
+ [(set (match_operand:HI 0 "memory_operand" "")
+ (match_operand:HI 1 "register_operand" ""))
+ (clobber (match_operand:DI 2 "register_operand" ""))]
"TARGET_THUMB"
- "*
- abort ();"
+ "
+ if (strict_memory_address_p (HImode, XEXP (operands[0], 0))
+ && REGNO (operands[1]) <= LAST_LO_REGNUM)
+ {
+ emit_insn (gen_movhi (operands[0], operands[1]));
+ DONE;
+ }
+ /* XXX Fixme, need to handle other cases here as well. */
+ gcc_unreachable ();
+ "
)
;; We use a DImode scratch because we may occasionally need an additional
[(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);
(match_operand:QI 1 "general_operand" ""))]
"TARGET_EITHER"
"
- if (TARGET_ARM)
- {
- /* Everything except mem = const or mem = mem can be done easily */
-
- if (!no_new_pseudos)
- {
- if (GET_CODE (operands[1]) == CONST_INT)
- {
- rtx reg = gen_reg_rtx (SImode);
-
- emit_insn (gen_movsi (reg, operands[1]));
- operands[1] = gen_lowpart (QImode, reg);
- }
- if (GET_CODE (operands[1]) == MEM && optimize > 0)
- {
- rtx reg = gen_reg_rtx (SImode);
+ /* Everything except mem = const or mem = mem can be done easily */
- emit_insn (gen_zero_extendqisi2 (reg, operands[1]));
- operands[1] = gen_lowpart (QImode, reg);
- }
- if (GET_CODE (operands[0]) == MEM)
- operands[1] = force_reg (QImode, operands[1]);
- }
- }
- else /* TARGET_THUMB */
+ if (!no_new_pseudos)
{
- if (!no_new_pseudos)
- {
- if (GET_CODE (operands[0]) != REG)
- operands[1] = force_reg (QImode, operands[1]);
+ if (GET_CODE (operands[1]) == CONST_INT)
+ {
+ rtx reg = gen_reg_rtx (SImode);
+ emit_insn (gen_movsi (reg, operands[1]));
+ operands[1] = gen_lowpart (QImode, reg);
+ }
+
+ if (TARGET_THUMB)
+ {
/* ??? We shouldn't really get invalid addresses here, but this can
happen if we are passed a SP (never OK for HImode/QImode) or
virtual register (rejected by GO_IF_LEGITIMATE_ADDRESS for
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_extendqisi2 (reg, operands[1]));
+ operands[1] = gen_lowpart (QImode, reg);
+ }
+
+ if (GET_CODE (operands[0]) == MEM)
+ operands[1] = force_reg (QImode, operands[1]);
+ }
+ else if (TARGET_THUMB
+ && GET_CODE (operands[1]) == CONST_INT
+ && !CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I'))
+ {
/* Handle loading a large integer during reload. */
- 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;
- }
+ /* 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;
}
"
)
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)
)
(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"))]
+ [(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
"
- "* return output_move_double (operands);"
- [(set_attr "length" "8,8,8")
- (set_attr "type" "*,load2,store2")
+ "*
+ 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")]
)
(set_attr "pool_range" "*,*,*,1020,*,*")]
)
+(define_expand "movxf"
+ [(set (match_operand:XF 0 "general_operand" "")
+ (match_operand:XF 1 "general_operand" ""))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+ "
+ if (GET_CODE (operands[0]) == MEM)
+ operands[1] = force_reg (XFmode, operands[1]);
+ "
+)
+
;; Vector Moves
(define_expand "movv2si"
[(set (match_operand:V2SI 0 "nonimmediate_operand" "")
(match_operand:SI 1 "" ""))
(use (match_operand:SI 2 "" ""))])]
"TARGET_ARM"
- "
+{
+ HOST_WIDE_INT offset = 0;
+
/* Support only fixed point registers. */
if (GET_CODE (operands[2]) != CONST_INT
|| INTVAL (operands[2]) > 14
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
(set_attr "predicable" "yes")]
)
+(define_insn "*ldmsi_postinc4_thumb"
+ [(match_parallel 0 "load_multiple_operation"
+ [(set (match_operand:SI 1 "s_register_operand" "=l")
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1")
+ (const_int 16)))
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
+ (mem:SI (match_dup 2)))
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
+ (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+ (set (match_operand:SI 5 "arm_hard_register_operand" "")
+ (mem:SI (plus:SI (match_dup 2) (const_int 8))))
+ (set (match_operand:SI 6 "arm_hard_register_operand" "")
+ (mem:SI (plus:SI (match_dup 2) (const_int 12))))])]
+ "TARGET_THUMB && XVECLEN (operands[0], 0) == 5"
+ "ldmia\\t%1!, {%3, %4, %5, %6}"
+ [(set_attr "type" "load4")]
+)
+
(define_insn "*ldmsi_postinc3"
[(match_parallel 0 "load_multiple_operation"
[(set (match_operand:SI 1 "s_register_operand" "=r")
(match_operand:SI 1 "" ""))
(use (match_operand:SI 2 "" ""))])]
"TARGET_ARM"
- "
+{
+ HOST_WIDE_INT offset = 0;
+
/* Support only fixed point registers. */
if (GET_CODE (operands[2]) != CONST_INT
|| INTVAL (operands[2]) > 14
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
(set_attr "type" "store4")]
)
+(define_insn "*stmsi_postinc4_thumb"
+ [(match_parallel 0 "store_multiple_operation"
+ [(set (match_operand:SI 1 "s_register_operand" "=l")
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1")
+ (const_int 16)))
+ (set (mem:SI (match_dup 2))
+ (match_operand:SI 3 "arm_hard_register_operand" ""))
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
+ (match_operand:SI 4 "arm_hard_register_operand" ""))
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 8)))
+ (match_operand:SI 5 "arm_hard_register_operand" ""))
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 12)))
+ (match_operand:SI 6 "arm_hard_register_operand" ""))])]
+ "TARGET_THUMB && XVECLEN (operands[0], 0) == 5"
+ "stmia\\t%1!, {%3, %4, %5, %6}"
+ [(set_attr "type" "store4")]
+)
+
(define_insn "*stmsi_postinc3"
[(match_parallel 0 "store_multiple_operation"
[(set (match_operand:SI 1 "s_register_operand" "=r")
;; 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" "")
"
if (TARGET_ARM)
{
- if (arm_gen_movstrqi (operands))
+ if (arm_gen_movmemqi (operands))
DONE;
FAIL;
}
|| INTVAL (operands[2]) > 48)
FAIL;
- thumb_expand_movstrqi (operands);
+ thumb_expand_movmemqi (operands);
DONE;
}
"
(define_insn "*negated_cbranchsi4"
[(set (pc)
(if_then_else
- (match_operator 0 "arm_comparison_operator"
+ (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 "" ""))
[(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"))
- (match_operand:SI 2 "s_register_operand" "0,1,1,1"))
+ [(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,*?h,*?m,*?m")
+ (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"))]
+ (clobber (match_scratch:SI 1 "=X,l,l,&l,&l"))]
"TARGET_THUMB"
"*
{
if (which_alternative == 0)
output_asm_insn (\"bic\\t%0, %3\", operands);
- else if (which_alternative == 1)
+ 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
(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,I,L"))
+ (match_operand:SI 2 "reg_or_int_operand" "J,l,L,IJ"))
(const_int 0)])
(label_ref (match_operand 4 "" ""))
(pc)))
case 1:
output_asm_insn (\"cmn\t%1, %2\", operands);
break;
- case 3:
- output_asm_insn (\"add\t%0, %1, %2\", operands);
+ 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 4:
- output_asm_insn (\"add\t%0, %0, %2\", operands);
+ 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;
}
(const_string "alu_shift_reg")))]
)
-(define_insn "*cmpsi_neg_shiftsi"
- [(set (reg:CC CC_REGNUM)
- (compare:CC (match_operand:SI 0 "s_register_operand" "r")
- (neg:SI (match_operator:SI 3 "shift_operator"
- [(match_operand:SI 1 "s_register_operand" "r")
- (match_operand:SI 2 "arm_rhs_operand" "rM")]))))]
+(define_insn "*cmpsi_negshiftsi_si"
+ [(set (reg:CC_Z CC_REGNUM)
+ (compare:CC_Z
+ (neg:SI (match_operator:SI 1 "shift_operator"
+ [(match_operand:SI 2 "s_register_operand" "r")
+ (match_operand:SI 3 "reg_or_int_operand" "rM")]))
+ (match_operand:SI 0 "s_register_operand" "r")))]
"TARGET_ARM"
- "cmn%?\\t%0, %1%S3"
+ "cmn%?\\t%0, %2%S1"
[(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")))]
+ (set (attr "type") (if_then_else (match_operand 3 "const_int_operand" "")
+ (const_string "alu_shift")
+ (const_string "alu_shift_reg")))]
)
;; Cirrus SF compare instruction
(if_then_else (unordered (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
- "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (UNORDERED, arm_compare_op0,
arm_compare_op1);"
)
(if_then_else (ordered (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
- "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (ORDERED, arm_compare_op0,
arm_compare_op1);"
)
(if_then_else (ungt (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
- "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (UNGT, arm_compare_op0, arm_compare_op1);"
)
(if_then_else (unlt (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
- "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (UNLT, arm_compare_op0, arm_compare_op1);"
)
(if_then_else (unge (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
- "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (UNGE, arm_compare_op0, arm_compare_op1);"
)
(if_then_else (unle (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
- "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (UNLE, arm_compare_op0, arm_compare_op1);"
)
(if_then_else (uneq (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
- "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (UNEQ, arm_compare_op0, arm_compare_op1);"
)
(if_then_else (ltgt (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
- "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (LTGT, arm_compare_op0, arm_compare_op1);"
)
(if_then_else (uneq (match_operand 1 "cc_register" "") (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
- "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+ "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\";
"
(if_then_else (ltgt (match_operand 1 "cc_register" "") (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
- "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+ "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\";
"
(if_then_else (uneq (match_operand 1 "cc_register" "") (const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
- "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+ "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\";
"
(if_then_else (ltgt (match_operand 1 "cc_register" "") (const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
- "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+ "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\";
"
(define_expand "sunordered"
[(set (match_operand:SI 0 "s_register_operand" "")
(unordered:SI (match_dup 1) (const_int 0)))]
- "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (UNORDERED, arm_compare_op0,
arm_compare_op1);"
)
(define_expand "sordered"
[(set (match_operand:SI 0 "s_register_operand" "")
(ordered:SI (match_dup 1) (const_int 0)))]
- "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (ORDERED, arm_compare_op0,
arm_compare_op1);"
)
(define_expand "sungt"
[(set (match_operand:SI 0 "s_register_operand" "")
(ungt:SI (match_dup 1) (const_int 0)))]
- "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (UNGT, arm_compare_op0,
arm_compare_op1);"
)
(define_expand "sunge"
[(set (match_operand:SI 0 "s_register_operand" "")
(unge:SI (match_dup 1) (const_int 0)))]
- "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (UNGE, arm_compare_op0,
arm_compare_op1);"
)
(define_expand "sunlt"
[(set (match_operand:SI 0 "s_register_operand" "")
(unlt:SI (match_dup 1) (const_int 0)))]
- "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (UNLT, arm_compare_op0,
arm_compare_op1);"
)
(define_expand "sunle"
[(set (match_operand:SI 0 "s_register_operand" "")
(unle:SI (match_dup 1) (const_int 0)))]
- "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (UNLE, arm_compare_op0,
arm_compare_op1);"
)
; (define_expand "suneq"
; [(set (match_operand:SI 0 "s_register_operand" "")
; (uneq:SI (match_dup 1) (const_int 0)))]
-; "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
-; "abort ();"
+; "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
+; "gcc_unreachable ();"
; )
;
; (define_expand "sltgt"
; [(set (match_operand:SI 0 "s_register_operand" "")
; (ltgt:SI (match_dup 1) (const_int 0)))]
-; "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
-; "abort ();"
+; "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
+; "gcc_unreachable ();"
; )
(define_insn "*mov_scc"
(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)))]
)
}"
)
-(define_insn "*call_reg"
+(define_insn "*call_reg_armv5"
[(call (mem:SI (match_operand:SI 0 "s_register_operand" "r"))
(match_operand 1 "" ""))
(use (match_operand 2 "" ""))
(clobber (reg:SI LR_REGNUM))]
- "TARGET_ARM"
+ "TARGET_ARM && arm_arch5"
+ "blx%?\\t%0"
+ [(set_attr "type" "call")]
+)
+
+(define_insn "*call_reg_arm"
+ [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r"))
+ (match_operand 1 "" ""))
+ (use (match_operand 2 "" ""))
+ (clobber (reg:SI LR_REGNUM))]
+ "TARGET_ARM && !arm_arch5"
"*
return output_call (operands);
"
(set_attr "type" "call")]
)
-(define_insn "*call_indirect"
+(define_insn "*call_reg_thumb_v5"
[(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
(match_operand 1 "" ""))
(use (match_operand 2 "" ""))
(clobber (reg:SI LR_REGNUM))]
- "TARGET_THUMB"
- "*
- {
- if (TARGET_CALLER_INTERWORKING)
- return \"bl\\t%__interwork_call_via_%0\";
- else
- return \"bl\\t%__call_via_%0\";
- }"
- [(set_attr "type" "call")]
+ "TARGET_THUMB && arm_arch5"
+ "blx\\t%0"
+ [(set_attr "length" "2")
+ (set_attr "type" "call")]
)
-(define_insn "*call_value_indirect"
- [(set (match_operand 0 "" "")
- (call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
- (match_operand 2 "" "")))
- (use (match_operand 3 "" ""))
+(define_insn "*call_reg_thumb"
+ [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
+ (match_operand 1 "" ""))
+ (use (match_operand 2 "" ""))
(clobber (reg:SI LR_REGNUM))]
- "TARGET_THUMB"
+ "TARGET_THUMB && !arm_arch5"
"*
{
- if (TARGET_CALLER_INTERWORKING)
- return \"bl\\t%__interwork_call_via_%1\";
+ if (!TARGET_CALLER_INTERWORKING)
+ return thumb_call_via_reg (operands[0]);
+ else if (operands[1] == const0_rtx)
+ return \"bl\\t%__interwork_call_via_%0\";
+ else if (frame_pointer_needed)
+ return \"bl\\t%__interwork_r7_call_via_%0\";
else
- return \"bl\\t%__call_via_%1\";
+ return \"bl\\t%__interwork_r11_call_via_%0\";
}"
[(set_attr "type" "call")]
)
}"
)
-(define_insn "*call_value_reg"
+(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]);
"
(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 "" ""))
- (match_operand 1 "" ""))
- (use (match_operand 2 "" ""))
+(define_insn "*call_value_reg_thumb_v5"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
+ (match_operand 2 "" "")))
+ (use (match_operand 3 "" ""))
(clobber (reg:SI LR_REGNUM))]
- "TARGET_ARM
- && (GET_CODE (operands[0]) == SYMBOL_REF)
- && !arm_is_longcall_p (operands[0], INTVAL (operands[2]), 1)"
+ "TARGET_THUMB && arm_arch5"
+ "blx\\t%1"
+ [(set_attr "length" "2")
+ (set_attr "type" "call")]
+)
+
+(define_insn "*call_value_reg_thumb"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
+ (match_operand 2 "" "")))
+ (use (match_operand 3 "" ""))
+ (clobber (reg:SI LR_REGNUM))]
+ "TARGET_THUMB && !arm_arch5"
+ "*
+ {
+ if (!TARGET_CALLER_INTERWORKING)
+ return thumb_call_via_reg (operands[1]);
+ else if (operands[2] == const0_rtx)
+ return \"bl\\t%__interwork_call_via_%1\";
+ else if (frame_pointer_needed)
+ return \"bl\\t%__interwork_r7_call_via_%1\";
+ else
+ return \"bl\\t%__interwork_r11_call_via_%1\";
+ }"
+ [(set_attr "type" "call")]
+)
+
+;; Allow calls to SYMBOL_REFs specially as they are not valid general addresses
+;; The 'a' causes the operand to be treated as an address, i.e. no '#' output.
+
+(define_insn "*call_symbol"
+ [(call (mem:SI (match_operand:SI 0 "" ""))
+ (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)"
"*
{
return NEED_PLT_RELOC ? \"bl%?\\t%a0(PLT)\" : \"bl%?\\t%a0\";
)
(define_insn "*call_value_symbol"
- [(set (match_operand 0 "s_register_operand" "")
+ [(set (match_operand 0 "" "")
(call (mem:SI (match_operand:SI 1 "" ""))
(match_operand:SI 2 "" "")))
(use (match_operand 3 "" ""))
)
(define_insn "*call_value_insn"
- [(set (match_operand 0 "register_operand" "")
+ [(set (match_operand 0 "" "")
(call (mem:SI (match_operand 1 "" ""))
(match_operand 2 "" "")))
(use (match_operand 3 "" ""))
)
(define_expand "sibcall_value"
- [(parallel [(set (match_operand 0 "register_operand" "")
+ [(parallel [(set (match_operand 0 "" "")
(call (match_operand 1 "memory_operand" "")
(match_operand 2 "general_operand" "")))
(return)
)
(define_insn "*sibcall_value_insn"
- [(set (match_operand 0 "s_register_operand" "")
+ [(set (match_operand 0 "" "")
(call (mem:SI (match_operand:SI 1 "" "X"))
(match_operand 2 "" "")))
(return)
return output_return_instruction (operands[0], TRUE, TRUE);
}"
[(set_attr "conds" "use")
+ (set_attr "length" "12")
(set_attr "type" "load1")]
)
(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);
- emit_move_insn (SET_DEST (set), SET_SRC (set));
+ XVECEXP (par, 0, i) = gen_rtx_EXPR_LIST (VOIDmode, src,
+ GEN_INT (size));
+ size += GET_MODE_SIZE (GET_MODE (src));
+ }
+
+ emit_call_insn (GEN_CALL_VALUE (par, operands[0], const0_rtx, NULL,
+ const0_rtx));
+
+ size = 0;
+
+ for (i = 0; i < XVECLEN (par, 0); i++)
+ {
+ HOST_WIDE_INT offset = 0;
+ rtx reg = XEXP (XVECEXP (par, 0, i), 0);
+
+ if (size != 0)
+ emit_move_insn (addr, plus_constant (addr, size));
+
+ 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
}"
)
+(define_expand "untyped_return"
+ [(match_operand:BLK 0 "memory_operand" "")
+ (match_operand 1 "" "")]
+ "TARGET_EITHER"
+ "
+ {
+ int i;
+ rtx addr = gen_reg_rtx (Pmode);
+ rtx mem;
+ int size = 0;
+
+ emit_move_insn (addr, XEXP (operands[0], 0));
+ mem = change_address (operands[0], BLKmode, addr);
+
+ for (i = 0; i < XVECLEN (operands[1], 0); i++)
+ {
+ HOST_WIDE_INT offset = 0;
+ rtx reg = SET_DEST (XVECEXP (operands[1], 0, i));
+
+ if (size != 0)
+ emit_move_insn (addr, plus_constant (addr, size));
+
+ mem = change_address (mem, GET_MODE (reg), NULL);
+ if (REGNO (reg) == R0_REGNUM)
+ {
+ /* On thumb we have to use a write-back instruction. */
+ emit_insn (arm_gen_load_multiple (R0_REGNUM, 4, addr, TRUE,
+ TARGET_THUMB ? TRUE : FALSE, mem, &offset));
+ size = TARGET_ARM ? 16 : 0;
+ }
+ else
+ {
+ emit_move_insn (reg, mem);
+ size = GET_MODE_SIZE (GET_MODE (reg));
+ }
+ }
+
+ /* Emit USE insns before the return. */
+ for (i = 0; i < XVECLEN (operands[1], 0); i++)
+ emit_insn (gen_rtx_USE (VOIDmode,
+ SET_DEST (XVECEXP (operands[1], 0, i))));
+
+ /* Construct the return. */
+ expand_naked_return ();
+
+ DONE;
+ }"
+)
+
;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
;; all of memory. This blocks insns from being moved across this point.
""
)
+;; NB Never uses BX.
(define_insn "*arm_indirect_jump"
[(set (pc)
(match_operand:SI 0 "s_register_operand" "r"))]
[(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"))]
(set_attr "predicable" "yes")]
)
+;; NB Never uses BX.
(define_insn "*thumb_indirect_jump"
[(set (pc)
(match_operand:SI 0 "register_operand" "l*r"))]
{
rtx ldm[3];
rtx arith[4];
- int val1 = 0, val2 = 0;
+ rtx base_reg;
+ HOST_WIDE_INT val1 = 0, val2 = 0;
if (REGNO (operands[0]) > REGNO (operands[4]))
{
ldm[1] = operands[0];
ldm[2] = operands[4];
}
- if (GET_CODE (XEXP (operands[2], 0)) != REG)
- val1 = INTVAL (XEXP (XEXP (operands[2], 0), 1));
- if (GET_CODE (XEXP (operands[3], 0)) != REG)
+
+ base_reg = XEXP (operands[2], 0);
+
+ if (!REG_P (base_reg))
+ {
+ val1 = INTVAL (XEXP (base_reg, 1));
+ base_reg = XEXP (base_reg, 0);
+ }
+
+ if (!REG_P (XEXP (operands[3], 0)))
val2 = INTVAL (XEXP (XEXP (operands[3], 0), 1));
+
arith[0] = operands[0];
arith[3] = operands[1];
+
if (val1 < val2)
{
arith[1] = ldm[1];
arith[1] = ldm[2];
arith[2] = ldm[1];
}
- if (val1 && val2)
+
+ ldm[0] = base_reg;
+ if (val1 !=0 && val2 != 0)
{
- rtx ops[3];
- ldm[0] = ops[0] = operands[4];
- ops[1] = XEXP (XEXP (operands[2], 0), 0);
- ops[2] = XEXP (XEXP (operands[2], 0), 1);
- output_add_immediate (ops);
- if (val1 < val2)
- output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm);
+ if (val1 == 4 || val2 == 4)
+ /* Other val must be 8, since we know they are adjacent and neither
+ is zero. */
+ output_asm_insn (\"ldm%?ib\\t%0, {%1, %2}\", ldm);
else
- output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm);
+ {
+ rtx ops[3];
+
+ ldm[0] = ops[0] = operands[4];
+ ops[1] = base_reg;
+ ops[2] = GEN_INT (val1);
+ output_add_immediate (ops);
+ if (val1 < val2)
+ output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm);
+ else
+ output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm);
+ }
}
- else if (val1)
+ else if (val1 != 0)
{
- ldm[0] = XEXP (operands[3], 0);
if (val1 < val2)
output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm);
else
}
else
{
- ldm[0] = XEXP (operands[2], 0);
if (val1 < val2)
output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm);
else
(set_attr "type" "load1")]
)
-;; 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_byte")
- (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_byte")
- (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_byte")
- (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_byte")
- (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" "load1")
- (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" "load1")
- (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_byte")
- (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_byte")
- (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_byte")
- (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_byte")
- (set_attr "predicable" "yes")]
-)
-
-(define_insn "*strsi_shiftpreinc"
- [(set (mem:SI (plus:SI (match_operator:SI 2 "shift_operator"
- [(match_operand:SI 3 "s_register_operand" "r")
- (match_operand:SI 4 "const_shift_operand" "n")])
- (match_operand:SI 1 "s_register_operand" "0")))
- (match_operand:SI 5 "s_register_operand" "r"))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)])
- (match_dup 1)))]
- "TARGET_ARM
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
- "str%?\\t%5, [%0, %3%S2]!"
- [(set_attr "type" "store1")
- (set_attr "predicable" "yes")]
-)
-
-(define_insn "*strsi_shiftpredec"
- [(set (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
- (match_operator:SI 2 "shift_operator"
- [(match_operand:SI 3 "s_register_operand" "r")
- (match_operand:SI 4 "const_shift_operand" "n")])))
- (match_operand:SI 5 "s_register_operand" "r"))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3)
- (match_dup 4)])))]
- "TARGET_ARM
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
- "str%?\\t%5, [%0, -%3%S2]!"
- [(set_attr "type" "store1")
- (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadsi_shiftpreinc"
- [(set (match_operand:SI 5 "s_register_operand" "=r")
- (mem:SI (plus:SI (match_operator:SI 2 "shift_operator"
- [(match_operand:SI 3 "s_register_operand" "r")
- (match_operand:SI 4 "const_shift_operand" "n")])
- (match_operand:SI 1 "s_register_operand" "0"))))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)])
- (match_dup 1)))]
- "TARGET_ARM
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
- "ldr%?\\t%5, [%0, %3%S2]!"
- [(set_attr "type" "load1")
- (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadsi_shiftpredec"
- [(set (match_operand:SI 5 "s_register_operand" "=r")
- (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
- (match_operator:SI 2 "shift_operator"
- [(match_operand:SI 3 "s_register_operand" "r")
- (match_operand:SI 4 "const_shift_operand" "n")]))))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3)
- (match_dup 4)])))]
- "TARGET_ARM
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
- "ldr%?\\t%5, [%0, -%3%S2]!"
- [(set_attr "type" "load1")
- (set_attr "predicable" "yes")])
-
-(define_insn "*loadhi_shiftpreinc"
- [(set (match_operand:HI 5 "s_register_operand" "=r")
- (mem:HI (plus:SI (match_operator:SI 2 "shift_operator"
- [(match_operand:SI 3 "s_register_operand" "r")
- (match_operand:SI 4 "const_shift_operand" "n")])
- (match_operand:SI 1 "s_register_operand" "0"))))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)])
- (match_dup 1)))]
- "TARGET_ARM
- && !BYTES_BIG_ENDIAN
- && !TARGET_MMU_TRAPS
- && !arm_arch4
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
- "ldr%?\\t%5, [%0, %3%S2]!\\t%@ loadhi"
- [(set_attr "type" "load_byte")
- (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadhi_shiftpredec"
- [(set (match_operand:HI 5 "s_register_operand" "=r")
- (mem:HI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
- (match_operator:SI 2 "shift_operator"
- [(match_operand:SI 3 "s_register_operand" "r")
- (match_operand:SI 4 "const_shift_operand" "n")]))))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3)
- (match_dup 4)])))]
- "TARGET_ARM
- && !BYTES_BIG_ENDIAN
- && !TARGET_MMU_TRAPS
- && !arm_arch4
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
- "ldr%?\\t%5, [%0, -%3%S2]!\\t%@ loadhi"
- [(set_attr "type" "load_byte")
- (set_attr "predicable" "yes")]
-)
-
-; It can also support extended post-inc expressions, but combine doesn't
-; try these....
-; It doesn't seem worth adding peepholes for anything but the most common
-; cases since, unlike combine, the increment must immediately follow the load
-; for this pattern to match.
-; We must watch to see that the source/destination register isn't also the
-; same as the base address register, and that if the index is a register,
-; that it is not the same as the base address register. In such cases the
-; instruction that we would generate would have UNPREDICTABLE behavior so
-; we cannot use it.
-
-(define_peephole
- [(set (mem:QI (match_operand:SI 0 "s_register_operand" "+r"))
- (match_operand:QI 2 "s_register_operand" "r"))
- (set (match_dup 0)
- (plus:SI (match_dup 0) (match_operand:SI 1 "index_operand" "rJ")))]
- "TARGET_ARM
- && (REGNO (operands[2]) != REGNO (operands[0]))
- && (GET_CODE (operands[1]) != REG
- || (REGNO (operands[1]) != REGNO (operands[0])))"
- "str%?b\\t%2, [%0], %1"
-)
-
-(define_peephole
- [(set (match_operand:QI 0 "s_register_operand" "=r")
- (mem:QI (match_operand:SI 1 "s_register_operand" "+r")))
- (set (match_dup 1)
- (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))]
- "TARGET_ARM
- && REGNO (operands[0]) != REGNO(operands[1])
- && (GET_CODE (operands[2]) != REG
- || REGNO(operands[0]) != REGNO (operands[2]))"
- "ldr%?b\\t%0, [%1], %2"
-)
-
-(define_peephole
- [(set (mem:SI (match_operand:SI 0 "s_register_operand" "+r"))
- (match_operand:SI 2 "s_register_operand" "r"))
- (set (match_dup 0)
- (plus:SI (match_dup 0) (match_operand:SI 1 "index_operand" "rJ")))]
- "TARGET_ARM
- && (REGNO (operands[2]) != REGNO (operands[0]))
- && (GET_CODE (operands[1]) != REG
- || (REGNO (operands[1]) != REGNO (operands[0])))"
- "str%?\\t%2, [%0], %1"
-)
-
-(define_peephole
- [(set (match_operand:HI 0 "s_register_operand" "=r")
- (mem:HI (match_operand:SI 1 "s_register_operand" "+r")))
- (set (match_dup 1)
- (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))]
- "TARGET_ARM
- && !BYTES_BIG_ENDIAN
- && !TARGET_MMU_TRAPS
- && !arm_arch4
- && REGNO (operands[0]) != REGNO(operands[1])
- && (GET_CODE (operands[2]) != REG
- || REGNO(operands[0]) != REGNO (operands[2]))"
- "ldr%?\\t%0, [%1], %2\\t%@ loadhi"
-)
-
-(define_peephole
- [(set (match_operand:SI 0 "s_register_operand" "=r")
- (mem:SI (match_operand:SI 1 "s_register_operand" "+r")))
- (set (match_dup 1)
- (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))]
- "TARGET_ARM
- && REGNO (operands[0]) != REGNO(operands[1])
- && (GET_CODE (operands[2]) != REG
- || REGNO(operands[0]) != REGNO (operands[2]))"
- "ldr%?\\t%0, [%1], %2"
-)
-
-(define_peephole
- [(set (mem:QI (plus:SI (match_operand:SI 0 "s_register_operand" "+r")
- (match_operand:SI 1 "index_operand" "rJ")))
- (match_operand:QI 2 "s_register_operand" "r"))
- (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))]
- "TARGET_ARM
- && (REGNO (operands[2]) != REGNO (operands[0]))
- && (GET_CODE (operands[1]) != REG
- || (REGNO (operands[1]) != REGNO (operands[0])))"
- "str%?b\\t%2, [%0, %1]!"
-)
-
-(define_peephole
- [(set (mem:QI (plus:SI (match_operator:SI 4 "shift_operator"
- [(match_operand:SI 0 "s_register_operand" "r")
- (match_operand:SI 1 "const_int_operand" "n")])
- (match_operand:SI 2 "s_register_operand" "+r")))
- (match_operand:QI 3 "s_register_operand" "r"))
- (set (match_dup 2) (plus:SI (match_op_dup 4 [(match_dup 0) (match_dup 1)])
- (match_dup 2)))]
- "TARGET_ARM
- && (REGNO (operands[3]) != REGNO (operands[2]))
- && (REGNO (operands[0]) != REGNO (operands[2]))"
- "str%?b\\t%3, [%2, %0%S4]!"
-)
-
; 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_HARD_FLOAT && TARGET_MAVERICK)
- || (!cirrus_fp_register (operands[0], SImode)
- && !cirrus_fp_register (operands[1], SImode)))
- "
+ "TARGET_ARM"
[(parallel [(set (reg:CC CC_REGNUM) (compare:CC (match_dup 1) (const_int 0)))
(set (match_dup 0) (match_dup 1))])]
""
)
(define_expand "epilogue"
- [(unspec_volatile [(return)] VUNSPEC_EPILOGUE)]
+ [(clobber (const_int 0))]
"TARGET_EITHER"
"
+ if (current_function_calls_eh_return)
+ emit_insn (gen_prologue_use (gen_rtx_REG (Pmode, 2)));
if (TARGET_THUMB)
thumb_expand_epilogue ();
else if (USE_RETURN_INSN (FALSE))
(define_insn "align_8"
[(unspec_volatile [(const_int 0)] VUNSPEC_ALIGN8)]
- "TARGET_REALLY_IWMMXT"
+ "TARGET_EITHER"
"*
assemble_align (64);
return \"\";
"
)
+;; NB never uses BX.
(define_insn "*thumb_tablejump"
[(set (pc) (match_operand:SI 0 "register_operand" "l*r"))
(use (label_ref (match_operand 1 "" "")))]
"%@ %0 needed for prologue"
)
+
+;; Patterns for exception handling
+
+(define_expand "eh_return"
+ [(use (match_operand 0 "general_operand" ""))]
+ "TARGET_EITHER"
+ "
+ {
+ if (TARGET_ARM)
+ emit_insn (gen_arm_eh_return (operands[0]));
+ else
+ emit_insn (gen_thumb_eh_return (operands[0]));
+ DONE;
+ }"
+)
+
+;; We can't expand this before we know where the link register is stored.
+(define_insn_and_split "arm_eh_return"
+ [(unspec_volatile [(match_operand:SI 0 "s_register_operand" "r")]
+ VUNSPEC_EH_RETURN)
+ (clobber (match_scratch:SI 1 "=&r"))]
+ "TARGET_ARM"
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
+ "
+ {
+ arm_set_return_address (operands[0], operands[1]);
+ DONE;
+ }"
+)
+
+(define_insn_and_split "thumb_eh_return"
+ [(unspec_volatile [(match_operand:SI 0 "s_register_operand" "l")]
+ VUNSPEC_EH_RETURN)
+ (clobber (match_scratch:SI 1 "=&l"))]
+ "TARGET_THUMB"
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
+ "
+ {
+ thumb_set_return_address (operands[0], operands[1]);
+ DONE;
+ }"
+)
+
;; Load the FPA co-processor patterns
(include "fpa.md")
;; Load the Maverick co-processor patterns