;; Machine description of the Adaptiva epiphany cpu for GNU C compiler ;; Copyright (C) 1994-2021 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_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, 0); operands[1] = simplify_gen_subreg (SImode, operands[1], mode, 0); emit_insn (gen_movsi (operands[0], operands[1])); DONE; } if (GET_CODE (operands[0]) == MEM) operands[1] = force_reg (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_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, 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))” "@

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))) || 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)) 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, 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 cannot 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 arithmetic. ; 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 “*<op_mnc>_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)))] "" “<op_mnc> %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 (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, we have mode combine opportunities with flag setting operations - if we get some. */ operands[1] = gen_compare_reg (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:MODEmode, 0); replace_rtx (operands[2], operands[9], operands[3], true); replace_rtx (operands[2], operands[0], operands[10], true); 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:MODEmode, 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 (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 (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 “<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<si_pattern_suffix> (o0l, o1l, o2l)); emit_insn (gen_<insn_opname>si3<si_pattern_suffix> (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” “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,12”) (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 (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 (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, 0); operands[5] = simplify_gen_subreg (<vmode_PART>mode, operands[1], mode, 0); operands[6] = simplify_gen_subreg (<vmode_PART>mode, operands[2], mode, 0); operands[7] = simplify_gen_subreg (<vmode_PART>mode, operands[0], mode, UNITS_PER_WORD); operands[8] = simplify_gen_subreg (<vmode_PART>mode, operands[1], mode, UNITS_PER_WORD); operands[9] = simplify_gen_subreg (<vmode_PART>mode, operands[2], 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_combine” [(match_parallel 4 “float_operation” [(set (match_operand:DWV2MODE 0 “gpr_operand” “=r”) (plus:DWV2MODE (mult: (match_operand: 1 “gpr_operand” “r”) (match_operand: 2 “gpr_operand” “r”)) (match_operand: 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, 0); operands[6] = simplify_gen_subreg (<vmode_PART>mode, operands[1], mode, 0); operands[7] = simplify_gen_subreg (<vmode_PART>mode, operands[2], mode, 0); operands[8] = simplify_gen_subreg (<vmode_PART>mode, operands[3], mode, 0); operands[9] = simplify_gen_subreg (<vmode_PART>mode, operands[0], mode, UNITS_PER_WORD); operands[10] = simplify_gen_subreg (<vmode_PART>mode, operands[1], mode, UNITS_PER_WORD); operands[11] = simplify_gen_subreg (<vmode_PART>mode, operands[2], mode, UNITS_PER_WORD); operands[12] = simplify_gen_subreg (<vmode_PART>mode, operands[3], 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” [(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, 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 (<vmode_PART>mode, operands[0], mode, 0); op01 = simplify_gen_subreg (<vmode_PART>mode, operands[0], mode, UNITS_PER_WORD); op10 = simplify_gen_subreg (<vmode_PART>mode, operands[1], mode, 0); op11 = simplify_gen_subreg (<vmode_PART>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”)])