summaryrefslogtreecommitdiff
path: root/gcc/config/epiphany/epiphany.md
diff options
context:
space:
mode:
authoraldyh <aldyh@138bc75d-0d04-0410-961f-82ee72b054a4>2011-11-08 03:20:30 +0000
committeraldyh <aldyh@138bc75d-0d04-0410-961f-82ee72b054a4>2011-11-08 03:20:30 +0000
commit643df0593c630691fa6877cddeefdd4c3023d444 (patch)
tree1eb48ad31d05a9ce117bedc17115de96dffa2f0b /gcc/config/epiphany/epiphany.md
parent54f3f029d816c6d1626310649adfda740e203f7b (diff)
parentd5d8f1ccc6d3972dc5cfc0949e85e0b1c9e24ee0 (diff)
downloadgcc-643df0593c630691fa6877cddeefdd4c3023d444.tar.gz
* Merge from mainline rev 181122.transactional-memory
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/transactional-memory@181148 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/epiphany/epiphany.md')
-rw-r--r--gcc/config/epiphany/epiphany.md2447
1 files changed, 2447 insertions, 0 deletions
diff --git a/gcc/config/epiphany/epiphany.md b/gcc/config/epiphany/epiphany.md
new file mode 100644
index 00000000000..c8354e8eddb
--- /dev/null
+++ b/gcc/config/epiphany/epiphany.md
@@ -0,0 +1,2447 @@
+;; Machine description of the Adaptiva epiphany cpu for GNU C compiler
+;; Copyright (C) 1994, 1997, 1998, 1999, 2000, 2004, 2005, 2007, 2009, 2010,
+;; 2011 Free Software Foundation, Inc.
+;; Contributed by Embecosm on behalf of Adapteva, Inc.
+
+;; This file is part of GCC.
+
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>.
+
+;; See file "rtl.def" for documentation on define_insn, match_*, et. al.
+
+(define_constants
+ [(GPR_0 0)
+ (GPR_FP 11)
+ (GPR_IP 12)
+ (GPR_SP 13)
+ (GPR_LR 14)
+ (GPR_16 16)
+ (GPR_18 18)
+ (GPR_20 20)
+ (ARG_POINTER_REGNUM 64)
+ (FRAME_POINTER_REGNUM 65)
+ (CC_REGNUM 66) ;; 66 or 17
+ (CCFP_REGNUM 67) ;; 67 or 18
+ (CONFIG_REGNUM 68)
+ (STATUS_REGNUM 69)
+ (LC_REGNUM 70)
+ (LS_REGNUM 71)
+ (LE_REGNUM 72)
+ (IRET_REGNUM 73)
+ (FP_NEAREST_REGNUM 74)
+ (FP_TRUNCATE_REGNUM 75)
+ (FP_ANYFP_REGNUM 76)
+ (UNKNOWN_REGNUM 77) ; used for addsi3_r and friends
+ ; We represent the return address as an unspec rather than a reg.
+ ; If we used a reg, we could use register elimination, but eliminating
+ ; to GPR_LR would make the latter visible to dataflow, thus making it
+ ; harder to determine when it must be saved.
+ (UNSPEC_RETURN_ADDR 0)
+ (UNSPEC_FP_MODE 1)
+
+ (UNSPECV_GID 0)
+ (UNSPECV_GIE 1)])
+
+;; Insn type. Used to default other attribute values.
+
+(define_attr "type"
+ "move,load,store,cmove,unary,compare,shift,mul,uncond_branch,branch,call,fp,fp_int,misc,sfunc,fp_sfunc,flow"
+ (const_string "misc"))
+
+;; Length (in # bytes)
+
+(define_attr "length" "" (const_int 4))
+
+;; The length here is the length of a single asm.
+
+(define_asm_attributes
+ [(set_attr "length" "4")
+ (set_attr "type" "misc")])
+
+;; pipeline model; so far we have only one.
+(define_attr "pipe_model" "epiphany" (const_string "epiphany"))
+
+(define_attr "rounding" "trunc,nearest"
+ (cond [(ne (symbol_ref "TARGET_ROUND_NEAREST") (const_int 0))
+ (const_string "nearest")]
+ (const_string "trunc")))
+
+(define_attr "fp_mode" "round_unknown,round_nearest,round_trunc,int,caller,none"
+ (cond [(eq_attr "type" "fp,fp_sfunc")
+ (symbol_ref "(enum attr_fp_mode) epiphany_normal_fp_rounding")
+ (eq_attr "type" "call")
+ (symbol_ref "(enum attr_fp_mode) epiphany_normal_fp_mode")
+ (eq_attr "type" "fp_int")
+ (const_string "int")]
+ (const_string "none")))
+
+(include "epiphany-sched.md")
+
+(include "predicates.md")
+(include "constraints.md")
+
+;; modes that are held in a single register, and hence, a word.
+(define_mode_iterator WMODE [SI SF HI QI V2HI V4QI])
+(define_mode_iterator WMODE2 [SI SF HI QI V2HI V4QI])
+
+;; modes that are held in a two single registers
+(define_mode_iterator DWMODE [DI DF V2SI V2SF V4HI V8QI])
+
+;; Double-word mode made up of two single-word mode values.
+(define_mode_iterator DWV2MODE [V2SI V2SF])
+(define_mode_attr vmode_part [(V2SI "si") (V2SF "sf")])
+(define_mode_attr vmode_PART [(V2SI "SI") (V2SF "SF")])
+(define_mode_attr vmode_fp_type [(V2SI "fp_int") (V2SF "fp")])
+(define_mode_attr vmode_ccmode [(V2SI "CC") (V2SF "CC_FP")])
+(define_mode_attr vmode_cc [(V2SI "CC_REGNUM") (V2SF "CCFP_REGNUM")])
+
+;; Move instructions.
+
+(define_expand "mov<mode>"
+ [(set (match_operand:WMODE 0 "general_operand" "")
+ (match_operand:WMODE 1 "general_operand" ""))]
+ ""
+{
+ if (<MODE>mode == V4QImode || <MODE>mode == V2HImode)
+ {
+ operands[0] = simplify_gen_subreg (SImode, operands[0], <MODE>mode, 0);
+ operands[1] = simplify_gen_subreg (SImode, operands[1], <MODE>mode, 0);
+ emit_insn (gen_movsi (operands[0], operands[1]));
+ DONE;
+ }
+ if (GET_CODE (operands[0]) == MEM)
+ operands[1] = force_reg (<MODE>mode, operands[1]);
+ if (<MODE>mode == SImode
+ && (operands[1] == frame_pointer_rtx || operands[1] == arg_pointer_rtx))
+ {
+ rtx reg = operands[0];
+
+ if (!REG_P (reg))
+ reg = gen_reg_rtx (SImode);
+ emit_insn (gen_move_frame (reg, operands[1]));
+ operands[1] = reg;
+ if (operands[0] == reg)
+ DONE;
+ }
+})
+
+(define_insn "*movqi_insn"
+ [(set (match_operand:QI 0 "move_dest_operand" "=Rcs, r, r,r,m")
+ (match_operand:QI 1 "move_src_operand" "Rcs,rU16,Cal,m,r"))]
+;; ??? Needed?
+ "gpr_operand (operands[0], QImode)
+ || gpr_operand (operands[1], QImode)"
+ "@
+ mov %0,%1
+ mov %0,%1
+ mov %0,%1
+ ldrb %0,%1
+ strb %1,%0"
+ [(set_attr "type" "move,move,move,load,store")])
+
+(define_insn_and_split "*movhi_insn"
+ [(set (match_operand:HI 0 "move_dest_operand" "=r, r,r,m")
+ (match_operand:HI 1 "move_src_operand""rU16,Cal,m,r"))]
+ "gpr_operand (operands[0], HImode)
+ || gpr_operand (operands[1], HImode)"
+ "@
+ mov %0,%1
+ mov %0,%%low(%1); %1
+ ldrh %0,%c1
+ strh %1,%c0"
+ "reload_completed && CONSTANT_P (operands[1])
+ && !satisfies_constraint_U16 (operands[1]) && TARGET_SPLIT_LOHI"
+ [(set (match_dup 2) (match_dup 3))]
+ "operands[2] = simplify_gen_subreg (SImode, operands[0], HImode, 0);
+ operands[3] = simplify_gen_subreg (SImode, operands[1], HImode, 0);"
+ [(set_attr "type" "move,move,load,store")])
+
+;; We use a special pattern for a move from the frame pointer to
+;; show the flag clobber that is needed when this move is changed
+;; to an add by register elimination.
+;; ??? A pseudo register might be equivalent to a function invariant,
+;; and thus placed by reload into reg_equiv_invariant; if the pseudo
+;; does not get a hard register, we then end up with the function
+;; invariant in its place, i.e. an unexpected clobber of the flags
+;; register.
+;;
+;; N.B. operand 1 is an operand so that reload will perform elimination.
+;;
+;; The post-reload pattern recognition and splitting is done in frame_move_1.
+(define_insn "move_frame"
+ [(set (match_operand:SI 0 "gpr_operand" "=r")
+ (match_operand:SI 1 "register_operand" "r"))
+ (clobber (reg:CC CC_REGNUM))]
+ "operands[1] == frame_pointer_rtx || operands[1] == arg_pointer_rtx"
+ "#")
+
+(define_insn "movsi_high"
+ [(set (match_operand:SI 0 "gpr_operand" "+r")
+ (ior:SI (and:SI (match_dup 0) (const_int 65535))
+ (high:SI (match_operand:SI 1 "move_src_operand" "i"))))]
+ ""
+ "movt %0, %%high(%1)"
+ [(set_attr "type" "move")
+ (set_attr "length" "4")])
+
+(define_insn "movsi_lo_sum"
+ [(set (match_operand:SI 0 "gpr_operand" "=r")
+ (lo_sum:SI (const_int 0)
+ (match_operand:SI 1 "move_src_operand" "i")))]
+ ""
+ "mov %0, %%low(%1)"
+ [(set_attr "type" "move")
+ (set_attr "length" "4")])
+
+(define_insn_and_split "*movsi_insn"
+ [(set (match_operand:SI 0 "move_dest_operand"
+ "= r, r, r, r, r, r, m, r, Rct")
+ (match_operand:SI 1 "move_src_operand"
+ "rU16Rra,Cm1,Cl1,Cr1,Cal,mSra,rRra,Rct,r"))]
+ "gpr_operand (operands[0], SImode)
+ || gpr_operand (operands[1], SImode)
+ || satisfies_constraint_Sra (operands[1])"
+{
+ switch (which_alternative)
+ {
+ case 0: return "mov %0,%1";
+ case 1: return "add %0,%-,(1+%1)";
+ case 2: operands[1] = GEN_INT (exact_log2 (-INTVAL (operands[1])));
+ return "lsl %0,%-,%1";
+ case 3: operands[1] = GEN_INT (32 - exact_log2 (INTVAL (operands[1]) + 1));
+ return "lsr %0,%-,%1";
+ case 4: return "mov %0,%%low(%1)\;movt %0,%%high(%1) ; %1";
+ case 5: return "ldr %0,%C1";
+ case 6: return "str %1,%C0";
+ case 7: return "movfs %0,%1";
+ case 8: return "movts %0,%1";
+ default: gcc_unreachable ();
+ }
+}
+ "reload_completed && CONSTANT_P (operands[1])
+ && !satisfies_constraint_U16 (operands[1])
+ && !satisfies_constraint_Cm1 (operands[1])
+ && !satisfies_constraint_Cl1 (operands[1])
+ && !satisfies_constraint_Cr1 (operands[1])
+ && TARGET_SPLIT_LOHI"
+ [(match_dup 2) (match_dup 3)]
+ "operands[2] = gen_movsi_lo_sum (operands[0], operands[1]);
+ operands[3] = gen_movsi_high (operands[0], operands[1]);"
+ [(set_attr "type" "move,misc,misc,misc,move,load,store,flow,flow")
+ (set_attr "length" "4,4,4,4,8,4,4,4,4")])
+
+(define_split
+ [(set (match_operand:SI 0 "nonimmediate_operand")
+ (unspec:SI [(const_int 0)] UNSPEC_RETURN_ADDR))]
+ "reload_completed && !MACHINE_FUNCTION (cfun)->lr_clobbered"
+ [(set (match_dup 0) (reg:SI GPR_LR))])
+
+(define_split
+ [(set (match_operand:SI 0 "gpr_operand")
+ (unspec:SI [(const_int 0)] UNSPEC_RETURN_ADDR))]
+ "reload_completed"
+ [(set (match_dup 0) (match_dup 1))]
+{
+ emit_insn (gen_reload_insi_ra (operands[0], operands[1]));
+ DONE;
+})
+
+(define_expand "reload_insi_ra"
+ [(set (match_operand:SI 0 "gpr_operand" "r") (match_operand:SI 1 "" "Sra"))]
+ ""
+{
+ rtx addr
+ = (frame_pointer_needed ? hard_frame_pointer_rtx : stack_pointer_rtx);
+
+ addr = plus_constant (addr, MACHINE_FUNCTION (cfun)->lr_slot_offset);
+ operands[1] = gen_frame_mem (SImode, addr);
+})
+
+;; If the frame pointer elimination offset is zero, we'll use this pattern.
+;; Note that the splitter can accept any gpr in operands[1]; this is
+;; necessary, (e.g. for compile/20021015-1.c -O0,)
+;; because when register elimination cannot be done with the constant
+;; as an immediate operand of the add instruction, reload will resort to
+;; loading the constant into a reload register, using gen_add2_insn to add
+;; the stack pointer, and then use the reload register as new source in
+;; the move_frame pattern.
+(define_insn_and_split "*move_frame_1"
+ [(set (match_operand:SI 0 "gpr_operand" "=r")
+ (match_operand:SI 1 "gpr_operand" "r"))
+ (clobber (reg:CC CC_REGNUM))]
+ "(reload_in_progress || reload_completed)
+ && (operands[1] == stack_pointer_rtx
+ || operands[1] == hard_frame_pointer_rtx)"
+ "#"
+ "reload_in_progress || reload_completed"
+ [(set (match_dup 0) (match_dup 1))])
+
+(define_expand "mov<mode>"
+ [(set (match_operand:DWMODE 0 "general_operand" "")
+ (match_operand:DWMODE 1 "general_operand" ""))]
+ ""
+ "
+{
+ if (GET_MODE_CLASS (<MODE>mode) == MODE_VECTOR_INT
+ || GET_MODE_CLASS (<MODE>mode) == MODE_VECTOR_FLOAT)
+ {
+ if (epiphany_vect_align == 4 && TARGET_SPLIT_VECMOVE_EARLY)
+ {
+ rtx o0l, o0h, o1l, o1h;
+
+ o0l = simplify_gen_subreg (SImode, operands[0], <MODE>mode, 0);
+ o0h = simplify_gen_subreg (SImode, operands[0], <MODE>mode,
+ UNITS_PER_WORD);
+ o1l = simplify_gen_subreg (SImode, operands[1], <MODE>mode, 0);
+ o1h = simplify_gen_subreg (SImode, operands[1], <MODE>mode,
+ UNITS_PER_WORD);
+ if (reg_overlap_mentioned_p (o0l, o1h))
+ {
+ emit_move_insn (o0h, o1h);
+ emit_move_insn (o0l, o1l);
+ }
+ else
+ {
+ emit_move_insn (o0l, o1l);
+ emit_move_insn (o0h, o1h);
+ }
+ DONE;
+ }
+ /* lower_subreg has a tendency to muck up vectorized code.
+ To protect the wide memory accesses, we must use same-size
+ subregs. */
+ if (epiphany_vect_align != 4 /* == 8 */
+ && !reload_in_progress
+ && (GET_CODE (operands[0]) == MEM || GET_CODE (operands[1]) == MEM)
+ && (GET_CODE (operands[0]) != SUBREG
+ || (GET_MODE_SIZE (GET_MODE (SUBREG_REG (operands[0])))
+ != GET_MODE_SIZE (<MODE>mode)
+ && GET_CODE (operands[1]) != SUBREG)))
+ {
+ operands[0]
+ = simplify_gen_subreg (DImode, operands[0], <MODE>mode, 0);
+ operands[1]
+ = simplify_gen_subreg (DImode, operands[1], <MODE>mode, 0);
+ emit_insn (gen_movdi (operands[0], operands[1]));
+ DONE;
+ }
+ }
+ /* Everything except mem = const or mem = mem can be done easily. */
+
+ if (GET_CODE (operands[0]) == MEM)
+ operands[1] = force_reg (<MODE>mode, operands[1]);
+}")
+
+(define_insn_and_split "*mov<mode>_insn"
+ [(set (match_operand:DWMODE 0 "move_dest_operand" "=r, r,r,m")
+ (match_operand:DWMODE 1 "move_double_src_operand" "r,CalE,m,r"))]
+ "(gpr_operand (operands[0], <MODE>mode)
+ || gpr_operand (operands[1], <MODE>mode))"
+ "@
+ #
+ #
+ ldrd %0,%X1
+ strd %1,%X0"
+ "reload_completed
+ && ((!MEM_P (operands[0]) && !MEM_P (operands[1]))
+ || epiphany_vect_align == 4)"
+ [(set (match_dup 2) (match_dup 3))
+ (set (match_dup 4) (match_dup 5))]
+{
+ int word0 = 0, word1 = UNITS_PER_WORD;
+
+ if (post_modify_operand (operands[0], <MODE>mode)
+ || post_modify_operand (operands[1], <MODE>mode))
+ word0 = UNITS_PER_WORD, word1 = 0;
+
+ operands[2] = simplify_gen_subreg (SImode, operands[0], <MODE>mode, word0);
+ operands[3] = simplify_gen_subreg (SImode, operands[1], <MODE>mode, word0);
+ operands[4] = simplify_gen_subreg (SImode, operands[0], <MODE>mode, word1);
+ operands[5] = simplify_gen_subreg (SImode, operands[1], <MODE>mode, word1);
+ if (post_modify_operand (operands[0], <MODE>mode))
+ operands[2]
+ = change_address (operands[2], VOIDmode,
+ plus_constant (XEXP (XEXP (operands[0], 0), 0),
+ UNITS_PER_WORD));
+ if (post_modify_operand (operands[1], <MODE>mode))
+ operands[3]
+ = change_address (operands[3], VOIDmode,
+ plus_constant (XEXP (XEXP (operands[1], 0), 0),
+ UNITS_PER_WORD));
+}
+ [(set_attr "type" "move,move,load,store")
+ (set_attr "length" "8,16,4,4")])
+
+
+(define_insn_and_split "*movsf_insn"
+ [(set (match_operand:SF 0 "move_dest_operand" "=r,r,r,m")
+ (match_operand:SF 1 "move_src_operand" "r,E,m,r"))]
+ "gpr_operand (operands[0], SFmode)
+ || gpr_operand (operands[1], SFmode)"
+ "@
+ mov %0,%1
+ mov %0,%%low(%1)\;movt %0,%%high(%1) ; %1
+ ldr %0,%C1
+ str %1,%C0"
+ "reload_completed && CONSTANT_P (operands[1]) && TARGET_SPLIT_LOHI"
+ [(set (match_dup 2) (match_dup 3))]
+ "operands[2] = simplify_gen_subreg (SImode, operands[0], SFmode, 0);
+ operands[3] = simplify_gen_subreg (SImode, operands[1], SFmode, 0);"
+ [(set_attr "type" "move,move,load,store")
+ (set_attr "length" "4,8,4,4")])
+
+(define_expand "addsi3"
+ [(set (match_operand:SI 0 "add_reg_operand" "")
+ (plus:SI (match_operand:SI 1 "add_reg_operand" "")
+ (match_operand:SI 2 "add_operand" "")))]
+ ""
+ "
+{
+ if (reload_in_progress || reload_completed)
+ emit_insn (gen_addsi3_r (operands[0], operands[1], operands[2]));
+ else
+ emit_insn (gen_addsi3_i (operands[0], operands[1], operands[2]));
+ DONE;
+}")
+
+(define_insn "addsi3_i"
+ [(set (match_operand:SI 0 "add_reg_operand" "=r")
+ (plus:SI (match_operand:SI 1 "add_reg_operand" "%r")
+ (match_operand:SI 2 "add_operand" "rL")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "add %0,%1,%2"
+[(set_attr "type" "misc")])
+
+; We use a clobber of UNKNOWN_REGNUM here so that the peephole optimizers
+; can identify the unresolved flags clobber problem, and also to
+; avoid unwanted matches.
+;
+; At -O0 / -O1 we don't peephole all instances away. We could get better
+; debug unwinding through the emitted code if we added a splitter.
+(define_insn "addsi3_r"
+ [(set (match_operand:SI 0 "gpr_operand" "=r")
+ (plus:SI (match_operand:SI 1 "gpr_operand" "%r")
+ (match_operand:SI 2 "nonmemory_operand" "rCar")))
+ (clobber (reg:CC UNKNOWN_REGNUM))]
+ "reload_in_progress || reload_completed"
+{
+ int scratch = (0x17
+ ^ (true_regnum (operands[0]) & 1)
+ ^ (true_regnum (operands[1]) & 2)
+ ^ (true_regnum (operands[2]) & 4));
+ asm_fprintf (asm_out_file, "\tstr r%d,[sp,#0]\n", scratch);
+ asm_fprintf (asm_out_file, "\tmovfs r%d,status\n", scratch);
+ output_asm_insn ("add %0,%1,%2", operands);
+ asm_fprintf (asm_out_file, "\tmovts status,r%d\n", scratch);
+ asm_fprintf (asm_out_file, "\tldr r%d,[sp,#0]\n", scratch);
+ return "";
+}
+ [(set_attr "length" "20")
+ (set_attr "type" "misc")])
+
+;; reload uses gen_addsi2 because it doesn't understand the need for
+;; the clobber.
+(define_peephole2
+ [(set (match_operand:SI 0 "gpr_operand" "")
+ (match_operand:SI 1 "const_int_operand" ""))
+ (parallel [(set (match_dup 0)
+ (plus:SI (match_dup 0)
+ (match_operand:SI 2 "gpr_operand")))
+ (clobber (reg:CC UNKNOWN_REGNUM))])]
+ "satisfies_constraint_L (operands[1])
+ || ((operands[2] == stack_pointer_rtx
+ || (operands[2] == hard_frame_pointer_rtx && frame_pointer_needed))
+ && !peep2_regno_dead_p (2, CC_REGNUM)
+ && satisfies_constraint_Car (operands[1]))"
+ [(parallel [(set (match_dup 0)
+ (plus:SI (match_dup 2) (match_dup 1)))
+ (clobber (reg:CC UNKNOWN_REGNUM))])]
+ ;; FIXME:
+ ;; need this patch: http://gcc.gnu.org/ml/gcc-patches/2011-10/msg02819.html
+ ;; "peep2_rescan = true;"
+)
+
+(define_peephole2
+ [(match_parallel 5 ""
+ [(set (match_operand 3 "cc_operand" "") (match_operand 4 "" ""))])
+ (parallel [(set (match_operand:SI 0 "gpr_operand" "")
+ (plus:SI (match_operand:SI 1 "gpr_operand" "")
+ (match_operand:SI 2 "nonmemory_operand" "")))
+ (clobber (reg:CC UNKNOWN_REGNUM))])]
+ "REGNO (operands[3]) == CC_REGNUM
+ && (gpr_operand (operands[2], SImode)
+ || satisfies_constraint_L (operands[2]))
+ && !reg_overlap_mentioned_p (operands[0], operands[5])
+ && !reg_set_p (operands[1], operands[5])
+ && !reg_set_p (operands[2], operands[5])"
+ [(parallel [(set (match_operand:SI 0 "gpr_operand" "")
+ (plus:SI (match_operand:SI 1 "gpr_operand" "")
+ (match_operand:SI 2 "nonmemory_operand" "")))
+ (clobber (reg:CC CC_REGNUM))])
+ (match_dup 5)]
+ "")
+
+(define_peephole2
+ [(parallel [(set (match_operand:SI 0 "gpr_operand" "")
+ (plus:SI (match_operand:SI 1 "gpr_operand" "")
+ (match_operand:SI 2 "nonmemory_operand" "")))
+ (clobber (reg:CC UNKNOWN_REGNUM))])]
+ "peep2_regno_dead_p (1, CC_REGNUM)
+ && (gpr_operand (operands[2], SImode)
+ || satisfies_constraint_L (operands[2]))"
+ [(parallel [(set (match_operand:SI 0 "gpr_operand" "")
+ (plus:SI (match_operand:SI 1 "gpr_operand" "")
+ (match_operand:SI 2 "nonmemory_operand" "")))
+ (clobber (reg:CC CC_REGNUM))])]
+ "")
+
+(define_peephole2
+ [(parallel [(set (match_operand:SI 0 "gpr_operand" "")
+ (plus:SI (reg:SI GPR_SP)
+ (match_operand:SI 1 "nonmemory_operand" "")))
+ (clobber (reg:CC UNKNOWN_REGNUM))])]
+ "(REG_P (operands[1]) && !reg_overlap_mentioned_p (operands[0], operands[1]))
+ || RTX_OK_FOR_OFFSET_P (<MODE>mode, operands[1])"
+ [(set (match_dup 0) (reg:SI GPR_SP))
+ (set (mem:WMODE (post_modify (match_dup 0)
+ (plus:SI (match_dup 0) (match_dup 1))))
+ (reg:WMODE GPR_SP))]
+ "")
+
+
+
+(define_peephole2
+ [(parallel [(set (match_operand:SI 0 "gpr_operand" "")
+ (plus:SI (reg:SI GPR_FP)
+ (match_operand:SI 1 "nonmemory_operand" "")))
+ (clobber (reg:CC UNKNOWN_REGNUM))])
+ (match_scratch:WMODE 2 "r")]
+ "frame_pointer_needed
+ && ((REG_P (operands[1])
+ && !reg_overlap_mentioned_p (operands[0], operands[1]))
+ || RTX_OK_FOR_OFFSET_P (<MODE>mode, operands[1]))"
+ [(set (match_dup 0) (reg:SI GPR_FP))
+ (set (match_dup 2)
+ (mem:WMODE (post_modify (match_dup 0)
+ (plus:SI (match_dup 0) (match_dup 1)))))]
+ "")
+
+(define_insn "subsi3"
+ [(set (match_operand:SI 0 "gpr_operand" "=r")
+ (minus:SI (match_operand:SI 1 "add_reg_operand" "r")
+ (match_operand:SI 2 "arith_operand" "rL")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "sub %0,%1,%2"
+ [(set_attr "type" "misc")])
+
+; After mode-switching, floating point operations, fp_sfuncs and calls
+; must exhibit the use of the control register, lest the setting of the
+; control register could be deleted or moved. OTOH a use of a hard register
+; greatly coundounds optimizers like the rtl loop optimizers or combine.
+; Therefore, we put an extra pass immediately after the mode switching pass
+; that inserts the USEs of the control registers, and sets a flag in struct
+; machine_function that float_operation can henceforth only match with that
+; USE.
+
+;; Addition
+(define_expand "addsf3"
+ [(parallel
+ [(set (match_operand:SF 0 "gpr_operand" "")
+ (plus:SF (match_operand:SF 1 "gpr_operand" "")
+ (match_operand:SF 2 "gpr_operand" "")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])])
+
+(define_insn "*addsf3_i"
+ [(match_parallel 3 "float_operation"
+ [(set (match_operand:SF 0 "gpr_operand" "=r")
+ (plus:SF (match_operand:SF 1 "gpr_operand" "%r")
+ (match_operand:SF 2 "gpr_operand" "r")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "fadd %0,%1,%2"
+ [(set_attr "type" "fp")])
+
+;; Subtraction
+(define_expand "subsf3"
+ [(parallel
+ [(set (match_operand:SF 0 "gpr_operand" "")
+ (minus:SF (match_operand:SF 1 "gpr_operand" "")
+ (match_operand:SF 2 "gpr_operand" "")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])])
+
+(define_insn "*subsf3_i"
+ [(match_parallel 3 "float_operation"
+ [(set (match_operand:SF 0 "gpr_operand" "=r")
+ (minus:SF (match_operand:SF 1 "gpr_operand" "r")
+ (match_operand:SF 2 "gpr_operand" "r")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "fsub %0,%1,%2"
+ [(set_attr "type" "fp")])
+
+(define_expand "subsf3_f"
+ [(parallel
+ [(set (reg:CC_FP CCFP_REGNUM)
+ (compare:CC_FP (match_operand:SF 1 "gpr_operand" "r")
+ (match_operand:SF 2 "gpr_operand" "r")))
+ (set (match_operand:SF 0 "gpr_operand" "=r")
+ (minus:SF (match_dup 1) (match_dup 2)))])]
+ "!TARGET_SOFT_CMPSF")
+
+(define_insn "*subsf3_f_i"
+ [(match_parallel 3 "float_operation"
+ [(set (reg:CC_FP CCFP_REGNUM)
+ (compare:CC_FP (match_operand:SF 1 "gpr_operand" "r")
+ (match_operand:SF 2 "gpr_operand" "r")))
+ (set (match_operand:SF 0 "gpr_operand" "=r")
+ (minus:SF (match_dup 1) (match_dup 2)))])]
+ "!TARGET_SOFT_CMPSF"
+ "fsub %0,%1,%2"
+ [(set_attr "type" "fp")])
+
+; There is an fabs instruction, but it has longer latency.
+(define_expand "abssf2"
+ [(set (match_operand:SF 0 "gpr_operand" "")
+ (abs:SF (match_operand:SF 1 "gpr_operand" "")))]
+ ""
+ "
+{
+ rtx op1 = copy_to_mode_reg (SImode, simplify_gen_subreg (SImode, operands[1],
+ SFmode, 0));
+ rtx op0 = simplify_gen_subreg (SImode, operands[0], SFmode, 0);
+
+ emit_insn (gen_ashlsi3 (op1, op1, const1_rtx));
+ emit_insn (gen_lshrsi3 (op0, op1, const1_rtx));
+ DONE;
+}")
+
+;; Multiplication
+(define_expand "mulsf3"
+ [(parallel
+ [(set (match_operand:SF 0 "gpr_operand" "")
+ (mult:SF (match_operand:SF 1 "gpr_operand" "")
+ (match_operand:SF 2 "gpr_operand" "")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])])
+
+(define_insn "*mulsf3_i"
+ [(match_parallel 3 "float_operation"
+ [(set (match_operand:SF 0 "gpr_operand" "=r")
+ (mult:SF (match_operand:SF 1 "gpr_operand" "%r")
+ (match_operand:SF 2 "gpr_operand" "r")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "fmul %0,%1,%2"
+ [(set_attr "type" "fp")])
+
+;; Division
+(define_expand "divsf3"
+ [(set (match_operand:SF 0 "gpr_operand" "")
+ (div:SF (match_operand:SF 1 "gpr_operand" "")
+ (match_operand:SF 2 "gpr_operand" "")))]
+ "flag_reciprocal_math"
+{
+ rtx one = CONST1_RTX (SFmode);
+ rtx dst = operands[0];
+
+ if (rtx_equal_p (dst, operands[1]))
+ {
+ emit_move_insn (dst, one);
+ DONE;
+ }
+ else if (!register_operand (dst, SFmode) && can_create_pseudo_p ())
+ dst = gen_reg_rtx (SFmode);
+ emit_insn (gen_recipsf2 (dst, one, operands[2],
+ sfunc_symbol (\"__fast_recipsf2\")));
+ emit_insn (gen_mulsf3 (operands[0], operands[1], dst));
+ DONE;
+})
+
+;; Before reload, keep the hard reg usage to clobbers so that the loop
+;; optimizers can more easily move this insn.
+;; It would be nicer to use a constraint for a GPR_0 - only register class,
+;; but sched1 can still cause trouble then, and there is no guarantee of
+;; better register allocations.
+;; Neither is there when using the opposite strategy - putting explicit
+;; hard register references into pre-reload rtl.
+(define_expand "recipsf2"
+ [(parallel
+ [(set (match_operand:SF 0 "gpr_operand" "")
+ (div:SF (match_operand:SF 1 "const_float_1_operand" "")
+ (match_operand:SF 2 "move_src_operand" "")))
+ (use (match_operand:SI 3 "move_src_operand" ""))
+ (clobber (reg:SF 0))
+ (clobber (reg:SI 1))
+ (clobber (reg:SF GPR_IP))
+ (clobber (reg:DI GPR_16))
+ (clobber (reg:DI GPR_18))
+ (clobber (reg:SI GPR_20))
+ (clobber (reg:SI GPR_LR))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (reg:CC_FP CCFP_REGNUM))])])
+
+(define_insn_and_split "*recipsf2_1"
+ [(match_parallel 4 "float_operation"
+ [(set (match_operand:SF 0 "gpr_operand" "=r,r")
+ (div:SF (match_operand:SF 1 "const_float_1_operand" "")
+ (match_operand:SF 2 "move_src_operand" "rU16m,rU16mCal")))
+ (use (match_operand:SI 3 "move_src_operand" "rU16m,rU16mCal"))
+ (clobber (reg:SF 0))
+ (clobber (reg:SI 1))
+ (clobber (reg:SF GPR_IP))
+ (clobber (reg:DI GPR_16))
+ (clobber (reg:DI GPR_18))
+ (clobber (reg:SI GPR_20))
+ (clobber (reg:SI GPR_LR))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ "flag_reciprocal_math"
+ "#"
+ "&& reload_completed"
+ [(set (reg:SI 1) (match_dup 3))
+ (set (reg:SF 0) (match_dup 2))
+ (parallel
+ [(set (reg:SF 0)
+ (div:SF (match_dup 1)
+ (reg:SF 0)))
+ (use (reg:SI 1))
+ (clobber (reg:SI GPR_IP))
+ (clobber (reg:DI GPR_16))
+ (clobber (reg:DI GPR_18))
+ (clobber (reg:SI GPR_20))
+ (clobber (reg:SI GPR_LR))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (reg:CC_FP CCFP_REGNUM))
+ (match_dup 5)
+ (match_dup 6)])
+ (set (match_dup 0) (reg:SF 0))]
+ "operands[5] = XVECEXP (operands[4], 0, XVECLEN (operands[4], 0) - 2);
+ operands[6] = XVECEXP (operands[4], 0, XVECLEN (operands[4], 0) - 1);"
+ [(set_attr "type" "fp_sfunc")
+ (set_attr "length" "16,24")])
+
+(define_insn "*recipsf2_2"
+ [(match_parallel 1 "float_operation"
+ [(set (reg:SF 0)
+ (div:SF (match_operand:SF 0 "const_float_1_operand" "")
+ (reg:SF 0)))
+ (use (reg:SI 1))
+ (clobber (reg:SI GPR_IP))
+ (clobber (reg:DI GPR_16))
+ (clobber (reg:DI GPR_18))
+ (clobber (reg:SI GPR_20))
+ (clobber (reg:SI GPR_LR))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ "flag_reciprocal_math"
+ "jalr r1"
+ [(set_attr "type" "fp_sfunc")])
+
+
+;; Fused multiply-add
+(define_expand "fmasf4"
+ [(parallel
+ [(set (match_operand:SF 0 "gpr_operand" "")
+ (fma:SF (match_operand:SF 1 "gpr_operand" "")
+ (match_operand:SF 2 "gpr_operand" "")
+ (match_operand:SF 3 "gpr_operand" "")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ "")
+
+; The multiply operands are commutative, but since they have the
+; same constraints, there is no point in telling reload about this.
+(define_insn "*fmadd"
+ [(match_parallel 4 "float_operation"
+ [(set (match_operand:SF 0 "gpr_operand" "=r")
+ (fma:SF (match_operand:SF 1 "gpr_operand" "r")
+ (match_operand:SF 2 "gpr_operand" "r")
+ (match_operand:SF 3 "gpr_operand" "0")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "fmadd %0,%1,%2"
+ [(set_attr "type" "fp")])
+
+; Once vetorization consistently works for this port, should check
+; if the fmadd / fmsub patterns still serve a purpose. With the
+; introduction of fma / fnma handling by the SSA optimizers,
+; at least scalars should be handled by these optimizers, would
+; have to see how well they do on vectors from auto-vectorization.
+;
+; combiner pattern, also used by vector combiner pattern
+(define_expand "maddsf"
+ [(parallel
+ [(set (match_operand:SF 0 "gpr_operand" "=r")
+ (plus:SF (mult:SF (match_operand:SF 1 "gpr_operand" "r")
+ (match_operand:SF 2 "gpr_operand" "r"))
+ (match_operand:SF 3 "gpr_operand" "0")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ "TARGET_FUSED_MADD")
+
+(define_insn "*maddsf_combine"
+ [(match_parallel 4 "float_operation"
+ [(set (match_operand:SF 0 "gpr_operand" "=r")
+ (plus:SF (mult:SF (match_operand:SF 1 "gpr_operand" "r")
+ (match_operand:SF 2 "gpr_operand" "r"))
+ (match_operand:SF 3 "gpr_operand" "0")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ "TARGET_FUSED_MADD"
+ "fmadd %0,%1,%2"
+ [(set_attr "type" "fp")])
+
+;; Fused multiply-sub
+(define_expand "fnmasf4"
+ [(parallel
+ [(set (match_operand:SF 0 "gpr_operand" "")
+ (fma:SF (neg:SF (match_operand:SF 1 "gpr_operand" ""))
+ (match_operand:SF 2 "gpr_operand" "")
+ (match_operand:SF 3 "gpr_operand" "")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ "")
+
+(define_insn "*fmsub"
+ [(match_parallel 4 "float_operation"
+ [(set (match_operand:SF 0 "gpr_operand" "=r")
+ (fma:SF (neg:SF (match_operand:SF 1 "gpr_operand" "r"))
+ (match_operand:SF 2 "gpr_operand" "r")
+ (match_operand:SF 3 "gpr_operand" "0")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "fmsub %0,%1,%2"
+ [(set_attr "type" "fp")])
+
+(define_insn "*fmsub_combine"
+ [(match_parallel 4 "float_operation"
+ [(set (match_operand:SF 0 "gpr_operand" "=r")
+ (minus:SF (match_operand:SF 3 "gpr_operand" "0")
+ (mult:SF (match_operand:SF 1 "gpr_operand" "r")
+ (match_operand:SF 2 "gpr_operand" "r"))))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ "TARGET_FUSED_MADD"
+ "fmsub %0,%1,%2"
+ [(set_attr "type" "fp")])
+
+;; float / integer conversions
+
+(define_expand "floatsisf2"
+ [(parallel
+ [(set (match_operand:SF 0 "gpr_operand" "")
+ (float:SF (match_operand:SI 1 "gpr_operand" "")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])])
+
+(define_insn "*floatsisf2_i"
+ [(match_parallel 2 "float_operation"
+ [(set (match_operand:SF 0 "gpr_operand" "=r")
+ (float:SF (match_operand:SI 1 "gpr_operand" "r")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "float %0, %1"
+ [(set_attr "type" "fp")])
+
+(define_expand "floatsisf2_cmp"
+ [(parallel
+ [(set (reg:CC_FP CCFP_REGNUM)
+ (compare:CC_FP (float:SF (match_operand:SF 1 "gpr_operand" "r"))
+ (match_dup 2)))
+ (set (match_operand:SF 0 "gpr_operand" "=r")
+ (float:SF (match_dup 1)))])]
+ ""
+ "operands[2] = CONST0_RTX (SFmode);")
+
+(define_insn "*floatsisf2_cmp_i"
+ [(match_parallel 3 "float_operation"
+ [(set (reg:CC_FP CCFP_REGNUM)
+ (compare:CC_FP (float:SF (match_operand:SF 1 "gpr_operand" "r"))
+ (match_operand:SF 2 "const0_operand" "")))
+ (set (match_operand:SF 0 "gpr_operand" "=r")
+ (float:SF (match_dup 1)))])]
+ ""
+ "float %0, %1"
+ [(set_attr "type" "fp")])
+
+(define_expand "floatunssisf2"
+ [(set (match_operand:SF 0 "gpr_operand" "")
+ (float:SF (match_operand:SI 1 "gpr_operand" "")))]
+ "epiphany_normal_fp_rounding == /*FP_MODE_ROUND_TRUNC*/ 2"
+{
+ rtx cst = force_reg (SImode, gen_int_mode (0xb0800000, SImode));
+ rtx tmp = gen_reg_rtx (SImode);
+ rtx cmp = gen_rtx_GTU (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM), const0_rtx);
+
+ if (reg_overlap_mentioned_p (operands[0], operands[1]))
+ operands[1] = copy_to_mode_reg (SImode, operands[1]);
+ emit_insn (gen_floatsisf2 (operands[0], operands[1]));
+ emit_insn (gen_ashrsi3 (tmp, operands[1], GEN_INT (8)));
+ emit_insn (gen_sub_f (tmp, tmp, cst));
+ emit_insn (gen_movsfcc (operands[0], cmp,
+ simplify_gen_subreg (SFmode, tmp, SImode, 0),
+ operands[0]));
+ DONE;
+})
+
+(define_expand "fix_truncsfsi2"
+ [(parallel
+ [(set (match_operand:SI 0 "gpr_operand" "")
+ (fix:SI (match_operand:SF 1 "gpr_operand" "")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])])
+
+(define_insn "*fix_truncsfsi2_i"
+ [(match_parallel 2 "float_operation"
+ [(set (match_operand:SI 0 "gpr_operand" "=r")
+ (fix:SI (match_operand:SF 1 "gpr_operand" "r")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "fix %0, %1"
+ [(set_attr "type" "fp")
+ (set_attr "fp_mode" "round_trunc")])
+
+(define_expand "fixuns_truncsfsi2"
+ [(set (match_operand:SI 0 "gpr_operand" "")
+ (unsigned_fix:SI (match_operand:SF 1 "gpr_operand" "")))]
+ ""
+{
+ if (reg_overlap_mentioned_p (operands[0], operands[1]))
+ operands[1] = copy_to_mode_reg (SImode, operands[1]);
+ if (TARGET_SOFT_CMPSF || optimize_function_for_speed_p (cfun))
+ {
+ rtx op1si;
+ /* By toggling what it to be bit31 before the shift, we get a chance to
+ use a short movt insn. */
+ rtx bit31 = force_reg (SImode, GEN_INT (0x800000));
+ rtx tmp = gen_reg_rtx (SImode);
+ rtx limit = force_reg (SImode, gen_int_mode (0x4f000000, SImode));
+ rtx cmp
+ = gen_rtx_GE (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM), const0_rtx);
+
+ op1si = simplify_gen_subreg (SImode, operands[1], SFmode, 0);
+ emit_insn (gen_fix_truncsfsi2 (operands[0], operands[1]));
+ emit_insn (gen_subsi3 (tmp, op1si, bit31));
+ emit_insn (gen_ashlsi3 (tmp, tmp, GEN_INT (8)));
+ emit_insn (gen_cmpsi_cc_insn (op1si, limit));
+ emit_insn (gen_movsicc (operands[0], cmp, tmp, operands[0]));
+ }
+ else
+ {
+ REAL_VALUE_TYPE offset;
+ rtx limit;
+ rtx tmp = gen_reg_rtx (SFmode);
+ rtx label = gen_label_rtx ();
+ rtx bit31;
+ rtx cc1 = gen_rtx_REG (CC_FPmode, CCFP_REGNUM);
+ rtx cmp = gen_rtx_LT (VOIDmode, cc1, CONST0_RTX (SFmode));
+
+ real_2expN (&offset, 31, SFmode);
+ limit = CONST_DOUBLE_FROM_REAL_VALUE (offset, SFmode);
+ limit = force_reg (SFmode, limit);
+ emit_insn (gen_fix_truncsfsi2 (operands[0], operands[1]));
+ emit_insn (gen_subsf3_f (tmp, operands[1], limit));
+ emit_jump_insn (gen_branch_insn (label, cmp, cc1));
+ bit31 = force_reg (SImode, gen_int_mode (0x80000000, SImode));
+ emit_insn (gen_fix_truncsfsi2 (operands[0], tmp));
+ emit_insn (gen_xorsi3 (operands[0], operands[0], bit31));
+ emit_label (label);
+ }
+ DONE;
+})
+
+(define_insn "*iadd"
+ [(match_parallel 3 "float_operation"
+ [(set (match_operand:SI 0 "gpr_operand" "=r")
+ (plus:SI (match_operand:SI 1 "gpr_operand" "%r")
+ (match_operand:SI 2 "gpr_operand" "r")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "iadd %0, %1, %2"
+ [(set_attr "type" "fp_int")])
+
+(define_insn "*isub"
+ [(match_parallel 3 "float_operation"
+ [(set (match_operand:SI 0 "gpr_operand" "=r")
+ (minus:SI (match_operand:SI 1 "gpr_operand" "r")
+ (match_operand:SI 2 "gpr_operand" "r")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "isub %0, %1, %2"
+ [(set_attr "type" "fp_int")])
+
+(define_expand "mulsi3"
+ [(parallel
+ [(set (match_operand:SI 0 "gpr_operand" "")
+ (mult:SI (match_operand:SI 1 "gpr_operand" "")
+ (match_operand:SI 2 "gpr_operand" "")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])])
+
+(define_insn "*imul"
+ [(match_parallel 3 "float_operation"
+ [(set (match_operand:SI 0 "gpr_operand" "=r")
+ (mult:SI (match_operand:SI 1 "gpr_operand" "%r")
+ (match_operand:SI 2 "gpr_operand" "r")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "imul %0, %1, %2"
+ [(set_attr "type" "fp_int")])
+
+; combiner pattern, also used by vector combiner pattern
+(define_expand "maddsi"
+ [(parallel
+ [(set (match_operand:SI 0 "gpr_operand" "=r")
+ (plus:SI (mult:SI (match_operand:SI 1 "gpr_operand" "r")
+ (match_operand:SI 2 "gpr_operand" "r"))
+ (match_operand:SI 3 "gpr_operand" "0")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ "")
+
+(define_insn "*maddsi_combine"
+ [(match_parallel 4 "float_operation"
+ [(set (match_operand:SI 0 "gpr_operand" "=r")
+ (plus:SI (mult:SI (match_operand:SI 1 "gpr_operand" "r")
+ (match_operand:SI 2 "gpr_operand" "r"))
+ (match_operand:SI 3 "gpr_operand" "0")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "imsub %0, %1, %2"
+ [(set_attr "type" "fp_int")])
+
+(define_insn "*imsub"
+ [(match_parallel 4 "float_operation"
+ [(set (match_operand:SI 0 "gpr_operand" "=r")
+ (minus:SI (match_operand:SI 3 "gpr_operand" "0")
+ (mult:SI (match_operand:SI 1 "gpr_operand" "r")
+ (match_operand:SI 2 "gpr_operand" "r"))))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "imsub %0, %1, %2"
+ [(set_attr "type" "fp_int")])
+
+(define_expand "divsi3"
+ [(parallel
+ [(set (match_operand:SI 0 "move_dest_operand" "")
+ (div:SI (match_operand:SI 1 "move_src_operand" "")
+ (match_operand:SI 2 "move_src_operand" "")))
+ (use (match_dup 3))
+ (clobber (reg:SI 0))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI GPR_IP))
+ (clobber (reg:DI GPR_16))
+ (clobber (reg:DI GPR_18))
+ (clobber (reg:SI GPR_20))
+ (clobber (reg:SI GPR_LR))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "operands[3] = sfunc_symbol (\"__divsi3\");")
+
+;; Before reload, keep the hard reg usage to clobbers so that the loop
+;; optimizers can more easily move this insn.
+(define_insn_and_split "*divsi3_1"
+ [(match_parallel 4 "float_operation"
+ [(set (match_operand:SI 0 "move_dest_operand" "=r,r")
+ (div:SI (match_operand:SI 1 "move_src_operand" "rU16m,rU16mCal")
+ (match_operand:SI 2 "move_src_operand" "rU16m,rU16mCal")))
+ (use (match_operand:SI 3 "call_address_operand" "Csy,r"))
+ (clobber (reg:SI 0))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI GPR_IP))
+ (clobber (reg:DI GPR_16))
+ (clobber (reg:DI GPR_18))
+ (clobber (reg:SI GPR_20))
+ (clobber (reg:SI GPR_LR))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "#"
+ "&& reload_completed"
+ [(set (reg:SI 0) (match_dup 1))
+ (set (reg:SI 1) (match_dup 2))
+ (parallel
+ [(set (reg:SI 0) (div:SI (reg:SI 0) (reg:SI 1)))
+ (use (match_dup 3))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI GPR_IP))
+ (clobber (reg:DI GPR_16))
+ (clobber (reg:DI GPR_18))
+ (clobber (reg:SI GPR_20))
+ (clobber (reg:SI GPR_LR))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (reg:CC_FP CCFP_REGNUM))
+ (match_dup 5)
+ (match_dup 6)])
+ (set (match_dup 0) (reg:SI 0))]
+ "operands[5] = XVECEXP (operands[4], 0, XVECLEN (operands[4], 0) - 2);
+ operands[6] = XVECEXP (operands[4], 0, XVECLEN (operands[4], 0) - 1);"
+ [(set_attr "type" "fp_sfunc")
+ (set_attr "length" "16,24")])
+
+(define_insn "*divsi3_2"
+ [(match_parallel 1 "float_operation"
+ [(set (reg:SI 0) (div:SI (reg:SI 0) (reg:SI 1)))
+ (use (match_operand:SI 0 "call_address_operand" "Csy,r"))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI GPR_IP))
+ (clobber (reg:DI GPR_16))
+ (clobber (reg:DI GPR_18))
+ (clobber (reg:SI GPR_20))
+ (clobber (reg:SI GPR_LR))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "%f0"
+ [(set_attr "type" "fp_sfunc")])
+
+(define_expand "udivsi3"
+ [(parallel
+ [(set (match_operand:SI 0 "move_dest_operand" "")
+ (udiv:SI (match_operand:SI 1 "move_src_operand" "")
+ (match_operand:SI 2 "move_src_operand" "")))
+ (use (match_dup 3))
+ (clobber (reg:SI 0))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI GPR_IP))
+ (clobber (reg:DI GPR_16))
+ (clobber (reg:SI GPR_18))
+ (clobber (reg:SI GPR_LR))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "operands[3] = sfunc_symbol (\"__udivsi3\");")
+
+;; Before reload, keep the hard reg usage to clobbers so that the loop
+;; optimizers can more easily move this insn.
+(define_insn_and_split "*udivsi3_1"
+ [(match_parallel 4 "float_operation"
+ [(set (match_operand:SI 0 "move_dest_operand" "=r,r")
+ (udiv:SI (match_operand:SI 1 "move_src_operand" "rU16m,rU16mCal")
+ (match_operand:SI 2 "move_src_operand" "rU16m,rU16mCal")))
+ (use (match_operand:SI 3 "call_address_operand" "Csy,r"))
+ (clobber (reg:SI 0))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI GPR_IP))
+ (clobber (reg:DI GPR_16))
+ (clobber (reg:SI GPR_18))
+ (clobber (reg:SI GPR_LR))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "#"
+ "&& reload_completed"
+ [(set (reg:SI 0) (match_dup 1))
+ (set (reg:SI 1) (match_dup 2))
+ (parallel
+ [(set (reg:SI 0) (udiv:SI (reg:SI 0) (reg:SI 1)))
+ (use (match_dup 3))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI GPR_IP))
+ (clobber (reg:DI GPR_16))
+ (clobber (reg:SI GPR_18))
+ (clobber (reg:SI GPR_LR))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (reg:CC_FP CCFP_REGNUM))
+ (match_dup 5)
+ (match_dup 6)])
+ (set (match_dup 0) (reg:SI 0))]
+ "operands[5] = XVECEXP (operands[4], 0, XVECLEN (operands[4], 0) - 2);
+ operands[6] = XVECEXP (operands[4], 0, XVECLEN (operands[4], 0) - 1);"
+ [(set_attr "type" "fp_sfunc")
+ (set_attr "length" "16,24")])
+
+(define_insn "*udivsi3_2"
+ [(match_parallel 1 "float_operation"
+ [(set (reg:SI 0) (udiv:SI (reg:SI 0) (reg:SI 1)))
+ (use (match_operand:SI 0 "call_address_operand" "Csy,r"))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI GPR_IP))
+ (clobber (reg:DI GPR_16))
+ (clobber (reg:SI GPR_18))
+ (clobber (reg:SI GPR_LR))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "%f0"
+ [(set_attr "type" "fp_sfunc")])
+
+(define_expand "modsi3"
+ [(parallel
+ [(set (match_operand:SI 0 "move_dest_operand" "")
+ (mod:SI (match_operand:SI 1 "move_src_operand" "")
+ (match_operand:SI 2 "move_src_operand" "")))
+ (use (match_dup 3))
+ (clobber (reg:SI 0))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (clobber (reg:SI GPR_IP))
+ (clobber (reg:DI GPR_16))
+ (clobber (reg:DI GPR_18))
+ (clobber (reg:SI GPR_LR))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "operands[3] = sfunc_symbol (\"__modsi3\");")
+
+;; Before reload, keep the hard reg usage to clobbers so that the loop
+;; optimizers can more easily move this insn.
+(define_insn_and_split "*modsi3_1"
+ [(match_parallel 4 "float_operation"
+ [(set (match_operand:SI 0 "move_dest_operand" "=r,r")
+ (mod:SI (match_operand:SI 1 "move_src_operand" "rU16m,rU16mCal")
+ (match_operand:SI 2 "move_src_operand" "rU16m,rU16mCal")))
+ (use (match_operand:SI 3 "call_address_operand" "Csy,r"))
+ (clobber (reg:SI 0))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (clobber (reg:SI GPR_IP))
+ (clobber (reg:DI GPR_16))
+ (clobber (reg:DI GPR_18))
+ (clobber (reg:SI GPR_LR))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "#"
+ "&& reload_completed"
+ [(set (reg:SI 0) (match_dup 1))
+ (set (reg:SI 1) (match_dup 2))
+ (parallel
+ [(set (reg:SI 0) (mod:SI (reg:SI 0) (reg:SI 1)))
+ (use (match_dup 3))
+ (clobber (reg:SI 2))
+ (clobber (reg:SI GPR_IP))
+ (clobber (reg:DI GPR_16))
+ (clobber (reg:DI GPR_18))
+ (clobber (reg:SI GPR_LR))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (reg:CC_FP CCFP_REGNUM))
+ (match_dup 5)
+ (match_dup 6)])
+ (set (match_dup 0) (reg:SI 0))]
+ "operands[5] = XVECEXP (operands[4], 0, XVECLEN (operands[4], 0) - 2);
+ operands[6] = XVECEXP (operands[4], 0, XVECLEN (operands[4], 0) - 1);"
+ [(set_attr "type" "fp_sfunc")
+ (set_attr "length" "16,24")])
+
+(define_insn "*modsi3_2"
+ [(match_parallel 1 "float_operation"
+ [(set (reg:SI 0) (mod:SI (reg:SI 0) (reg:SI 1)))
+ (use (match_operand:SI 0 "call_address_operand" "Csy,r"))
+ (clobber (reg:SI 2))
+ (clobber (reg:SI GPR_IP))
+ (clobber (reg:DI GPR_16))
+ (clobber (reg:DI GPR_18))
+ (clobber (reg:SI GPR_LR))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "%f0"
+ [(set_attr "type" "fp_sfunc")])
+
+(define_expand "umodsi3"
+ [(parallel
+ [(set (match_operand:SI 0 "move_dest_operand" "")
+ (umod:SI (match_operand:SI 1 "move_src_operand" "")
+ (match_operand:SI 2 "move_src_operand" "")))
+ (use (match_dup 3))
+ (clobber (reg:SI 0))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (clobber (reg:SI GPR_IP))
+ (clobber (reg:DI GPR_16))
+ (clobber (reg:SI GPR_LR))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "operands[3] = sfunc_symbol (\"__umodsi3\");")
+
+;; Before reload, keep the hard reg usage to clobbers so that the loop
+;; optimizers can more easily move this insn.
+(define_insn_and_split "*umodsi3_1"
+ [(match_parallel 4 "float_operation"
+ [(set (match_operand:SI 0 "move_dest_operand" "=r,r")
+ (umod:SI (match_operand:SI 1 "move_src_operand" "rU16m,rU16mCal")
+ (match_operand:SI 2 "move_src_operand" "rU16m,rU16mCal")))
+ (use (match_operand:SI 3 "call_address_operand" "Csy,r"))
+ (clobber (reg:SI 0))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (clobber (reg:SI GPR_IP))
+ (clobber (reg:DI GPR_16))
+ (clobber (reg:SI GPR_LR))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "#"
+ "&& reload_completed"
+ [(set (reg:SI 0) (match_dup 1))
+ (set (reg:SI 1) (match_dup 2))
+ (parallel
+ [(set (reg:SI 0) (umod:SI (reg:SI 0) (reg:SI 1)))
+ (use (match_dup 3))
+ (clobber (reg:SI 2))
+ (clobber (reg:SI GPR_IP))
+ (clobber (reg:DI GPR_16))
+ (clobber (reg:SI GPR_LR))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (reg:CC_FP CCFP_REGNUM))
+ (match_dup 5)
+ (match_dup 6)])
+ (set (match_dup 0) (reg:SI 0))]
+ "operands[5] = XVECEXP (operands[4], 0, XVECLEN (operands[4], 0) - 2);
+ operands[6] = XVECEXP (operands[4], 0, XVECLEN (operands[4], 0) - 1);"
+ [(set_attr "type" "fp_sfunc")
+ (set_attr "length" "16,24")])
+
+(define_insn "*umodsi3_2"
+ [(match_parallel 1 "float_operation"
+ [(set (reg:SI 0) (umod:SI (reg:SI 0) (reg:SI 1)))
+ (use (match_operand:SI 0 "call_address_operand" "Csy,r"))
+ (clobber (reg:SI 2))
+ (clobber (reg:SI GPR_IP))
+ (clobber (reg:DI GPR_16))
+ (clobber (reg:SI GPR_LR))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "%f0"
+ [(set_attr "type" "fp_sfunc")])
+
+; Disable interrupts.
+; Any earlier values read from CONFIG_REGNUM are out of date, since interrupts
+; might have changed settings that we do not want to mess with.
+(define_insn "gid"
+ [(set (reg:SI CONFIG_REGNUM)
+ (unspec_volatile:SI [(const_int 0)] UNSPECV_GID))]
+ ""
+ "gid"
+ [(set_attr "type" "flow")])
+
+; Enable interrupts.
+; Present CONTROL_REGNUM here to make sure it is live before the
+; actual uses in floating point insns / calls are inserted.
+; FWIW, interrupts also do mind what is in the control register.
+(define_insn "gie"
+ [(unspec_volatile [(reg:SI CONFIG_REGNUM)] UNSPECV_GIE)]
+ ""
+ "gie"
+ [(set_attr "type" "flow")])
+
+; Floating point instructions require manipulating the control register.
+; Manipulating the control register needs aritmetic.
+; Arithmetic clobbers flags.
+; The flags are in the status register, which also contains the alternate
+; flag and the interrupt enable/disable bits.
+; saving/restoring status and mixing up the order with gid/gie could
+; lead to disaster.
+; Usually, saving/restoring the status is unnecessary, and will be optimized
+; away. But when we really need it, we must make sure that we don't change
+; anything but the flags.
+; N.B.: We could make the constant easier to load by inverting it, but
+; then we'd need to clobber the saved value - and that would make optimizing
+; away unneeded saves/restores harder / less likely.
+(define_expand "movcc"
+ [(parallel [(set (match_operand:CC 0 "cc_move_operand" "")
+ (match_operand:CC 1 "cc_move_operand" ""))
+ (use (match_dup 2))
+ (clobber (match_scratch:SI 3 "=X, &r"))])]
+ ""
+ "operands[2] = gen_int_mode (~0x10f0, SImode);")
+
+(define_insn "*movcc_i"
+ [(set (match_operand:CC 0 "cc_move_operand" "=r,Rcc")
+ (match_operand:CC 1 "cc_move_operand" "Rcc, r"))
+ (use (match_operand:SI 2 "nonmemory_operand" "X, r"))
+ (clobber (match_scratch:SI 3 "=X, &r"))]
+ ""
+ "@
+ movfs %0,status
+ movfs %3,status\;eor %3,%3,%1\;and %3,%3,%2\;eor %3,%3,%1\;movts status,%3"
+ [(set_attr "type" "flow")
+ (set_attr "length" "20,4")])
+
+(define_insn_and_split "set_fp_mode"
+ [(set (reg:SI FP_NEAREST_REGNUM)
+ (match_operand:SI 0 "set_fp_mode_operand" "rCfm"))
+ (set (reg:SI FP_TRUNCATE_REGNUM) (match_dup 0))
+ (set (reg:SI FP_ANYFP_REGNUM)
+ (match_operand:SI 1 "set_fp_mode_operand" "rCfm"))
+ (use (match_operand:SI 2 "gpr_operand" "r"))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (match_scratch:SI 3 "=&r"))]
+ ""
+ "#"
+ "reload_completed || !rtx_equal_p (operands[0], operands[1])"
+ [(const_int 0)]
+{
+ if (!reload_completed)
+ emit_note (NOTE_INSN_DELETED);
+ else
+ epiphany_expand_set_fp_mode (operands);
+ DONE;
+})
+
+
+;; Boolean instructions.
+;;
+;; We don't define the DImode versions as expand_binop does a good enough job.
+
+(define_insn "andsi3"
+ [(set (match_operand:SI 0 "gpr_operand" "=r")
+ (and:SI (match_operand:SI 1 "gpr_operand" "r")
+ (match_operand:SI 2 "gpr_operand" "r")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "and %0,%1,%2")
+
+(define_insn "iorsi3"
+ [(set (match_operand:SI 0 "gpr_operand" "=r")
+ (ior:SI (match_operand:SI 1 "gpr_operand" "r")
+ (match_operand:SI 2 "gpr_operand" "r")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "orr %0,%1,%2")
+
+(define_insn "xorsi3"
+ [(set (match_operand:SI 0 "gpr_operand" "=r")
+ (xor:SI (match_operand:SI 1 "gpr_operand" "r")
+ (match_operand:SI 2 "gpr_operand" "r")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "eor %0,%1,%2")
+
+(define_expand "one_cmplsi2"
+ [(set (match_operand:SI 0 "gpr_operand" "")
+ (xor:SI (match_operand:SI 1 "gpr_operand" "")
+ (match_dup 2)))]
+ ""
+{
+ if (epiphany_m1reg >= 0)
+ emit_insn (gen_one_cmplsi2_i (operands[0], operands[1]));
+ else
+ emit_insn (gen_xorsi3 (operands[0], operands[1],
+ force_reg (SImode, GEN_INT (-1))));
+ DONE;
+})
+
+; Note that folding this pattern into the xorsi3 pattern would make combine
+; less effective.
+(define_insn "one_cmplsi2_i"
+ [(set (match_operand:SI 0 "gpr_operand" "=r")
+ (not:SI (match_operand:SI 1 "gpr_operand" "r")))
+ (clobber (reg:CC CC_REGNUM))]
+ "epiphany_m1reg >= 0"
+ "eor %0,%1,%-")
+
+;; Shift instructions.
+;; In principle we could support arbitrary symbolic values as shift constant
+;; (truncating the value appropriately), but that would require a suitable
+;; relocation and assembler & linker support.
+(define_insn "ashrsi3"
+ [(set (match_operand:SI 0 "gpr_operand" "=r,r")
+ (ashiftrt:SI (match_operand:SI 1 "gpr_operand" "r,r")
+ (match_operand:SI 2 "arith_operand" "r,K")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "asr %0,%1,%2"
+ [(set_attr "length" "4")
+ (set_attr "type" "shift")])
+
+(define_insn "ashrsi3_tst"
+ [(set (reg:CC CC_REGNUM)
+ (compare:CC
+ (ashiftrt:SI (match_operand:SI 1 "gpr_operand" "r,r")
+ (match_operand:SI 2 "arith_operand" "r,K"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpr_operand" "=r,r")
+ (ashiftrt:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "asr %0,%1,%2"
+ [(set_attr "length" "4")
+ (set_attr "type" "shift")])
+
+;; Logical Shift Right
+(define_insn "lshrsi3"
+ [(set (match_operand:SI 0 "gpr_operand" "=r,r")
+ (lshiftrt:SI (match_operand:SI 1 "gpr_operand" "r,r")
+ (match_operand:SI 2 "arith_operand" "r,K")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "lsr %0,%1,%2"
+ [(set_attr "length" "4")
+ (set_attr "type" "shift")])
+
+(define_insn "lshrsi3_tst"
+ [(set (reg:CC CC_REGNUM)
+ (compare:CC
+ (lshiftrt:SI (match_operand:SI 1 "gpr_operand" "r,r")
+ (match_operand:SI 2 "arith_operand" "r,K"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpr_operand" "=r,r")
+ (lshiftrt:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "lsr %0,%1,%2"
+ [(set_attr "length" "4")
+ (set_attr "type" "shift")])
+
+;; Logical/Arithmetic Shift Left
+(define_insn "ashlsi3"
+ [(set (match_operand:SI 0 "gpr_operand" "=r,r")
+ (ashift:SI (match_operand:SI 1 "gpr_operand" "r,r")
+ (match_operand:SI 2 "arith_operand" "r,K")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "lsl %0,%1,%2"
+ [(set_attr "length" "4")
+ (set_attr "type" "shift")])
+
+(define_insn "*ashlsi_btst"
+ [(set (reg:CC_N_NE CC_REGNUM)
+ (compare:CC_N_NE
+ (zero_extract:SI (match_operand:SI 1 "gpr_operand" "r")
+ (const_int 1)
+ (match_operand 2 "const_int_operand" "K"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 0 "=r"))]
+ ""
+{
+ rtx xop[3];
+
+ xop[0] = operands[0];
+ xop[1] = operands[1];
+ xop[2] = GEN_INT (31-INTVAL (operands[2]));
+ output_asm_insn ("lsl %0,%1,%2", xop);
+ return "";
+})
+
+;; zero extensions
+(define_insn_and_split "zero_extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "@
+ #
+ ldrb %0,%1"
+ "reload_completed
+ ? true_regnum (operands[1]) >= 0
+ : REG_P (operands[1]) && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER"
+ [(parallel [(set (match_dup 0) (ashift:SI (match_dup 2) (const_int 24)))
+ (clobber (reg:CC CC_REGNUM))])
+ (parallel [(set (match_dup 0) (lshiftrt:SI (match_dup 0) (const_int 24)))
+ (clobber (reg:CC CC_REGNUM))])]
+ "operands[2] = simplify_gen_subreg (SImode, operands[1], QImode, 0);")
+
+(define_insn "zero_extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0,m")))]
+ ""
+ "@
+ movt %0, 0
+ ldrh %0,%c1")
+
+
+;; Compare instructions.
+
+(define_insn "cmpsi_cc_insn"
+ [(set (reg:CC CC_REGNUM)
+ (compare:CC (match_operand:SI 0 "add_reg_operand" "r,r")
+ (match_operand:SI 1 "arith_operand" "r,L")))
+ (clobber (match_scratch:SI 2 "=r,r"))]
+ ""
+ "sub %2,%0,%1"
+ [(set_attr "type" "compare")])
+
+(define_insn "sub_f"
+ [(set (reg:CC CC_REGNUM)
+ (compare:CC (match_operand:SI 1 "gpr_operand" "r,r")
+ (match_operand:SI 2 "arith_operand" "r,L")))
+ (set (match_operand:SI 0 "gpr_operand" "=r,r")
+ (minus:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "sub %0,%1,%2"
+ [(set_attr "type" "compare")])
+
+(define_insn "*sub_f_add_imm"
+ [(set (reg:CC CC_REGNUM)
+ (compare:CC (match_operand:SI 1 "gpr_operand" "r")
+ (match_operand:SI 2 "arith_int_operand" "L")))
+ (set (match_operand:SI 0 "gpr_operand" "=r")
+ (plus:SI (match_dup 1) (match_operand:SI 3 "const_int_operand" "L")))]
+ "INTVAL (operands[2]) == -INTVAL (operands[3])"
+ "sub %0,%1,%2"
+ [(set_attr "type" "compare")])
+
+(define_expand "abssi2"
+ [(set (match_dup 2) (const_int 0))
+ (parallel [(set (reg:CC CC_REGNUM)
+ (compare:CC (match_dup 2)
+ (match_operand:SI 1 "nonmemory_operand" "")))
+ (set (match_dup 3)
+ (minus:SI (match_dup 2) (match_dup 1)))])
+ (set (match_operand:SI 0 "gpr_operand" "=r")
+ (if_then_else:SI (gt:SI (reg:CC CC_REGNUM) (const_int 0))
+ (match_dup 3)
+ (match_dup 1)))]
+ "TARGET_CMOVE"
+ "operands[2] = gen_reg_rtx (SImode); operands[3] = gen_reg_rtx (SImode);")
+
+(define_insn "*add_c"
+ [(set (reg:CC_C_LTU CC_REGNUM)
+ (compare:CC_C_LTU
+ (plus:SI (match_operand:SI 1 "gpr_operand" "%r,r")
+ (match_operand:SI 2 "arith_operand" "r,L"))
+ (match_dup 1)))
+ (set (match_operand:SI 0 "gpr_operand" "=r,r")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "add %0,%1,%2"
+ [(set_attr "type" "compare")])
+
+(define_insn "*add_c_rev"
+ [(set (reg:CC_C_LTU CC_REGNUM)
+ (compare:CC_C_LTU
+ (plus:SI (match_operand:SI 1 "gpr_operand" "%r,r")
+ (match_operand:SI 2 "arith_operand" "r,L"))
+ (match_dup 1)))
+ (set (match_operand:SI 0 "gpr_operand" "=r,r")
+ (plus:SI (match_dup 2) (match_dup 1)))]
+ ""
+ "add %0,%1,%2"
+ [(set_attr "type" "compare")])
+
+(define_insn "*sub_c"
+ [(set (reg:CC_C_GTU CC_REGNUM)
+ (compare:CC_C_GTU
+ (minus:SI (match_operand:SI 1 "gpr_operand" "r,r")
+ (match_operand:SI 2 "arith_operand" "r,L"))
+ (match_dup 1)))
+ (set (match_operand:SI 0 "gpr_operand" "=r,r")
+ (minus:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "sub %0,%1,%2"
+ [(set_attr "type" "compare")])
+
+(define_insn "*sub_c_void"
+ [(set (reg:CC_C_GTU CC_REGNUM)
+ (compare:CC_C_GTU
+ (minus:SI (match_operand:SI 1 "gpr_operand" "r,r")
+ (match_operand:SI 2 "arith_operand" "r,L"))
+ (match_dup 1)))
+ (clobber (match_scratch:SI 0 "=r,r"))]
+ ""
+ "sub %0,%1,%2"
+ [(set_attr "type" "compare")])
+
+; floating point comparisons
+
+(define_insn "*cmpsf_cc_insn"
+ [(match_parallel 3 "float_operation"
+ [(set (reg:CC_FP CCFP_REGNUM)
+ (compare:CC_FP (match_operand:SF 0 "gpr_operand" "r")
+ (match_operand:SF 1 "gpr_operand" "r")))
+ (clobber (match_scratch:SF 2 "=r"))])]
+ "!TARGET_SOFT_CMPSF"
+ "fsub %2,%0,%1"
+ [(set_attr "type" "fp")
+ (set_attr "fp_mode" "round_unknown")])
+
+;; ??? do we have to relax the operand0 predicate to immediate_operand
+;; to allow the rtl loop optimizer to generate comparisons? OTOH
+;; we want call_address_operand to enforce valid operands so that
+;; combine won't do silly things, allowing instruction scheduling to do
+;; a proper job.
+(define_insn "*cmpsf_eq"
+ [(set (reg:CC_FP_EQ CC_REGNUM) (compare:CC_FP_EQ (reg:SF 0) (reg:SF 1)))
+ (use (match_operand:SI 0 "call_address_operand" "Csy,r"))
+ (clobber (reg:SI GPR_IP))
+ (clobber (reg:SI GPR_LR))]
+ "TARGET_SOFT_CMPSF"
+ "%f0"
+ [(set_attr "type" "sfunc")])
+
+(define_insn "*cmpsf_gte"
+ [(set (reg:CC_FP_GTE CC_REGNUM) (compare:CC_FP_GTE (reg:SF 0) (reg:SF 1)))
+ (use (match_operand:SI 0 "call_address_operand" "Csy,r"))
+ (clobber (reg:SI GPR_IP))
+ (clobber (reg:SI GPR_LR))]
+ "TARGET_SOFT_CMPSF"
+ "%f0"
+ [(set_attr "type" "sfunc")])
+
+(define_insn "*cmpsf_ord"
+ [(set (reg:CC_FP_ORD CC_REGNUM) (compare:CC_FP_ORD (reg:SF 0) (reg:SF 1)))
+ (use (match_operand:SI 0 "call_address_operand" "Csy,r"))
+ (clobber (reg:SI GPR_IP))
+ (clobber (reg:SI GPR_16))
+ (clobber (reg:SI GPR_LR))]
+ "TARGET_SOFT_CMPSF"
+ "%f0"
+ [(set_attr "type" "sfunc")])
+
+(define_insn "*cmpsf_uneq"
+ [(set (reg:CC_FP_UNEQ CC_REGNUM) (compare:CC_FP_UNEQ (reg:SF 0) (reg:SF 1)))
+ (use (match_operand:SI 0 "call_address_operand" "Csy,r"))
+ (clobber (reg:SI GPR_IP))
+ (clobber (reg:SI GPR_16))
+ (clobber (reg:SI GPR_LR))]
+ "TARGET_SOFT_CMPSF"
+ "%f0"
+ [(set_attr "type" "sfunc")])
+
+;; conditional moves
+
+(define_expand "mov<mode>cc"
+ [(set (match_operand:WMODE 0 "gpr_operand" "")
+ (if_then_else:WMODE (match_operand 1 "comparison_operator" "")
+ (match_operand:WMODE 2 "gpr_operand" "")
+ (match_operand:WMODE 3 "gpr_operand" "")))]
+ "TARGET_CMOVE"
+{
+ rtx cmp_op0 = XEXP (operands[1], 0);
+ rtx cmp_op1 = XEXP (operands[1], 1);
+ enum machine_mode cmp_in_mode;
+ enum rtx_code code = GET_CODE (operands[1]);
+
+ cmp_in_mode = GET_MODE (cmp_op0);
+ if (cmp_in_mode == VOIDmode)
+ cmp_in_mode = GET_MODE (cmp_op0);
+ if (cmp_in_mode == VOIDmode)
+ cmp_in_mode = SImode;
+ /* If the operands are a better match when reversed, swap them now.
+ This allows combine to see the proper comparison codes. */
+ if (rtx_equal_p (operands[0], operands[2])
+ && !rtx_equal_p (operands[0], operands[3]))
+ {
+ rtx tmp = operands[2]; operands[2] = operands[3]; operands[3] = tmp;
+ code = (FLOAT_MODE_P (GET_MODE (cmp_op0))
+ ? reverse_condition_maybe_unordered (code)
+ : reverse_condition (code));
+ }
+
+ if (proper_comparison_operator (operands[1], VOIDmode))
+ operands[1] = gen_rtx_fmt_ee (code, cmp_in_mode, cmp_op0, cmp_op1);
+ else
+ {
+ if (!currently_expanding_to_rtl)
+ {
+ /* ??? It would seem safest to FAIL here, but that would defeat
+ the purpose of having an if-conversion pass; its logic currently
+ assumes that the backend should be safe to insert condition code
+ setting instructions, as the same condition codes were presumably
+ set by the if-conversion input code. */
+ }
+ /* What mode to give as first operand to gen_compare_reg here is
+ debatable. VOIDmode would be minimalist; telling gen_compare_reg
+ to use the mode of CC_REGNUM (or putting it on the comparison
+ operator afterwards) is also a logical choice. OTOH, by using
+ <MODE>mode, we have mode combine opportunities with flag setting
+ operations - if we get some. */
+ operands[1]
+ = gen_compare_reg (<MODE>mode, code, cmp_in_mode, cmp_op0, cmp_op1);
+ }
+})
+
+(define_insn "*mov<mode>cc_insn"
+ [(set (match_operand:WMODE 0 "gpr_operand" "=r")
+ (if_then_else:WMODE (match_operator 3 "proper_comparison_operator"
+ [(match_operand 4 "cc_operand") (const_int 0)])
+ (match_operand:WMODE 1 "gpr_operand" "r")
+ (match_operand:WMODE 2 "gpr_operand" "0")))]
+ "TARGET_CMOVE"
+ "mov%d3 %0,%1"
+ [(set_attr "type" "cmove")])
+
+(define_peephole2
+ [(parallel [(set (match_operand:WMODE 0 "gpr_operand" "")
+ (match_operand:WMODE 1 "" ""))
+ (clobber (match_operand 8 "cc_operand"))])
+ (match_operand 2 "" "")
+ (set (match_operand:WMODE2 3 "gpr_operand" "")
+ (match_operand:WMODE2 9 "gpr_operand" ""))
+ (set (match_dup 3)
+ (if_then_else:WMODE2 (match_operator 5 "proper_comparison_operator"
+ [(match_operand 6 "cc_operand")
+ (match_operand 7 "const0_operand")])
+ (match_operand:WMODE2 4 "nonmemory_operand" "")
+ (match_dup 3)))]
+ "REGNO (operands[0]) == REGNO (operands[9])
+ && peep2_reg_dead_p (3, operands[0])
+ && !reg_set_p (operands[0], operands[2])
+ && !reg_set_p (operands[3], operands[2])
+ && !reg_overlap_mentioned_p (operands[3], operands[2])"
+ [(parallel [(set (match_dup 10) (match_dup 1))
+ (clobber (match_dup 8))])
+ (match_dup 2)
+ (set (match_dup 3)
+ (if_then_else:WMODE2 (match_dup 5) (match_dup 4) (match_dup 3)))]
+{
+ operands[10] = simplify_gen_subreg (<WMODE:MODE>mode, operands[3],
+ <WMODE2:MODE>mode, 0);
+ replace_rtx (operands[2], operands[9], operands[3]);
+ replace_rtx (operands[2], operands[0], operands[10]);
+ gcc_assert (!reg_overlap_mentioned_p (operands[0], operands[2]));
+})
+
+(define_peephole2
+ [(parallel [(set (match_operand 6 "cc_operand") (match_operand 2 "" ""))
+ (set (match_operand:WMODE 0 "gpr_operand" "")
+ (match_operand:WMODE 1 "" ""))])
+ (set (match_operand:WMODE2 3 "gpr_operand" "")
+ (match_operand:WMODE2 4 "gpr_operand"))
+ (set (match_dup 3)
+ (if_then_else:WMODE2 (match_operator 5 "proper_comparison_operator"
+ [(match_dup 6)
+ (match_operand:WMODE 7 "const0_operand")])
+ (match_operand:WMODE2 8 "gpr_operand")
+ (match_dup 3)))]
+ "REGNO (operands[0]) == REGNO (operands[8])
+ && REVERSIBLE_CC_MODE (GET_MODE (operands[6]))
+ && peep2_reg_dead_p (3, operands[6])
+ && peep2_reg_dead_p (3, operands[0])
+ && !reg_overlap_mentioned_p (operands[4], operands[3])"
+ [(parallel [(set (match_dup 6) (match_dup 2))
+ (set (match_dup 9) (match_dup 1))])
+ (set (match_dup 3)
+ (if_then_else:WMODE2 (match_dup 5) (match_dup 4) (match_dup 3)))]
+ "
+{
+ operands[5]
+ = gen_rtx_fmt_ee (REVERSE_CONDITION (GET_CODE (operands[5]),
+ GET_MODE (operands[6])),
+ GET_MODE (operands[5]), operands[6], operands[7]);
+ operands[9] = simplify_gen_subreg (<WMODE:MODE>mode, operands[3],
+ <WMODE2:MODE>mode, 0);
+}")
+
+;; These control RTL generation for conditional jump insns
+
+;; To signal to can_compare_p that the cbranchs?4 patterns work,
+;; they must allow const0_rtx for both comparison operands
+(define_expand "cbranchsi4"
+ [(set (reg CC_REGNUM)
+ (compare (match_operand:SI 1 "add_operand" "")
+ (match_operand:SI 2 "arith_operand" "")))
+ (set (pc)
+ (if_then_else
+ (match_operator 0 "ordered_comparison_operator" [(reg CC_REGNUM)
+ (const_int 0)])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))]
+ ""
+{
+ rtx cmp = gen_compare_reg (VOIDmode, GET_CODE (operands[0]), SImode,
+ operands[1], operands[2]);
+ emit_jump_insn (gen_branch_insn (operands[3], cmp, XEXP (cmp, 0)));
+ DONE;
+})
+
+(define_expand "cbranchsf4"
+ [(set (reg CC_REGNUM)
+ (compare (match_operand:SF 1 "arith_operand" "")
+ (match_operand:SF 2 "arith_operand" "")))
+ (set (pc)
+ (if_then_else
+ (match_operator 0 "comparison_operator" [(reg CC_REGNUM)
+ (const_int 0)])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))]
+ ""
+{
+ rtx cmp = gen_compare_reg (VOIDmode, GET_CODE (operands[0]), SFmode,
+ operands[1], operands[2]);
+ emit_jump_insn (gen_branch_insn (operands[3], cmp, XEXP (cmp, 0)));
+ DONE;
+})
+
+;; Now match both normal and inverted jump.
+
+(define_insn "branch_insn"
+ [(set (pc)
+ (if_then_else (match_operator 1 "proper_comparison_operator"
+ [(match_operand 2 "cc_operand")
+ (const_int 0)])
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "b%d1 %l0"
+ [(set_attr "type" "branch")])
+
+(define_insn "*rev_branch_insn"
+ [(set (pc)
+ (if_then_else (match_operator 1 "proper_comparison_operator"
+ [(reg CC_REGNUM) (const_int 0)])
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+ "b%D1 %l0"
+ [(set_attr "type" "branch")])
+
+;; Unconditional and other jump instructions.
+
+(define_insn "jump"
+ [(set (pc) (label_ref (match_operand 0 "" "")))]
+ ""
+ "b %l0"
+ [(set_attr "type" "uncond_branch")])
+
+(define_insn "indirect_jump"
+ [(set (pc) (match_operand:SI 0 "gpr_operand" "r"))]
+ ""
+ "jr %0"
+ [(set_attr "type" "uncond_branch")])
+
+(define_expand "tablejump"
+ [(parallel [(set (pc) (match_operand:SI 0 "gpr_operand" ""))
+ (use (label_ref (match_operand 1 "" "")))])]
+ ""
+{
+ /* In PIC mode, the table entries are stored PC relative.
+ Convert the relative address to an absolute address. */
+ if (flag_pic)
+ {
+ rtx op1 = gen_rtx_LABEL_REF (Pmode, operands[1]);
+
+ operands[0] = expand_simple_binop (Pmode, PLUS, operands[0],
+ op1, NULL_RTX, 0, OPTAB_DIRECT);
+ }
+})
+
+(define_insn "*tablejump_internal"
+ [(set (pc) (match_operand:SI 0 "gpr_operand" "r"))
+ (use (label_ref (match_operand 1 "" "")))]
+ ""
+ "jr %0;"
+ [(set_attr "type" "uncond_branch")])
+
+(define_insn "*tablejump_hi_internal"
+ [(set (pc) (match_operand:HI 0 "gpr_operand" "r"))
+ (use (label_ref (match_operand 1 "" "")))]
+ "optimize_size && TARGET_SMALL16"
+ "jr %0;"
+ [(set_attr "type" "uncond_branch")])
+
+
+(define_expand "call"
+ ;; operands[1] is stack_size_rtx
+ ;; operands[2] is next_arg_register
+ [(parallel [(call (match_operand:SI 0 "call_operand" "")
+ (match_operand 1 "" ""))
+ (clobber (reg:SI GPR_LR))])]
+ ""
+{
+ bool target_uninterruptible = epiphany_call_uninterruptible_p (operands[0]);
+
+ if (!call_operand (operands[1], VOIDmode))
+ operands[0]
+ = change_address (operands[0], VOIDmode,
+ copy_to_mode_reg (Pmode, XEXP (operands[0], 0)));
+ if (epiphany_uninterruptible_p (current_function_decl)
+ != target_uninterruptible)
+ {
+ emit_insn (target_uninterruptible ? gen_gid (): gen_gie ());
+ emit_call_insn
+ (gen_rtx_PARALLEL
+ (VOIDmode,
+ gen_rtvec (2, gen_rtx_CALL (VOIDmode, operands[0], operands[1]),
+ gen_rtx_CLOBBER (VOIDmode,
+ gen_rtx_REG (SImode, GPR_LR)))));
+ emit_insn (target_uninterruptible ? gen_gie (): gen_gid ());
+ DONE;
+ }
+})
+
+(define_insn "*call_i"
+ [(match_parallel 2 "float_operation"
+ [(call (mem:SI (match_operand:SI 0 "call_address_operand" "Csy,r"))
+ (match_operand 1 "" ""))
+ (clobber (reg:SI GPR_LR))])]
+ ""
+ "%f0"
+ [(set_attr "type" "call")])
+
+(define_expand "sibcall"
+ ;; operands[1] is stack_size_rtx
+ ;; operands[2] is next_arg_register
+ [(parallel [(call (match_operand:SI 0 "call_operand" "")
+ (match_operand 1 "" ""))
+ (return)])]
+ ""
+{
+ bool target_uninterruptible = epiphany_call_uninterruptible_p (operands[0]);
+
+ if (!call_operand (operands[1], VOIDmode))
+ operands[0]
+ = change_address (operands[0], VOIDmode,
+ copy_to_mode_reg (Pmode, XEXP (operands[0], 0)));
+ if (epiphany_uninterruptible_p (current_function_decl)
+ != target_uninterruptible)
+ {
+ emit_insn (target_uninterruptible ? gen_gid (): gen_gie ());
+ emit_call_insn
+ (gen_rtx_PARALLEL
+ (VOIDmode,
+ gen_rtvec (2, gen_rtx_CALL (VOIDmode, operands[0], operands[1]),
+ ret_rtx)));
+ emit_insn (target_uninterruptible ? gen_gie (): gen_gid ());
+ DONE;
+ }
+})
+
+(define_insn "*sibcall_i"
+ [(call (mem:SI (match_operand:SI 0 "call_address_operand" "Csy,Rsc"))
+ (match_operand 1 "" ""))
+ (return)]
+ ""
+ "@
+ b %0
+ jr %0"
+ [(set_attr "type" "call")])
+
+(define_expand "call_value"
+ ;; operand 2 is stack_size_rtx
+ ;; operand 3 is next_arg_register
+ [(parallel [(set (match_operand 0 "gpr_operand" "=r")
+ (call (match_operand:SI 1 "call_operand" "")
+ (match_operand 2 "" "")))
+ (clobber (reg:SI GPR_LR))])]
+ ""
+{
+ bool target_uninterruptible = epiphany_call_uninterruptible_p (operands[1]);
+
+ if (!call_operand (operands[1], VOIDmode))
+ operands[1]
+ = change_address (operands[1], VOIDmode,
+ copy_to_mode_reg (Pmode, XEXP (operands[1], 0)));
+ if (epiphany_uninterruptible_p (current_function_decl)
+ != target_uninterruptible)
+ {
+ emit_insn (target_uninterruptible ? gen_gid (): gen_gie ());
+ emit_call_insn
+ (gen_rtx_PARALLEL
+ (VOIDmode,
+ gen_rtvec (2, gen_rtx_SET
+ (VOIDmode, operands[0],
+ gen_rtx_CALL (VOIDmode, operands[1], operands[2])),
+ gen_rtx_CLOBBER (VOIDmode,
+ gen_rtx_REG (SImode, GPR_LR)))));
+ emit_insn (target_uninterruptible ? gen_gie (): gen_gid ());
+ DONE;
+ }
+})
+
+(define_insn "*call_value_i"
+ [(match_parallel 3 "float_operation"
+ [(set (match_operand 0 "gpr_operand" "=r,r")
+ (call (mem:SI (match_operand:SI 1 "call_address_operand" "Csy,r"))
+ (match_operand 2 "" "")))
+ (clobber (reg:SI GPR_LR))])]
+ ""
+ "%f1"
+ [(set_attr "type" "call")
+ (set_attr "length" "4")])
+
+(define_expand "sibcall_value"
+ ;; operand 2 is stack_size_rtx
+ ;; operand 3 is next_arg_register
+ [(parallel [(set (match_operand 0 "gpr_operand" "=r")
+ (call (match_operand:SI 1 "call_operand" "")
+ (match_operand 2 "" "")))
+ (return)])]
+ ""
+{
+ bool target_uninterruptible = epiphany_call_uninterruptible_p (operands[1]);
+
+ if (!call_operand (operands[1], VOIDmode))
+ operands[1]
+ = change_address (operands[1], VOIDmode,
+ copy_to_mode_reg (Pmode, XEXP (operands[1], 0)));
+ if (epiphany_uninterruptible_p (current_function_decl)
+ != target_uninterruptible)
+ {
+ emit_insn (target_uninterruptible ? gen_gid (): gen_gie ());
+ emit_call_insn
+ (gen_rtx_PARALLEL
+ (VOIDmode,
+ gen_rtvec (2, gen_rtx_SET
+ (VOIDmode, operands[0],
+ gen_rtx_CALL (VOIDmode, operands[1], operands[2])),
+ ret_rtx)));
+ emit_insn (target_uninterruptible ? gen_gie (): gen_gid ());
+ DONE;
+ }
+})
+
+(define_insn "*sibcall_value_i"
+ [(set (match_operand 0 "gpr_operand" "=r,r")
+ (call (mem:SI (match_operand:SI 1 "call_address_operand" "Csy,Rsc"))
+ (match_operand 2 "" "")))
+ (return)]
+ ""
+ "@
+ b %1
+ jr %1"
+ [(set_attr "type" "call")
+ (set_attr "length" "4")])
+
+(define_expand "prologue"
+ [(pc)]
+ ""
+{
+ epiphany_expand_prologue ();
+ DONE;
+})
+
+(define_expand "epilogue"
+ [(pc)]
+ ""
+{
+ epiphany_expand_epilogue (0);
+ DONE;
+})
+
+(define_expand "sibcall_epilogue"
+ [(pc)]
+ ""
+{
+ epiphany_expand_epilogue (1);
+ DONE;
+})
+
+; Since the demise of REG_N_SETS, it is no longer possible to find out
+; in the prologue / epilogue expanders how many times lr is set.
+; Using df_regs_ever_live_p to decide if lr needs saving means that
+; any explicit use of lr will cause it to be saved; hence we cannot
+; represent the blink use in return / sibcall instructions themselves, and
+; instead have to show it in EPILOGUE_USES.
+(define_insn "return_i"
+ [(return)]
+ "reload_completed"
+ "rts"
+ [(set_attr "type" "uncond_branch")])
+
+(define_insn "return_internal_interrupt"
+ [(return)
+ (unspec_volatile [(const_int 0)] 1)]
+ ""
+ "rti"
+ [(set_attr "type" "uncond_branch")])
+
+(define_insn "stack_adjust_add"
+ [(set (reg:SI GPR_SP)
+ (plus:SI (reg:SI GPR_SP) (match_operand:SI 0 "arith_operand" "rL")))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (reg:SI STATUS_REGNUM))
+ (clobber (match_operand:BLK 1 "memory_operand" "=m"))]
+ "reload_completed"
+ "add sp,sp,%0")
+
+(define_insn "stack_adjust_mov"
+ [(set (reg:SI GPR_SP) (reg:SI GPR_FP))
+ (clobber (match_operand:BLK 0 "memory_operand" "=m"))]
+ "reload_completed"
+ "mov sp,fp"
+ [(set_attr "type" "move")])
+
+(define_insn "stack_adjust_str"
+ [(set (match_operand 0 "stacktop_operand" "=m")
+ (match_operand 1 "any_gpr_operand" "r"))
+ (set (reg:SI GPR_SP)
+ (plus:SI (reg:SI GPR_SP) (match_operand:SI 2 "nonmemory_operand" "rn")))
+ (clobber (match_operand:BLK 3 "memory_operand" "=m"))]
+ "reload_completed"
+{
+ return (GET_MODE_SIZE (GET_MODE (operands[0])) <= 4
+ ? \"str %1,%0,%C2\" : \"strd %1,%0,%X2\");
+}
+ [(set_attr "type" "store")])
+
+(define_insn "stack_adjust_ldr"
+ [(set (match_operand:SI 0 "gpr_operand" "=r")
+ (match_operand:SI 1 "stacktop_operand" "m"))
+ (set (reg:SI GPR_SP)
+ (plus:SI (reg:SI GPR_SP) (match_operand:SI 2 "nonmemory_operand" "rn")))
+ (clobber (match_operand:BLK 3 "memory_operand" "=m"))]
+ "reload_completed"
+ "ldr %0,%1,%C2"
+ [(set_attr "type" "load")])
+
+;; Define some fake vector operations so that the vectorizer is happy to use
+;; 64 bit loads/stores.
+(define_expand "vec_unpacks_lo_v4hi"
+ [(match_operand:V2SI 0 "gpr_operand")
+ (match_operand:V4HI 1 "gpr_operand")]
+ ""
+{
+ rtx in = simplify_gen_subreg (SImode, operands[1], V4HImode, 0);
+ rtx outl = simplify_gen_subreg (SImode, operands[0], V2SImode, 0);
+ rtx outh
+ = simplify_gen_subreg (SImode, operands[0], V2SImode, UNITS_PER_WORD);
+
+ if (reg_overlap_mentioned_p (outl, in))
+ in = copy_to_mode_reg (SImode, in);
+ emit_insn (gen_ashlsi3 (outl, in, GEN_INT (16)));
+ emit_insn (gen_ashrsi3 (outl, outl, GEN_INT (16)));
+ emit_insn (gen_ashrsi3 (outh, in, GEN_INT (16)));
+ DONE;
+})
+
+(define_expand "vec_unpacks_hi_v4hi"
+ [(match_operand:V2SI 0 "gpr_operand")
+ (match_operand:V4HI 1 "gpr_operand")]
+ ""
+{
+ rtx in = simplify_gen_subreg (SImode, operands[1], V4HImode, UNITS_PER_WORD);
+ rtx outl = simplify_gen_subreg (SImode, operands[0], V2SImode, 0);
+ rtx outh
+ = simplify_gen_subreg (SImode, operands[0], V2SImode, UNITS_PER_WORD);
+
+ if (reg_overlap_mentioned_p (outl, in))
+ in = copy_to_mode_reg (SImode, in);
+ emit_insn (gen_ashlsi3 (outl, in, GEN_INT (16)));
+ emit_insn (gen_ashrsi3 (outl, outl, GEN_INT (16)));
+ emit_insn (gen_ashrsi3 (outh, in, GEN_INT (16)));
+ DONE;
+})
+
+(define_code_iterator addsub [plus minus])
+
+(define_code_iterator alu_binop
+ [plus minus and ior xor])
+
+(define_code_attr insn_opname
+ [(plus "add") (minus "sub") (mult "mul") (div "div")
+ (and "and") (ior "ior") (xor "xor")])
+
+; You might think that this would work better as a define_expand, but
+; again lower_subreg pessimizes the code if it sees indiviudual operations.
+; We need to keep inputs and outputs as register pairs if we want to
+; get sensible register allocation for double-word load and store operations.
+(define_insn_and_split "<insn_opname>v2si3"
+ [(set (match_operand:V2SI 0 "gpr_operand" "=r")
+ (alu_binop:V2SI (match_operand:V2SI 1 "gpr_operand" "r")
+ (match_operand:V2SI 2 "gpr_operand" "r")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "#"
+ "reload_completed || (epiphany_vect_align == 4 && TARGET_SPLIT_VECMOVE_EARLY)"
+ [(const_int 0)]
+{
+ rtx o0l, o0h, o1l, o1h, o2l, o2h;
+
+ o0l = simplify_gen_subreg (SImode, operands[0], V2SImode, 0);
+ o0h = simplify_gen_subreg (SImode, operands[0], V2SImode, UNITS_PER_WORD);
+ o1l = simplify_gen_subreg (SImode, operands[1], V2SImode, 0);
+ o1h = simplify_gen_subreg (SImode, operands[1], V2SImode, UNITS_PER_WORD);
+ o2l = simplify_gen_subreg (SImode, operands[2], V2SImode, 0);
+ o2h = simplify_gen_subreg (SImode, operands[2], V2SImode, UNITS_PER_WORD);
+ if (reg_overlap_mentioned_p (o0l, o1h))
+ o1h = copy_to_mode_reg (SImode, o1h);
+ if (reg_overlap_mentioned_p (o0l, o2h))
+ o2h = copy_to_mode_reg (SImode, o2h);
+ emit_insn (gen_<insn_opname>si3 (o0l, o1l, o2l));
+ emit_insn (gen_<insn_opname>si3 (o0h, o1h, o2h));
+ DONE;
+}
+ [(set_attr "length" "8")])
+
+(define_expand "<insn_opname>v2sf3"
+ [(parallel
+ [(set (match_operand:V2SF 0 "gpr_operand" "")
+ (addsub:V2SF (match_operand:V2SF 1 "gpr_operand" "")
+ (match_operand:V2SF 2 "gpr_operand" "")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])])
+
+(define_insn_and_split "<insn_opname>v2sf3_i"
+ [(match_parallel 3 "float_operation"
+ [(set (match_operand:V2SF 0 "gpr_operand" "=r")
+ (addsub:V2SF (match_operand:V2SF 1 "gpr_operand" "r")
+ (match_operand:V2SF 2 "gpr_operand" "r")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "#"
+ "reload_completed || (epiphany_vect_align == 4 && TARGET_SPLIT_VECMOVE_EARLY)"
+ [(parallel
+ [(set (match_dup 4) (addsub:SF (match_dup 5) (match_dup 6)))
+ (clobber (reg:CC_FP CCFP_REGNUM))
+ (match_dup 10)
+ (match_dup 11)])
+ (parallel
+ [(set (match_dup 7) (addsub:SF (match_dup 8) (match_dup 9)))
+ (clobber (reg:CC_FP CCFP_REGNUM))
+ (match_dup 10)
+ (match_dup 11)])]
+{
+ operands[4] = simplify_gen_subreg (SFmode, operands[0], V2SFmode, 0);
+ operands[5] = simplify_gen_subreg (SFmode, operands[1], V2SFmode, 0);
+ operands[6] = simplify_gen_subreg (SFmode, operands[2], V2SFmode, 0);
+ operands[7]
+ = simplify_gen_subreg (SFmode, operands[0], V2SFmode, UNITS_PER_WORD);
+ operands[8]
+ = simplify_gen_subreg (SFmode, operands[1], V2SFmode, UNITS_PER_WORD);
+ operands[9]
+ = simplify_gen_subreg (SFmode, operands[2], V2SFmode, UNITS_PER_WORD);
+ if (!reload_completed)
+ {
+ if (reg_overlap_mentioned_p (operands[4], operands[8]))
+ operands[8] = copy_to_mode_reg (SFmode, operands[8]);
+ if (reg_overlap_mentioned_p (operands[4], operands[9]))
+ operands[9] = copy_to_mode_reg (SFmode, operands[9]);
+ emit_insn (gen_<insn_opname>sf3 (operands[4], operands[5], operands[6]));
+ emit_insn (gen_<insn_opname>sf3 (operands[7], operands[8], operands[9]));
+ DONE;
+ }
+ gcc_assert (!reg_overlap_mentioned_p (operands[4], operands[8]));
+ gcc_assert (!reg_overlap_mentioned_p (operands[4], operands[9]));
+ operands[10] = XVECEXP (operands[3], 0, XVECLEN (operands[3], 0) - 2);
+ operands[11] = XVECEXP (operands[3], 0, XVECLEN (operands[3], 0) - 1);
+}
+ [(set_attr "length" "8")
+ (set_attr "type" "fp")])
+
+(define_expand "mul<mode>3"
+ [(parallel
+ [(set (match_operand:DWV2MODE 0 "gpr_operand" "")
+ (mult:DWV2MODE (match_operand:DWV2MODE 1 "gpr_operand" "")
+ (match_operand:DWV2MODE 2 "gpr_operand" "")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])])
+
+(define_insn_and_split "mul<mode>3_i"
+ [(match_parallel 3 "float_operation"
+ [(set (match_operand:DWV2MODE 0 "gpr_operand" "=r")
+ (mult:DWV2MODE (match_operand:DWV2MODE 1 "gpr_operand" "r")
+ (match_operand:DWV2MODE 2 "gpr_operand" "r")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ ""
+ "#"
+ "reload_completed || (epiphany_vect_align == 4 && TARGET_SPLIT_VECMOVE_EARLY)"
+ [(parallel
+ [(set (match_dup 4) (mult:<vmode_PART> (match_dup 5) (match_dup 6)))
+ (clobber (reg:CC_FP CCFP_REGNUM))
+ (match_dup 10)
+ (match_dup 11)])
+ (parallel
+ [(set (match_dup 7) (mult:<vmode_PART> (match_dup 8) (match_dup 9)))
+ (clobber (reg:CC_FP CCFP_REGNUM))
+ (match_dup 10)
+ (match_dup 11)])]
+{
+ operands[4]
+ = simplify_gen_subreg (<vmode_PART>mode, operands[0], <MODE>mode, 0);
+ operands[5]
+ = simplify_gen_subreg (<vmode_PART>mode, operands[1], <MODE>mode, 0);
+ operands[6]
+ = simplify_gen_subreg (<vmode_PART>mode, operands[2], <MODE>mode, 0);
+ operands[7] = simplify_gen_subreg (<vmode_PART>mode, operands[0],
+ <MODE>mode, UNITS_PER_WORD);
+ operands[8] = simplify_gen_subreg (<vmode_PART>mode, operands[1],
+ <MODE>mode, UNITS_PER_WORD);
+ operands[9] = simplify_gen_subreg (<vmode_PART>mode, operands[2],
+ <MODE>mode, UNITS_PER_WORD);
+ if (!reload_completed)
+ {
+ if (reg_overlap_mentioned_p (operands[4], operands[8]))
+ operands[8] = copy_to_mode_reg (<vmode_PART>mode, operands[8]);
+ if (reg_overlap_mentioned_p (operands[4], operands[9]))
+ operands[9] = copy_to_mode_reg (<vmode_PART>mode, operands[9]);
+ emit_insn (gen_mul<vmode_part>3 (operands[4], operands[5], operands[6]));
+ emit_insn (gen_mul<vmode_part>3 (operands[7], operands[8], operands[9]));
+ DONE;
+ }
+ gcc_assert (!reg_overlap_mentioned_p (operands[4], operands[8]));
+ gcc_assert (!reg_overlap_mentioned_p (operands[4], operands[9]));
+ operands[10] = XVECEXP (operands[3], 0, XVECLEN (operands[3], 0) - 2);
+ operands[11] = XVECEXP (operands[3], 0, XVECLEN (operands[3], 0) - 1);
+}
+ [(set_attr "length" "8")
+ (set_attr "type" "<vmode_fp_type>")])
+
+(define_insn_and_split "*fmadd<mode>_combine"
+ [(match_parallel 4 "float_operation"
+ [(set (match_operand:DWV2MODE 0 "gpr_operand" "=r")
+ (plus:DWV2MODE (mult:<MODE>
+ (match_operand:<MODE> 1 "gpr_operand" "r")
+ (match_operand:<MODE> 2 "gpr_operand" "r"))
+ (match_operand:<MODE> 3 "gpr_operand" "0")))
+ (clobber (reg:CC_FP CCFP_REGNUM))])]
+ "TARGET_FUSED_MADD || <MODE>mode == V2SImode"
+ "#"
+ "reload_completed || (epiphany_vect_align == 4 && TARGET_SPLIT_VECMOVE_EARLY)"
+ [(parallel
+ [(set (match_dup 5)
+ (plus:<vmode_PART> (mult:<vmode_PART> (match_dup 6) (match_dup 7))
+ (match_dup 8)))
+ (clobber (reg:CC_FP CCFP_REGNUM))
+ (match_dup 13)
+ (match_dup 14)])
+ (parallel
+ [(set (match_dup 9)
+ (plus:<vmode_PART> (mult:<vmode_PART> (match_dup 10) (match_dup 11))
+ (match_dup 12)))
+ (clobber (reg:CC_FP CCFP_REGNUM))
+ (match_dup 13)
+ (match_dup 14)])]
+{
+ operands[5]
+ = simplify_gen_subreg (<vmode_PART>mode, operands[0], <MODE>mode, 0);
+ operands[6]
+ = simplify_gen_subreg (<vmode_PART>mode, operands[1], <MODE>mode, 0);
+ operands[7]
+ = simplify_gen_subreg (<vmode_PART>mode, operands[2], <MODE>mode, 0);
+ operands[8]
+ = simplify_gen_subreg (<vmode_PART>mode, operands[3], <MODE>mode, 0);
+ operands[9] = simplify_gen_subreg (<vmode_PART>mode, operands[0],
+ <MODE>mode, UNITS_PER_WORD);
+ operands[10] = simplify_gen_subreg (<vmode_PART>mode, operands[1],
+ <MODE>mode, UNITS_PER_WORD);
+ operands[11] = simplify_gen_subreg (<vmode_PART>mode, operands[2],
+ <MODE>mode, UNITS_PER_WORD);
+ operands[12] = simplify_gen_subreg (<vmode_PART>mode, operands[3],
+ <MODE>mode, UNITS_PER_WORD);
+ if (!reload_completed)
+ {
+ if (reg_overlap_mentioned_p (operands[5], operands[10]))
+ operands[10] = copy_to_mode_reg (<vmode_PART>mode, operands[10]);
+ if (reg_overlap_mentioned_p (operands[5], operands[11]))
+ operands[11] = copy_to_mode_reg (<vmode_PART>mode, operands[11]);
+ if (reg_overlap_mentioned_p (operands[5], operands[12]))
+ operands[12] = copy_to_mode_reg (<vmode_PART>mode, operands[12]);
+ emit_insn (gen_madd<vmode_part> (operands[5], operands[6], operands[7],
+ operands[8]));
+ emit_insn (gen_madd<vmode_part> (operands[9], operands[10], operands[11],
+ operands[12]));
+ DONE;
+ }
+ gcc_assert (!reg_overlap_mentioned_p (operands[5], operands[10]));
+ gcc_assert (!reg_overlap_mentioned_p (operands[5], operands[11]));
+ gcc_assert (!reg_overlap_mentioned_p (operands[5], operands[12]));
+ operands[13] = XVECEXP (operands[4], 0, XVECLEN (operands[4], 0) - 2);
+ operands[14] = XVECEXP (operands[4], 0, XVECLEN (operands[4], 0) - 1);
+}
+ [(set_attr "length" "8")
+ (set_attr "type" "<vmode_fp_type>")])
+
+(define_expand "vec_set<mode>"
+ [(match_operand:DWV2MODE 0 "register_operand")
+ (match_operand:<vmode_PART> 1 "register_operand")
+ (match_operand 2 "const_int_operand" "")]
+ ""
+{
+ operands[0]
+ = simplify_gen_subreg (<vmode_PART>mode, operands[0], <MODE>mode,
+ UNITS_PER_WORD * INTVAL (operands[2]));
+ emit_move_insn (operands[0], operands[1]);
+ DONE;
+})
+
+(define_insn "nop"
+ [(const_int 0)]
+ ""
+ "nop"
+ [(set_attr "type" "flow")])