;; Machine description of the Adaptiva epiphany cpu for GNU C compiler ;; Copyright (C) 1994-2014 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 ;; . ;; 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, 0); o0h = simplify_gen_subreg (SImode, operands[0], mode, UNITS_PER_WORD); o1l = simplify_gen_subreg (SImode, operands[1], mode, 0); o1h = simplify_gen_subreg (SImode, operands[1], 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) && (GET_CODE (operands[0]) != SUBREG || (GET_MODE_SIZE (GET_MODE (SUBREG_REG (operands[0]))) != GET_MODE_SIZE (mode) && GET_CODE (operands[1]) != SUBREG))) { operands[0] = simplify_gen_subreg (DImode, operands[0], mode, 0); operands[1] = simplify_gen_subreg (DImode, operands[1], 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 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" "L")))] "INTVAL (operands[2]) == -INTVAL (operands[3])" "sub %0,%1,%2" [(set_attr "type" "compare")]) (define_expand "abssi2" [(set (match_dup 2) (const_int 0)) (parallel [(set (reg:CC CC_REGNUM) (compare:CC (match_dup 2) (match_operand:SI 1 "nonmemory_operand" ""))) (set (match_dup 3) (minus:SI (match_dup 2) (match_dup 1)))]) (set (match_operand:SI 0 "gpr_operand" "=r") (if_then_else:SI (gt:SI (reg:CC CC_REGNUM) (const_int 0)) (match_dup 3) (match_dup 1)))] "TARGET_CMOVE" "operands[2] = gen_reg_rtx (SImode); operands[3] = gen_reg_rtx (SImode);") (define_insn "*add_c" [(set (reg:CC_C_LTU CC_REGNUM) (compare:CC_C_LTU (plus:SI (match_operand:SI 1 "gpr_operand" "%r,r") (match_operand:SI 2 "arith_operand" "r,L")) (match_dup 1))) (set (match_operand:SI 0 "gpr_operand" "=r,r") (plus:SI (match_dup 1) (match_dup 2)))] "" "add %0,%1,%2" [(set_attr "type" "compare")]) (define_insn "*add_c_rev" [(set (reg:CC_C_LTU CC_REGNUM) (compare:CC_C_LTU (plus:SI (match_operand:SI 1 "gpr_operand" "%r,r") (match_operand:SI 2 "arith_operand" "r,L")) (match_dup 1))) (set (match_operand:SI 0 "gpr_operand" "=r,r") (plus:SI (match_dup 2) (match_dup 1)))] "" "add %0,%1,%2" [(set_attr "type" "compare")]) (define_insn "*sub_c" [(set (reg:CC_C_GTU CC_REGNUM) (compare:CC_C_GTU (minus:SI (match_operand:SI 1 "gpr_operand" "r,r") (match_operand:SI 2 "arith_operand" "r,L")) (match_dup 1))) (set (match_operand:SI 0 "gpr_operand" "=r,r") (minus:SI (match_dup 1) (match_dup 2)))] "" "sub %0,%1,%2" [(set_attr "type" "compare")]) (define_insn "*sub_c_void" [(set (reg:CC_C_GTU CC_REGNUM) (compare:CC_C_GTU (minus:SI (match_operand:SI 1 "gpr_operand" "r,r") (match_operand:SI 2 "arith_operand" "r,L")) (match_dup 1))) (clobber (match_scratch:SI 0 "=r,r"))] "" "sub %0,%1,%2" [(set_attr "type" "compare")]) (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); enum machine_mode cmp_in_mode; enum rtx_code code = GET_CODE (operands[1]); cmp_in_mode = GET_MODE (cmp_op0); if (cmp_in_mode == VOIDmode) cmp_in_mode = GET_MODE (cmp_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)) ? 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 (mode, operands[3], 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 (mode, operands[3], mode, 0); }") ;; These control RTL generation for conditional jump insns ;; To signal to can_compare_p that the cbranchs?4 patterns work, ;; they must allow const0_rtx for both comparison operands (define_expand "cbranchsi4" [(set (reg CC_REGNUM) (compare (match_operand:SI 1 "add_operand" "") (match_operand:SI 2 "arith_operand" ""))) (set (pc) (if_then_else (match_operator 0 "ordered_comparison_operator" [(reg CC_REGNUM) (const_int 0)]) (label_ref (match_operand 3 "" "")) (pc)))] "" { rtx cmp = gen_compare_reg (VOIDmode, GET_CODE (operands[0]), SImode, operands[1], operands[2]); emit_jump_insn (gen_branch_insn (operands[3], cmp, XEXP (cmp, 0))); DONE; }) (define_expand "cbranchsf4" [(set (reg CC_REGNUM) (compare (match_operand:SF 1 "arith_operand" "") (match_operand:SF 2 "arith_operand" ""))) (set (pc) (if_then_else (match_operator 0 "comparison_operator" [(reg CC_REGNUM) (const_int 0)]) (label_ref (match_operand 3 "" "")) (pc)))] "" { rtx cmp = gen_compare_reg (VOIDmode, GET_CODE (operands[0]), SFmode, operands[1], operands[2]); emit_jump_insn (gen_branch_insn (operands[3], cmp, XEXP (cmp, 0))); DONE; }) ;; Now match both normal and inverted jump. (define_insn "branch_insn" [(set (pc) (if_then_else (match_operator 1 "proper_comparison_operator" [(match_operand 2 "cc_operand") (const_int 0)]) (label_ref (match_operand 0 "" "")) (pc)))] "" "b%d1 %l0" [(set_attr "type" "branch")]) (define_insn "*rev_branch_insn" [(set (pc) (if_then_else (match_operator 1 "proper_comparison_operator" [(reg CC_REGNUM) (const_int 0)]) (pc) (label_ref (match_operand 0 "" ""))))] "" "b%D1 %l0" [(set_attr "type" "branch")]) ;; Unconditional and other jump instructions. (define_insn "jump" [(set (pc) (label_ref (match_operand 0 "" "")))] "" "b %l0" [(set_attr "type" "uncond_branch")]) (define_insn "indirect_jump" [(set (pc) (match_operand:SI 0 "gpr_operand" "r"))] "" "jr %0" [(set_attr "type" "uncond_branch")]) (define_expand "tablejump" [(parallel [(set (pc) (match_operand:SI 0 "gpr_operand" "")) (use (label_ref (match_operand 1 "" "")))])] "" { /* In PIC mode, the table entries are stored PC relative. Convert the relative address to an absolute address. */ if (flag_pic) { rtx op1 = gen_rtx_LABEL_REF (Pmode, operands[1]); operands[0] = expand_simple_binop (Pmode, PLUS, operands[0], op1, NULL_RTX, 0, OPTAB_DIRECT); } }) (define_insn "*tablejump_internal" [(set (pc) (match_operand:SI 0 "gpr_operand" "r")) (use (label_ref (match_operand 1 "" "")))] "" "jr %0;" [(set_attr "type" "uncond_branch")]) (define_insn "*tablejump_hi_internal" [(set (pc) (match_operand:HI 0 "gpr_operand" "r")) (use (label_ref (match_operand 1 "" "")))] "optimize_size && TARGET_SMALL16" "jr %0;" [(set_attr "type" "uncond_branch")]) (define_expand "call" ;; operands[1] is stack_size_rtx ;; operands[2] is next_arg_register [(parallel [(call (match_operand:SI 0 "call_operand" "") (match_operand 1 "" "")) (clobber (reg:SI GPR_LR))])] "" { bool target_uninterruptible = epiphany_call_uninterruptible_p (operands[0]); if (!call_operand (operands[1], VOIDmode)) operands[0] = change_address (operands[0], VOIDmode, copy_to_mode_reg (Pmode, XEXP (operands[0], 0))); if (epiphany_uninterruptible_p (current_function_decl) != target_uninterruptible) { emit_insn (target_uninterruptible ? gen_gid (): gen_gie ()); emit_call_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, gen_rtx_CALL (VOIDmode, operands[0], operands[1]), gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_LR))))); emit_insn (target_uninterruptible ? gen_gie (): gen_gid ()); DONE; } }) (define_insn "*call_i" [(match_parallel 2 "float_operation" [(call (mem:SI (match_operand:SI 0 "call_address_operand" "Csy,r")) (match_operand 1 "" "")) (clobber (reg:SI GPR_LR))])] "" "%f0" [(set_attr "type" "call")]) (define_expand "sibcall" ;; operands[1] is stack_size_rtx ;; operands[2] is next_arg_register [(parallel [(call (match_operand:SI 0 "call_operand" "") (match_operand 1 "" "")) (return)])] "" { bool target_uninterruptible = epiphany_call_uninterruptible_p (operands[0]); if (!call_operand (operands[1], VOIDmode)) operands[0] = change_address (operands[0], VOIDmode, copy_to_mode_reg (Pmode, XEXP (operands[0], 0))); if (epiphany_uninterruptible_p (current_function_decl) != target_uninterruptible) { emit_insn (target_uninterruptible ? gen_gid (): gen_gie ()); emit_call_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, gen_rtx_CALL (VOIDmode, operands[0], operands[1]), ret_rtx))); emit_insn (target_uninterruptible ? gen_gie (): gen_gid ()); DONE; } }) (define_insn "*sibcall_i" [(call (mem:SI (match_operand:SI 0 "call_address_operand" "Csy,Rsc")) (match_operand 1 "" "")) (return)] "" "@ b %0 jr %0" [(set_attr "type" "call")]) (define_expand "call_value" ;; operand 2 is stack_size_rtx ;; operand 3 is next_arg_register [(parallel [(set (match_operand 0 "gpr_operand" "=r") (call (match_operand:SI 1 "call_operand" "") (match_operand 2 "" ""))) (clobber (reg:SI GPR_LR))])] "" { bool target_uninterruptible = epiphany_call_uninterruptible_p (operands[1]); if (!call_operand (operands[1], VOIDmode)) operands[1] = change_address (operands[1], VOIDmode, copy_to_mode_reg (Pmode, XEXP (operands[1], 0))); if (epiphany_uninterruptible_p (current_function_decl) != target_uninterruptible) { emit_insn (target_uninterruptible ? gen_gid (): gen_gie ()); emit_call_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, gen_rtx_SET (VOIDmode, operands[0], gen_rtx_CALL (VOIDmode, operands[1], operands[2])), gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_LR))))); emit_insn (target_uninterruptible ? gen_gie (): gen_gid ()); DONE; } }) (define_insn "*call_value_i" [(match_parallel 3 "float_operation" [(set (match_operand 0 "gpr_operand" "=r,r") (call (mem:SI (match_operand:SI 1 "call_address_operand" "Csy,r")) (match_operand 2 "" ""))) (clobber (reg:SI GPR_LR))])] "" "%f1" [(set_attr "type" "call") (set_attr "length" "4")]) (define_expand "sibcall_value" ;; operand 2 is stack_size_rtx ;; operand 3 is next_arg_register [(parallel [(set (match_operand 0 "gpr_operand" "=r") (call (match_operand:SI 1 "call_operand" "") (match_operand 2 "" ""))) (return)])] "" { bool target_uninterruptible = epiphany_call_uninterruptible_p (operands[1]); if (!call_operand (operands[1], VOIDmode)) operands[1] = change_address (operands[1], VOIDmode, copy_to_mode_reg (Pmode, XEXP (operands[1], 0))); if (epiphany_uninterruptible_p (current_function_decl) != target_uninterruptible) { emit_insn (target_uninterruptible ? gen_gid (): gen_gie ()); emit_call_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, gen_rtx_SET (VOIDmode, operands[0], gen_rtx_CALL (VOIDmode, operands[1], operands[2])), ret_rtx))); emit_insn (target_uninterruptible ? gen_gie (): gen_gid ()); DONE; } }) (define_insn "*sibcall_value_i" [(set (match_operand 0 "gpr_operand" "=r,r") (call (mem:SI (match_operand:SI 1 "call_address_operand" "Csy,Rsc")) (match_operand 2 "" ""))) (return)] "" "@ b %1 jr %1" [(set_attr "type" "call") (set_attr "length" "4")]) (define_expand "prologue" [(pc)] "" { epiphany_expand_prologue (); DONE; }) (define_expand "epilogue" [(pc)] "" { epiphany_expand_epilogue (0); DONE; }) (define_expand "sibcall_epilogue" [(pc)] "" { epiphany_expand_epilogue (1); DONE; }) ; Since the demise of REG_N_SETS, it is no longer possible to find out ; in the prologue / epilogue expanders how many times lr is set. ; Using df_regs_ever_live_p to decide if lr needs saving means that ; any explicit use of lr will cause it to be saved; hence we cannot ; represent the blink use in return / sibcall instructions themselves, and ; instead have to show it in EPILOGUE_USES. (define_insn "return_i" [(return)] "reload_completed" "rts" [(set_attr "type" "uncond_branch")]) (define_insn "return_internal_interrupt" [(return) (unspec_volatile [(const_int 0)] 1)] "" "rti" [(set_attr "type" "uncond_branch")]) (define_insn "stack_adjust_add" [(set (reg:SI GPR_SP) (plus:SI (reg:SI GPR_SP) (match_operand:SI 0 "arith_operand" "rL"))) (clobber (reg:CC CC_REGNUM)) (clobber (reg:SI STATUS_REGNUM)) (clobber (match_operand:BLK 1 "memory_operand" "=m"))] "reload_completed" "add sp,sp,%0") (define_insn "stack_adjust_mov" [(set (reg:SI GPR_SP) (reg:SI GPR_FP)) (clobber (match_operand:BLK 0 "memory_operand" "=m"))] "reload_completed" "mov sp,fp" [(set_attr "type" "move")]) (define_insn "stack_adjust_str" [(set (match_operand 0 "stacktop_operand" "=m") (match_operand 1 "any_gpr_operand" "r")) (set (reg:SI GPR_SP) (plus:SI (reg:SI GPR_SP) (match_operand:SI 2 "nonmemory_operand" "rn"))) (clobber (match_operand:BLK 3 "memory_operand" "=m"))] "reload_completed" { return (GET_MODE_SIZE (GET_MODE (operands[0])) <= 4 ? \"str %1,%0,%C2\" : \"strd %1,%0,%X2\"); } [(set_attr "type" "store")]) (define_insn "stack_adjust_ldr" [(set (match_operand:SI 0 "gpr_operand" "=r") (match_operand:SI 1 "stacktop_operand" "m")) (set (reg:SI GPR_SP) (plus:SI (reg:SI GPR_SP) (match_operand:SI 2 "nonmemory_operand" "rn"))) (clobber (match_operand:BLK 3 "memory_operand" "=m"))] "reload_completed" "ldr %0,%1,%C2" [(set_attr "type" "load")]) ;; Define some fake vector operations so that the vectorizer is happy to use ;; 64 bit loads/stores. (define_expand "vec_unpacks_lo_v4hi" [(match_operand:V2SI 0 "gpr_operand") (match_operand:V4HI 1 "gpr_operand")] "" { rtx in = simplify_gen_subreg (SImode, operands[1], V4HImode, 0); rtx outl = simplify_gen_subreg (SImode, operands[0], V2SImode, 0); rtx outh = simplify_gen_subreg (SImode, operands[0], V2SImode, UNITS_PER_WORD); if (reg_overlap_mentioned_p (outl, in)) in = copy_to_mode_reg (SImode, in); emit_insn (gen_ashlsi3 (outl, in, GEN_INT (16))); emit_insn (gen_ashrsi3 (outl, outl, GEN_INT (16))); emit_insn (gen_ashrsi3 (outh, in, GEN_INT (16))); DONE; }) (define_expand "vec_unpacks_hi_v4hi" [(match_operand:V2SI 0 "gpr_operand") (match_operand:V4HI 1 "gpr_operand")] "" { rtx in = simplify_gen_subreg (SImode, operands[1], V4HImode, UNITS_PER_WORD); rtx outl = simplify_gen_subreg (SImode, operands[0], V2SImode, 0); rtx outh = simplify_gen_subreg (SImode, operands[0], V2SImode, UNITS_PER_WORD); if (reg_overlap_mentioned_p (outl, in)) in = copy_to_mode_reg (SImode, in); emit_insn (gen_ashlsi3 (outl, in, GEN_INT (16))); emit_insn (gen_ashrsi3 (outl, outl, GEN_INT (16))); emit_insn (gen_ashrsi3 (outh, in, GEN_INT (16))); DONE; }) (define_code_iterator addsub [plus minus]) (define_code_iterator alu_binop [plus minus and ior xor]) (define_code_attr insn_opname [(plus "add") (minus "sub") (mult "mul") (div "div") (and "and") (ior "ior") (xor "xor")]) ; 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); emit_insn (gen_si3 (o0l, o1l, o2l)); emit_insn (gen_si3 (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_sf3 (operands[4], operands[5], operands[6])); emit_insn (gen_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: (match_dup 5) (match_dup 6))) (clobber (reg:CC_FP CCFP_REGNUM)) (match_dup 10) (match_dup 11)]) (parallel [(set (match_dup 7) (mult: (match_dup 8) (match_dup 9))) (clobber (reg:CC_FP CCFP_REGNUM)) (match_dup 10) (match_dup 11)])] { operands[4] = simplify_gen_subreg (mode, operands[0], mode, 0); operands[5] = simplify_gen_subreg (mode, operands[1], mode, 0); operands[6] = simplify_gen_subreg (mode, operands[2], mode, 0); operands[7] = simplify_gen_subreg (mode, operands[0], mode, UNITS_PER_WORD); operands[8] = simplify_gen_subreg (mode, operands[1], mode, UNITS_PER_WORD); operands[9] = simplify_gen_subreg (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 (mode, operands[8]); if (reg_overlap_mentioned_p (operands[4], operands[9])) operands[9] = copy_to_mode_reg (mode, operands[9]); emit_insn (gen_mul3 (operands[4], operands[5], operands[6])); emit_insn (gen_mul3 (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: (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: (mult: (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: (mult: (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 (mode, operands[0], mode, 0); operands[6] = simplify_gen_subreg (mode, operands[1], mode, 0); operands[7] = simplify_gen_subreg (mode, operands[2], mode, 0); operands[8] = simplify_gen_subreg (mode, operands[3], mode, 0); operands[9] = simplify_gen_subreg (mode, operands[0], mode, UNITS_PER_WORD); operands[10] = simplify_gen_subreg (mode, operands[1], mode, UNITS_PER_WORD); operands[11] = simplify_gen_subreg (mode, operands[2], mode, UNITS_PER_WORD); operands[12] = simplify_gen_subreg (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 (mode, operands[10]); if (reg_overlap_mentioned_p (operands[5], operands[11])) operands[11] = copy_to_mode_reg (mode, operands[11]); if (reg_overlap_mentioned_p (operands[5], operands[12])) operands[12] = copy_to_mode_reg (mode, operands[12]); emit_insn (gen_madd (operands[5], operands[6], operands[7], operands[8])); emit_insn (gen_madd (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 (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 (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")])