epiphany.md 94 KB

;; Machine description of the Adaptiva epiphany cpu for GNU C compiler ;; Copyright (C) 1994-2015 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 defineinsn, match*, et. al. (define_constants [(GPR_0 0) (GPR_1 1) (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,v2fp,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,v2fp,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" [(set (match_operand:WMODE 0 "general_operand" "")

(match_operand:WMODE 1 "general_operand" ""))]

"" { if (mode == V4QImode || 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 == 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);

if (!MACHINE_FUNCTION (cfun)->lr_slot_known)

{
  start_sequence ();
  epiphany_expand_prologue ();
  if (!MACHINE_FUNCTION (cfun)->lr_slot_known)
    epiphany_expand_epilogue (0);
  end_sequence ();
  gcc_assert (MACHINE_FUNCTION (cfun)->lr_slot_known);
}

addr = plus_constant (Pmode, 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" [(set (match_operand:DWMODE 0 "general_operand" "")

(match_operand:DWMODE 1 "general_operand" ""))]

"" " { if (GET_MODE_CLASS (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)
  && !misaligned_operand (operands[1], <MODE>mode)
  && (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_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)

|| gpr_operand (operands[1], <MODE>mode))"

"@ # # ldrd %0,%X1 strd %1,%X0" "reload_completed && (((!MEM_P (operands[0]) || misaligned_operand (operands[0], mode))

&& (!MEM_P (operands[1])
    || misaligned_operand (operands[1], <MODE>mode)))
   || 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)

  || post_modify_operand (operands[1], <MODE>mode))
word0 = UNITS_PER_WORD, word1 = 0;

operands[2] = simplify_gen_subreg (SImode, operands[0], mode, word0); operands[3] = simplify_gen_subreg (SImode, operands[1], mode, word0); operands[4] = simplify_gen_subreg (SImode, operands[0], mode, word1); operands[5] = simplify_gen_subreg (SImode, operands[1], mode, word1); if (post_modify_operand (operands[0], mode))

operands[2]
  = change_address (operands[2], VOIDmode,
        plus_constant (Pmode, XEXP (XEXP (operands[0], 0), 0),
                   UNITS_PER_WORD));

if (post_modify_operand (operands[1], mode))

operands[3]
  = change_address (operands[3], VOIDmode,
        plus_constant (Pmode, 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 if (TARGET_FP_IARITH && add_reg_operand (operands[2], SImode))

emit_insn (gen_iadd (operands[0], operands[1], operands[2]));

else

emit_insn (gen_addsi3_i (operands[0], operands[1], operands[2]));

DONE; }")

; The default case of epiphany_print_operand emits IMMEDIATE_PREFIX ; where appropriate; however, 'n' is processed by output_asm_insn ; which doesn't, so we have to explicitly emit the '# in the ; r/r/CnL output template alternative. (define_insn "addsi3_i" [(set (match_operand:SI 0 "add_reg_operand" "=r,r")

(plus:SI (match_operand:SI 1 "add_reg_operand" "%r,r")
     (match_operand:SI 2 "add_operand" "rL,CnL")))

(clobber (reg:CC CC_REGNUM))] "" "@ add %0,%1,%2 sub %0,%1,#%n2" [(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, 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_expand "subsi3" [(set (match_operand:SI 0 "gpr_operand" "")

(plus:SI (match_operand:SI 1 "add_reg_operand" "")
     (match_operand:SI 2 "arith_operand" "")))]

"" " { gcc_assert (!reload_in_progress && !reload_completed);

if (TARGET_FP_IARITH)

emit_insn (gen_isub (operands[0], operands[1], operands[2]));

else

emit_insn (gen_subsi3_i (operands[0], operands[1], operands[2]));

DONE; }")

(define_insn "subsi3_i" [(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 counfounds 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")

(cond [(match_test "TARGET_MAY_ROUND_FOR_TRUNC")
       (const_string "round_unknown")]
      (const_string "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_i (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_code_label *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_expand "iadd" [(parallel

 [(set (match_operand:SF 0 "gpr_operand" "")
   (plus:SI (match_operand:SF 1 "gpr_operand" "")
        (match_operand:SF 2 "gpr_operand" "")))
  (clobber (reg:CC_FP CCFP_REGNUM))])])

(define_insn "*iadd_i" [(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_expand "isub" [(parallel

 [(set (match_operand:SF 0 "gpr_operand" "")
   (minus:SI (match_operand:SF 1 "gpr_operand" "")
         (match_operand:SF 2 "gpr_operand" "")))
  (clobber (reg:CC_FP CCFP_REGNUM))])])

(define_insn "*isub_i" [(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")])

; Try to figure out if we over-committed the FPU, and if so, move ; some insns back over to the integer pipe.

; The peephole optimizer 'consumes' the insns that are explicitly ; mentioned. We do not want the preceding insn reconsidered, but ; we do want that for the following one, so that if we have a run ; of five fpu users, two of them get changed. Therefore, we ; use next_active_insn to look at the 'following' insn. That should ; exist, because peephole2 runs after reload, and there has to be ; a return after an fp_int insn. ; ??? However, we can not even ordinarily match the preceding insn; ; there is some bug in the generators such that then it leaves out ; the check for PARALLEL before the length check for the then-second ; main insn. Observed when compiling compatibility-atomic-c++0x.cc ; from libstdc++-v3. (define_peephole2 [(match_parallel 3 "float_operation"

 [(set (match_operand:SI 0 "gpr_operand" "")
   (match_operator:SI 4 "addsub_operator"
     [(match_operand:SI 1 "gpr_operand" "")
      (match_operand:SI 2 "gpr_operand" "")]))
  (clobber (reg:CC_FP CCFP_REGNUM))])]

"get_attr_sched_use_fpu (prev_active_insn (peep2_next_insn (0))) && peep2_regno_dead_p (1, CC_REGNUM) && get_attr_sched_use_fpu (next_active_insn (peep2_next_insn (0)))" [(parallel [(set (match_dup 0) (match_dup 4))

      (clobber (reg:CC CC_REGNUM))])]

)

(define_peephole2 [(match_parallel 3 "float_operation"

 [(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))])]

"prev_active_insn (peep2_next_insn (0)) && get_attr_sched_use_fpu (prev_active_insn (peep2_next_insn (0))) && peep2_regno_dead_p (1, CC_REGNUM) && get_attr_sched_use_fpu (next_active_insn (peep2_next_insn (0))) && find_reg_note (insn, REG_EQUAL, NULL_RTX) != NULL_RTX && GET_CODE (XEXP (find_reg_note (insn, REG_EQUAL, NULL_RTX), 0)) == MULT && CONST_INT_P (XEXP (XEXP (find_reg_note (insn, REG_EQUAL, NULL_RTX), 0),

         1))"

[(parallel [(set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 4)))

      (clobber (reg:CC CC_REGNUM))])]

{ operands[4]

= XEXP (XEXP (find_reg_note (curr_insn, REG_EQUAL, NULL_RTX), 0), 1);

})

(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))])]

"" "imadd %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 "save_config" [(set (match_operand:SI 0 "gpr_operand" "=r") (reg:SI CONFIG_REGNUM)) (use (reg:SI FP_NEAREST_REGNUM)) (use (reg:SI FP_TRUNCATE_REGNUM)) (use (reg:SI FP_ANYFP_REGNUM))] "" "#" "reload_completed" [(set (match_dup 0) (reg:SI CONFIG_REGNUM))])

(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" "CnL")))]

"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")])

(define_code_iterator logical_op [and ior xor])

(define_code_attr op_mnc [(plus "add") (minus "sub") (and "and") (ior "orr") (xor "eor")])

(define_insn "*_f" [(set (reg:CC CC_REGNUM)

    (compare:CC (logical_op:SI (match_operand:SI 1 "gpr_operand" "%r")
               (match_operand:SI 2 "gpr_operand"  "r"))
                (const_int 0)))

(set (match_operand:SI 0 "gpr_operand" "=r")

    (logical_op:SI (match_dup 1) (match_dup 2)))]

"" " %0,%1,%2" [(set_attr "type" "compare")])

(define_insn_and_split "*mov_f" [(set (reg:CC CC_REGNUM)

    (compare:CC (match_operand:SI 1 "gpr_operand"  "r") (const_int 0)))

(set (match_operand:SI 0 "gpr_operand" "=r") (match_dup 1))] "" "#" "reload_completed" [(parallel

[(set (reg:CC CC_REGNUM)
  (compare:CC (and:SI (match_dup 1) (match_dup 1)) (const_int 0)))
 (set (match_operand:SI 0 "gpr_operand" "=r")
  (and:SI (match_dup 1) (match_dup 1)))])]

"" [(set_attr "type" "compare")])

(define_peephole2 [(parallel

[(set (match_operand:SI 0 "gpr_operand")
  (logical_op:SI (match_operand:SI 1 "gpr_operand")
         (match_operand:SI 2 "gpr_operand")))
 (clobber (reg:CC CC_REGNUM))])

(parallel

[(set (reg:CC CC_REGNUM)
  (compare:CC (and:SI (match_dup 0) (match_dup 0)) (const_int 0)))
 (set (match_operand:SI 3 "gpr_operand")
  (and:SI (match_dup 0) (match_dup 0)))])]

"peep2_reg_dead_p (2, operands[0])" [(parallel

[(set (reg:CC CC_REGNUM)
  (compare:CC (logical_op:SI (match_dup 1) (match_dup 2))
          (const_int 0)))
 (set (match_dup 3) (logical_op:SI (match_dup 1) (match_dup 2)))])])

(define_peephole2 [(parallel

[(set (match_operand:SI 0 "gpr_operand")
  (logical_op:SI (match_operand:SI 1 "gpr_operand")
         (match_operand:SI 2 "gpr_operand")))
 (clobber (reg:CC CC_REGNUM))])

(parallel

[(set (reg:CC CC_REGNUM)
  (compare:CC (and:SI (match_dup 0) (match_dup 0)) (const_int 0)))
 (set (match_operand:SI 3 "gpr_operand")
  (and:SI (match_dup 0) (match_dup 0)))])]

"peep2_reg_dead_p (2, operands[3])" [(parallel

[(set (reg:CC CC_REGNUM)
  (compare:CC (logical_op:SI (match_dup 1) (match_dup 2))
          (const_int 0)))
 (set (match_dup 0) (logical_op:SI (match_dup 1) (match_dup 2)))])])

(define_peephole2 [(parallel

[(set (match_operand:SI 0 "gpr_operand")
  (logical_op:SI (match_operand:SI 1 "gpr_operand")
         (match_operand:SI 2 "gpr_operand")))
 (clobber (reg:CC CC_REGNUM))])

(parallel

[(set (reg:CC CC_REGNUM)
  (compare:CC (match_dup 0) (const_int 0)))
 (clobber (match_operand:SI 3 "gpr_operand"))])]

"" [(parallel

[(set (reg:CC CC_REGNUM)
  (compare:CC (logical_op:SI (match_dup 1) (match_dup 2))
          (const_int 0)))
 (set (match_dup 0) (logical_op:SI (match_dup 1) (match_dup 2)))])])

(define_expand "cstoresi4" [(parallel

[(set (reg:CC CC_REGNUM)
      (match_operand:SI 1 "comparison_operator"))
 (match_operand:SI 2 "" "")])

(set (match_dup 0) (match_operand:SI 3 "arith_operand" "")) (set (match_operand:SI 0 "gpr_operand" "=r")

(if_then_else:SI (match_dup 4) (match_dup 5) (match_dup 0)))]

"" { enum rtx_code o2_code = GET_CODE (operands[2]); enum rtx_code cmp_code = GET_CODE (operands[1]);

if ((o2_code == AND || o2_code == IOR || o2_code == XOR)

  && operands[3] == const0_rtx)
{
  operands[2] = copy_rtx(operands[2]);
  XEXP (operands[2], 0) = force_reg (SImode, XEXP (operands[2], 0));
  XEXP (operands[2], 1) = force_reg (SImode, XEXP (operands[2], 1));
}

else

operands[2] = force_reg (SImode, operands[2]);

operands[1] = gen_rtx_COMPARE (CCmode, operands[2], operands[3]); if (cmp_code != NE)

{
  operands[2] = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (SImode));
  operands[3] = const0_rtx;
}

else

{
  if (operands[3] != const0_rtx)
operands[2] = gen_rtx_MINUS (SImode, operands[2], operands[3]);
  operands[2] = gen_rtx_SET (VOIDmode, operands[0], operands[2]);
  operands[3] = operands[0];
}

operands[4] = gen_rtx_fmt_ee (cmp_code, SImode,

            gen_rtx_REG (CCmode, CC_REGNUM), const0_rtx);

operands[5] = force_reg (SImode, GEN_INT (STORE_FLAG_VALUE)); })

; 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))] "" "%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 "movcc" [(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); 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_op1);

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)) && !flag_finite_math_only
      ? 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);
  if (!operands[1])
FAIL;
}

})

(define_insn "*movcc_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:MODEmode, 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:MODEmode, 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 "memclob_operand" "=X"))] "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 "memclob_operand" "=X"))] "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")])

; The addsi3 / subsi3 do checks that we don't want when splitting V2SImode ; operations into two SImode operations. (define_code_attr si_pattern_suffix [(plus "_i") (minus "_i") (and "") (ior "") (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 "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);

emitinsn (gensi3 (o0l, o1l, o2l)); emitinsn (gensi3 (o0h, o1h, o2h)); DONE; } [(set_attr "length" "8")])

(define_expand "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 "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" "v2fp")])

(define_expand "ashlv2si3" [(parallel

 [(set (match_operand:V2SI 0 "gpr_operand" "")
   (ashift:V2SI (match_operand:V2SI 1 "gpr_operand" "")
        (match_operand:SI 2 "general_operand")))
  (use (match_dup 3))
  (clobber (reg:CC_FP CCFP_REGNUM))])]

"" { if (const_int_operand (operands[2], VOIDmode))

operands[3]
  = copy_to_mode_reg (SImode, GEN_INT (1 << INTVAL (operands[2])));

else

{
  int o, i;
  rtx xop[2], last_out = pc_rtx;

  for (o = 0; o <= UNITS_PER_WORD; o += UNITS_PER_WORD)
{
  for (i = 0; i < 2; i++)
    {
      xop[i]
    = (i == 2 ? operands[2]
       : simplify_gen_subreg (SImode, operands[i], V2SImode, o));
      gcc_assert (!reg_overlap_mentioned_p (last_out, xop[i])
          /* ??? reg_overlap_mentioned_p doesn't understand
             about multi-word SUBREGs.  */
          || (GET_CODE (last_out) == SUBREG
              && GET_CODE (xop[i]) == SUBREG
              && SUBREG_REG (last_out) == SUBREG_REG (xop[i])
              && ((SUBREG_BYTE (last_out) & -UNITS_PER_WORD)
              != (SUBREG_BYTE (xop[i]) & -UNITS_PER_WORD))));
    }
  emit_insn (gen_ashlsi3 (xop[0], xop[1], operands[2]));
  last_out = xop[0];
}
  DONE;
}

})

(define_insn_and_split "*ashlv2si3_i" [(match_parallel 3 "float_operation"

 [(set (match_operand:V2SI 0 "gpr_operand" "=&r,*1*2")
   (ashift:V2SI (match_operand:V2SI 1 "gpr_operand" "r,r")
        (match_operand 2 "const_int_operand" "n,n")))
  (use (match_operand:SI 4 "gpr_operand" "r,r"))
  (clobber (reg:CC_FP CCFP_REGNUM))])]

"" "#" "reload_completed" [(parallel

 [(set (match_dup 5) (mult:SI (match_dup 6) (match_dup 4)))
   (clobber (reg:CC_FP CCFP_REGNUM))
   (match_dup 9)
   (match_dup 10)])

(parallel

 [(set (match_dup 7) (mult:SI (match_dup 8) (match_dup 4)))
   (clobber (reg:CC_FP CCFP_REGNUM))
   (match_dup 9)
   (match_dup 10)])]

{ operands[5] = simplify_gen_subreg (SImode, operands[0], V2SImode, 0); operands[6] = simplify_gen_subreg (SImode, operands[1], V2SImode, 0); operands[7] = simplify_gen_subreg (SImode, operands[0],

                 V2SImode, UNITS_PER_WORD);

operands[8] = simplify_gen_subreg (SImode, operands[1],

                 V2SImode, UNITS_PER_WORD);

gcc_assert (!reg_overlap_mentioned_p (operands[5], operands[8])); gcc_assert (!reg_overlap_mentioned_p (operands[5], operands[4])); operands[9] = XVECEXP (operands[3], 0, XVECLEN (operands[3], 0) - 2); operands[10] = XVECEXP (operands[3], 0, XVECLEN (operands[3], 0) - 1); rtx insn

= (gen_rtx_PARALLEL
(VOIDmode,
 gen_rtvec
  (4,
   gen_rtx_SET (VOIDmode, operands[5],
        gen_rtx_MULT (SImode, operands[6], operands[4])),
   gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CC_FPmode, CCFP_REGNUM)),
   operands[9], operands[10])));

insn = emit_insn (insn); add_reg_note (insn, REG_EQUAL,

    gen_rtx_ASHIFT (SImode, operands[6], operands[2]));

insn

= (gen_rtx_PARALLEL
(VOIDmode,
 gen_rtvec
  (4,
   gen_rtx_SET (VOIDmode, operands[7],
        gen_rtx_MULT (SImode, operands[8], operands[4])),
   gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CC_FPmode, CCFP_REGNUM)),
   operands[9], operands[10])));

insn = emit_insn (insn); add_reg_note (insn, REG_EQUAL,

    gen_rtx_ASHIFT (SImode, operands[7], operands[2]));

DONE; } [(set_attr "length" "8") (set_attr "type" "fp_int")])

(define_expand "mul3" [(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 "mul3_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 (mode, operands[0],

                 <MODE>mode, UNITS_PER_WORD);

operands[8] = simplify_gen_subreg (mode, operands[1],

                 <MODE>mode, UNITS_PER_WORD);

operands[9] = simplify_gen_subreg (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" "")])

(define_insn_and_split "*fmadd_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 == 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 (mode, operands[0],

                 <MODE>mode, UNITS_PER_WORD);

operands[10] = simplify_gen_subreg (mode, operands[1],

                  <MODE>mode, UNITS_PER_WORD);

operands[11] = simplify_gen_subreg (mode, operands[2],

                  <MODE>mode, UNITS_PER_WORD);

operands[12] = simplify_gen_subreg (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" "")])

(define_expand "vec_set" [(match_operand:DWV2MODE 0 "register_operand") (match_operand: 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_expand "movmisalign" [(set (match_operand:DWV2MODE 0 "nonimmediate_operand" "")

   (match_operand:DWV2MODE 1 "general_operand" ""))]

"" { rtx op00, op01, op10, op11;

op00 = simplify_gen_subreg (mode, operands[0], mode, 0); op01 = simplify_gen_subreg (mode, operands[0], mode,

              UNITS_PER_WORD);

op10 = simplify_gen_subreg (mode, operands[1], mode, 0); op11 = simplify_gen_subreg (mode, operands[1], mode,

              UNITS_PER_WORD);

emit_move_insn (op00, op10); emit_move_insn (op01, op11); DONE; }) (define_insn "nop" [(const_int 0)] "" "nop" [(set_attr "type" "flow")])