X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fconfig%2Fbfin%2Fbfin.c;h=d1a5c80d2a8012e5f388cc0e7d4488e7c9af9d2d;hp=7b2f988064113d13cb6a95db32a11b5b7273b51d;hb=87943377315aebb9dbe539bae0a87829a6c22071;hpb=121e4cf51d17c3c337e1c4789da2e014f85fbc7c;ds=sidebyside diff --git a/gcc/config/bfin/bfin.c b/gcc/config/bfin/bfin.c index 7b2f9880641..d1a5c80d2a8 100644 --- a/gcc/config/bfin/bfin.c +++ b/gcc/config/bfin/bfin.c @@ -1,5 +1,5 @@ /* The Blackfin code generation auxiliary output file. - Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc. + Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc. Contributed by Analog Devices. This file is part of GCC. @@ -49,6 +49,7 @@ #include "langhooks.h" #include "bfin-protos.h" #include "tm-preds.h" +#include "tm-constrs.h" #include "gt-bfin.h" #include "basic-block.h" #include "cfglayout.h" @@ -95,6 +96,122 @@ static int bfin_flag_var_tracking; /* -mcpu support */ bfin_cpu_t bfin_cpu_type = DEFAULT_CPU_TYPE; +/* -msi-revision support. There are three special values: + -1 -msi-revision=none. + 0xffff -msi-revision=any. */ +int bfin_si_revision; + +/* The workarounds enabled */ +unsigned int bfin_workarounds = 0; + +static bool cputype_selected = false; + +struct bfin_cpu +{ + const char *name; + bfin_cpu_t type; + int si_revision; + unsigned int workarounds; +}; + +struct bfin_cpu bfin_cpus[] = +{ + {"bf522", BFIN_CPU_BF522, 0x0000, + WA_SPECULATIVE_LOADS | WA_RETS}, + + {"bf523", BFIN_CPU_BF523, 0x0000, + WA_SPECULATIVE_LOADS | WA_RETS}, + + {"bf524", BFIN_CPU_BF524, 0x0000, + WA_SPECULATIVE_LOADS | WA_RETS}, + + {"bf525", BFIN_CPU_BF525, 0x0000, + WA_SPECULATIVE_LOADS | WA_RETS}, + + {"bf526", BFIN_CPU_BF526, 0x0000, + WA_SPECULATIVE_LOADS | WA_RETS}, + + {"bf527", BFIN_CPU_BF527, 0x0000, + WA_SPECULATIVE_LOADS | WA_RETS}, + + {"bf531", BFIN_CPU_BF531, 0x0005, + WA_SPECULATIVE_LOADS | WA_RETS}, + {"bf531", BFIN_CPU_BF531, 0x0004, + WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS}, + {"bf531", BFIN_CPU_BF531, 0x0003, + WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS}, + + {"bf532", BFIN_CPU_BF532, 0x0005, + WA_SPECULATIVE_LOADS | WA_RETS}, + {"bf532", BFIN_CPU_BF532, 0x0004, + WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS}, + {"bf532", BFIN_CPU_BF532, 0x0003, + WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS}, + + {"bf533", BFIN_CPU_BF533, 0x0005, + WA_SPECULATIVE_LOADS | WA_RETS}, + {"bf533", BFIN_CPU_BF533, 0x0004, + WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS}, + {"bf533", BFIN_CPU_BF533, 0x0003, + WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS}, + + {"bf534", BFIN_CPU_BF534, 0x0003, + WA_SPECULATIVE_LOADS | WA_RETS}, + {"bf534", BFIN_CPU_BF534, 0x0002, + WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS}, + {"bf534", BFIN_CPU_BF534, 0x0001, + WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS}, + + {"bf536", BFIN_CPU_BF536, 0x0003, + WA_SPECULATIVE_LOADS | WA_RETS}, + {"bf536", BFIN_CPU_BF536, 0x0002, + WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS}, + {"bf536", BFIN_CPU_BF536, 0x0001, + WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS}, + + {"bf537", BFIN_CPU_BF537, 0x0003, + WA_SPECULATIVE_LOADS | WA_RETS}, + {"bf537", BFIN_CPU_BF537, 0x0002, + WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS}, + {"bf537", BFIN_CPU_BF537, 0x0001, + WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS}, + + {"bf538", BFIN_CPU_BF538, 0x0004, + WA_SPECULATIVE_LOADS | WA_RETS}, + {"bf538", BFIN_CPU_BF538, 0x0003, + WA_SPECULATIVE_LOADS | WA_RETS}, + + {"bf539", BFIN_CPU_BF539, 0x0004, + WA_SPECULATIVE_LOADS | WA_RETS}, + {"bf539", BFIN_CPU_BF539, 0x0003, + WA_SPECULATIVE_LOADS | WA_RETS}, + {"bf539", BFIN_CPU_BF539, 0x0002, + WA_SPECULATIVE_LOADS | WA_RETS}, + + {"bf542", BFIN_CPU_BF542, 0x0000, + WA_SPECULATIVE_LOADS | WA_RETS}, + + {"bf544", BFIN_CPU_BF544, 0x0000, + WA_SPECULATIVE_LOADS | WA_RETS}, + + {"bf547", BFIN_CPU_BF547, 0x0000, + WA_SPECULATIVE_LOADS | WA_RETS}, + + {"bf548", BFIN_CPU_BF548, 0x0000, + WA_SPECULATIVE_LOADS | WA_RETS}, + + {"bf549", BFIN_CPU_BF549, 0x0000, + WA_SPECULATIVE_LOADS | WA_RETS}, + + {"bf561", BFIN_CPU_BF561, 0x0005, WA_RETS}, + {"bf561", BFIN_CPU_BF561, 0x0003, + WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS}, + {"bf561", BFIN_CPU_BF561, 0x0002, + WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS}, + + {NULL, 0, 0, 0} +}; + int splitting_for_sched; static void @@ -238,22 +355,15 @@ legitimize_pic_address (rtx orig, rtx reg, rtx picreg) /* Stack frame layout. */ -/* Compute the number of DREGS to save with a push_multiple operation. - This could include registers that aren't modified in the function, - since push_multiple only takes a range of registers. - If IS_INTHANDLER, then everything that is live must be saved, even - if normally call-clobbered. */ - -static int -n_dregs_to_save (bool is_inthandler) +/* For a given REGNO, determine whether it must be saved in the function + prologue. IS_INTHANDLER specifies whether we're generating a normal + prologue or an interrupt/exception one. */ +static bool +must_save_p (bool is_inthandler, unsigned regno) { - unsigned i; - - for (i = REG_R0; i <= REG_R7; i++) + if (D_REGNO_P (regno)) { - if (df_regs_ever_live_p (i) && (is_inthandler || ! call_used_regs[i])) - return REG_R7 - i + 1; - + bool is_eh_return_reg = false; if (current_function_calls_eh_return) { unsigned j; @@ -262,30 +372,71 @@ n_dregs_to_save (bool is_inthandler) unsigned test = EH_RETURN_DATA_REGNO (j); if (test == INVALID_REGNUM) break; - if (test == i) - return REG_R7 - i + 1; + if (test == regno) + is_eh_return_reg = true; } } + return (is_eh_return_reg + || (df_regs_ever_live_p (regno) + && !fixed_regs[regno] + && (is_inthandler || !call_used_regs[regno]))); } - return 0; + else if (P_REGNO_P (regno)) + { + return ((df_regs_ever_live_p (regno) + && !fixed_regs[regno] + && (is_inthandler || !call_used_regs[regno])) + || (!TARGET_FDPIC + && regno == PIC_OFFSET_TABLE_REGNUM + && (current_function_uses_pic_offset_table + || (TARGET_ID_SHARED_LIBRARY && !current_function_is_leaf)))); + } + else + return ((is_inthandler || !call_used_regs[regno]) + && (df_regs_ever_live_p (regno) + || (!leaf_function_p () && call_used_regs[regno]))); + +} + +/* Compute the number of DREGS to save with a push_multiple operation. + This could include registers that aren't modified in the function, + since push_multiple only takes a range of registers. + If IS_INTHANDLER, then everything that is live must be saved, even + if normally call-clobbered. + If CONSECUTIVE, return the number of registers we can save in one + instruction with a push/pop multiple instruction. */ + +static int +n_dregs_to_save (bool is_inthandler, bool consecutive) +{ + int count = 0; + unsigned i; + + for (i = REG_R7 + 1; i-- != REG_R0;) + { + if (must_save_p (is_inthandler, i)) + count++; + else if (consecutive) + return count; + } + return count; } /* Like n_dregs_to_save, but compute number of PREGS to save. */ static int -n_pregs_to_save (bool is_inthandler) +n_pregs_to_save (bool is_inthandler, bool consecutive) { + int count = 0; unsigned i; - for (i = REG_P0; i <= REG_P5; i++) - if ((df_regs_ever_live_p (i) && (is_inthandler || ! call_used_regs[i])) - || (!TARGET_FDPIC - && i == PIC_OFFSET_TABLE_REGNUM - && (current_function_uses_pic_offset_table - || (TARGET_ID_SHARED_LIBRARY && ! current_function_is_leaf)))) - return REG_P5 - i + 1; - return 0; + for (i = REG_P5 + 1; i-- != REG_P0;) + if (must_save_p (is_inthandler, i)) + count++; + else if (consecutive) + return count; + return count; } /* Determine if we are going to save the frame pointer in the prologue. */ @@ -314,48 +465,94 @@ stack_frame_needed_p (void) static void expand_prologue_reg_save (rtx spreg, int saveall, bool is_inthandler) { - int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler); - int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler); - int dregno = REG_R7 + 1 - ndregs; - int pregno = REG_P5 + 1 - npregs; - int total = ndregs + npregs; - int i; - rtx pat, insn, val; + rtx predec1 = gen_rtx_PRE_DEC (SImode, spreg); + rtx predec = gen_rtx_MEM (SImode, predec1); + int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler, false); + int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler, false); + int ndregs_consec = saveall ? 8 : n_dregs_to_save (is_inthandler, true); + int npregs_consec = saveall ? 6 : n_pregs_to_save (is_inthandler, true); + int dregno, pregno; + int total_consec = ndregs_consec + npregs_consec; + int i, d_to_save; + + if (saveall || is_inthandler) + { + rtx insn = emit_move_insn (predec, gen_rtx_REG (SImode, REG_ASTAT)); + RTX_FRAME_RELATED_P (insn) = 1; + } - if (total == 0) - return; + if (total_consec != 0) + { + rtx insn; + rtx val = GEN_INT (-total_consec * 4); + rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_consec + 2)); + + XVECEXP (pat, 0, 0) = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, val), + UNSPEC_PUSH_MULTIPLE); + XVECEXP (pat, 0, total_consec + 1) = gen_rtx_SET (VOIDmode, spreg, + gen_rtx_PLUS (Pmode, + spreg, + val)); + RTX_FRAME_RELATED_P (XVECEXP (pat, 0, total_consec + 1)) = 1; + d_to_save = ndregs_consec; + dregno = REG_R7 + 1 - ndregs_consec; + pregno = REG_P5 + 1 - npregs_consec; + for (i = 0; i < total_consec; i++) + { + rtx memref = gen_rtx_MEM (word_mode, + gen_rtx_PLUS (Pmode, spreg, + GEN_INT (- i * 4 - 4))); + rtx subpat; + if (d_to_save > 0) + { + subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode, + dregno++)); + d_to_save--; + } + else + { + subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode, + pregno++)); + } + XVECEXP (pat, 0, i + 1) = subpat; + RTX_FRAME_RELATED_P (subpat) = 1; + } + insn = emit_insn (pat); + RTX_FRAME_RELATED_P (insn) = 1; + } - val = GEN_INT (-total * 4); - pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total + 2)); - XVECEXP (pat, 0, 0) = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, val), - UNSPEC_PUSH_MULTIPLE); - XVECEXP (pat, 0, total + 1) = gen_rtx_SET (VOIDmode, spreg, - gen_rtx_PLUS (Pmode, spreg, - val)); - RTX_FRAME_RELATED_P (XVECEXP (pat, 0, total + 1)) = 1; - for (i = 0; i < total; i++) - { - rtx memref = gen_rtx_MEM (word_mode, - gen_rtx_PLUS (Pmode, spreg, - GEN_INT (- i * 4 - 4))); - rtx subpat; - if (ndregs > 0) + for (dregno = REG_R0; ndregs != ndregs_consec; dregno++) + { + if (must_save_p (is_inthandler, dregno)) { - subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode, - dregno++)); + rtx insn = emit_move_insn (predec, gen_rtx_REG (word_mode, dregno)); + RTX_FRAME_RELATED_P (insn) = 1; ndregs--; } - else + } + for (pregno = REG_P0; npregs != npregs_consec; pregno++) + { + if (must_save_p (is_inthandler, pregno)) { - subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode, - pregno++)); - npregs++; + rtx insn = emit_move_insn (predec, gen_rtx_REG (word_mode, pregno)); + RTX_FRAME_RELATED_P (insn) = 1; + npregs--; } - XVECEXP (pat, 0, i + 1) = subpat; - RTX_FRAME_RELATED_P (subpat) = 1; } - insn = emit_insn (pat); - RTX_FRAME_RELATED_P (insn) = 1; + for (i = REG_P7 + 1; i < REG_CC; i++) + if (saveall + || (is_inthandler + && (df_regs_ever_live_p (i) + || (!leaf_function_p () && call_used_regs[i])))) + { + rtx insn; + if (i == REG_A0 || i == REG_A1) + insn = emit_move_insn (gen_rtx_MEM (PDImode, predec1), + gen_rtx_REG (PDImode, i)); + else + insn = emit_move_insn (predec, gen_rtx_REG (SImode, i)); + RTX_FRAME_RELATED_P (insn) = 1; + } } /* Emit code to restore registers in the epilogue. SAVEALL is nonzero if we @@ -366,45 +563,92 @@ expand_prologue_reg_save (rtx spreg, int saveall, bool is_inthandler) static void expand_epilogue_reg_restore (rtx spreg, bool saveall, bool is_inthandler) { - int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler); - int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler); - int total = ndregs + npregs; - int i, regno; - rtx pat, insn; + rtx postinc1 = gen_rtx_POST_INC (SImode, spreg); + rtx postinc = gen_rtx_MEM (SImode, postinc1); - if (total == 0) - return; + int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler, false); + int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler, false); + int ndregs_consec = saveall ? 8 : n_dregs_to_save (is_inthandler, true); + int npregs_consec = saveall ? 6 : n_pregs_to_save (is_inthandler, true); + int total_consec = ndregs_consec + npregs_consec; + int i, regno; + rtx insn; - pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total + 1)); - XVECEXP (pat, 0, 0) = gen_rtx_SET (VOIDmode, spreg, - gen_rtx_PLUS (Pmode, spreg, - GEN_INT (total * 4))); + /* A slightly crude technique to stop flow from trying to delete "dead" + insns. */ + MEM_VOLATILE_P (postinc) = 1; - if (npregs > 0) - regno = REG_P5 + 1; - else - regno = REG_R7 + 1; + for (i = REG_CC - 1; i > REG_P7; i--) + if (saveall + || (is_inthandler + && (df_regs_ever_live_p (i) + || (!leaf_function_p () && call_used_regs[i])))) + { + if (i == REG_A0 || i == REG_A1) + { + rtx mem = gen_rtx_MEM (PDImode, postinc1); + MEM_VOLATILE_P (mem) = 1; + emit_move_insn (gen_rtx_REG (PDImode, i), mem); + } + else + emit_move_insn (gen_rtx_REG (SImode, i), postinc); + } - for (i = 0; i < total; i++) + regno = REG_P5 - npregs_consec; + for (; npregs != npregs_consec; regno--) + { + if (must_save_p (is_inthandler, regno)) + { + emit_move_insn (gen_rtx_REG (word_mode, regno), postinc); + npregs--; + } + } + regno = REG_R7 - ndregs_consec; + for (; ndregs != ndregs_consec; regno--) { - rtx addr = (i > 0 - ? gen_rtx_PLUS (Pmode, spreg, GEN_INT (i * 4)) - : spreg); - rtx memref = gen_rtx_MEM (word_mode, addr); + if (must_save_p (is_inthandler, regno)) + { + emit_move_insn (gen_rtx_REG (word_mode, regno), postinc); + ndregs--; + } + } - regno--; - XVECEXP (pat, 0, i + 1) - = gen_rtx_SET (VOIDmode, gen_rtx_REG (word_mode, regno), memref); + if (total_consec != 0) + { + rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_consec + 1)); + XVECEXP (pat, 0, 0) + = gen_rtx_SET (VOIDmode, spreg, + gen_rtx_PLUS (Pmode, spreg, + GEN_INT (total_consec * 4))); + + if (npregs_consec > 0) + regno = REG_P5 + 1; + else + regno = REG_R7 + 1; - if (npregs > 0) + for (i = 0; i < total_consec; i++) { - if (--npregs == 0) - regno = REG_R7 + 1; + rtx addr = (i > 0 + ? gen_rtx_PLUS (Pmode, spreg, GEN_INT (i * 4)) + : spreg); + rtx memref = gen_rtx_MEM (word_mode, addr); + + regno--; + XVECEXP (pat, 0, i + 1) + = gen_rtx_SET (VOIDmode, gen_rtx_REG (word_mode, regno), memref); + + if (npregs_consec > 0) + { + if (--npregs_consec == 0) + regno = REG_R7 + 1; + } } - } - insn = emit_insn (pat); - RTX_FRAME_RELATED_P (insn) = 1; + insn = emit_insn (pat); + RTX_FRAME_RELATED_P (insn) = 1; + } + if (saveall || is_inthandler) + emit_move_insn (gen_rtx_REG (SImode, REG_ASTAT), postinc); } /* Perform any needed actions needed for a function that is receiving a @@ -486,9 +730,10 @@ n_regs_saved_by_prologue (void) tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); bool all = (lookup_attribute ("saveall", attrs) != NULL_TREE || (is_inthandler && !current_function_is_leaf)); - int ndregs = all ? 8 : n_dregs_to_save (is_inthandler); - int npregs = all ? 6 : n_pregs_to_save (is_inthandler); + int ndregs = all ? 8 : n_dregs_to_save (is_inthandler, false); + int npregs = all ? 6 : n_pregs_to_save (is_inthandler, false); int n = ndregs + npregs; + int i; if (all || stack_frame_needed_p ()) /* We use a LINK instruction in this case. */ @@ -501,23 +746,24 @@ n_regs_saved_by_prologue (void) n++; } + if (fkind != SUBROUTINE || all) + /* Increment once for ASTAT. */ + n++; + if (fkind != SUBROUTINE) { - int i; - - /* Increment once for ASTAT. */ - n++; - /* RETE/X/N. */ if (lookup_attribute ("nesting", attrs)) n++; - - for (i = REG_P7 + 1; i < REG_CC; i++) - if (all - || df_regs_ever_live_p (i) - || (!leaf_function_p () && call_used_regs[i])) - n += i == REG_A0 || i == REG_A1 ? 2 : 1; } + + for (i = REG_P7 + 1; i < REG_CC; i++) + if (all + || (fkind != SUBROUTINE + && (df_regs_ever_live_p (i) + || (!leaf_function_p () && call_used_regs[i])))) + n += i == REG_A0 || i == REG_A1 ? 2 : 1; + return n; } @@ -534,9 +780,9 @@ bfin_initial_elimination_offset (int from, int to) if (to == STACK_POINTER_REGNUM) { - if (current_function_outgoing_args_size >= FIXED_STACK_AREA) - offset += current_function_outgoing_args_size; - else if (current_function_outgoing_args_size) + if (crtl->outgoing_args_size >= FIXED_STACK_AREA) + offset += crtl->outgoing_args_size; + else if (crtl->outgoing_args_size) offset += FIXED_STACK_AREA; offset += get_frame_size (); @@ -700,10 +946,10 @@ emit_link_insn (rtx spreg, HOST_WIDE_INT frame_size) static HOST_WIDE_INT arg_area_size (void) { - if (current_function_outgoing_args_size) + if (crtl->outgoing_args_size) { - if (current_function_outgoing_args_size >= FIXED_STACK_AREA) - return current_function_outgoing_args_size; + if (crtl->outgoing_args_size >= FIXED_STACK_AREA) + return crtl->outgoing_args_size; else return FIXED_STACK_AREA; } @@ -780,15 +1026,13 @@ do_unlink (rtx spreg, HOST_WIDE_INT frame_size, bool all, int epilogue_p) SPREG contains (reg:SI REG_SP). */ static void -expand_interrupt_handler_prologue (rtx spreg, e_funkind fkind) +expand_interrupt_handler_prologue (rtx spreg, e_funkind fkind, bool all) { - int i; HOST_WIDE_INT frame_size = get_frame_size (); rtx predec1 = gen_rtx_PRE_DEC (SImode, spreg); rtx predec = gen_rtx_MEM (SImode, predec1); rtx insn; tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); - bool all = lookup_attribute ("saveall", attrs) != NULL_TREE; tree kspisusp = lookup_attribute ("kspisusp", attrs); if (kspisusp) @@ -805,28 +1049,12 @@ expand_interrupt_handler_prologue (rtx spreg, e_funkind fkind) RTX_FRAME_RELATED_P (insn) = 1; } - insn = emit_move_insn (predec, gen_rtx_REG (SImode, REG_ASTAT)); - RTX_FRAME_RELATED_P (insn) = 1; - /* If we're calling other functions, they won't save their call-clobbered registers, so we must save everything here. */ if (!current_function_is_leaf) all = true; expand_prologue_reg_save (spreg, all, true); - for (i = REG_P7 + 1; i < REG_CC; i++) - if (all - || df_regs_ever_live_p (i) - || (!leaf_function_p () && call_used_regs[i])) - { - if (i == REG_A0 || i == REG_A1) - insn = emit_move_insn (gen_rtx_MEM (PDImode, predec1), - gen_rtx_REG (PDImode, i)); - else - insn = emit_move_insn (predec, gen_rtx_REG (SImode, i)); - RTX_FRAME_RELATED_P (insn) = 1; - } - if (lookup_attribute ("nesting", attrs)) { rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX @@ -859,13 +1087,11 @@ expand_interrupt_handler_prologue (rtx spreg, e_funkind fkind) SPREG contains (reg:SI REG_SP). */ static void -expand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind) +expand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind, bool all) { - int i; + tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); rtx postinc1 = gen_rtx_POST_INC (SImode, spreg); rtx postinc = gen_rtx_MEM (SImode, postinc1); - tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); - bool all = lookup_attribute ("saveall", attrs) != NULL_TREE; /* A slightly crude technique to stop flow from trying to delete "dead" insns. */ @@ -886,25 +1112,8 @@ expand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind) if (!current_function_is_leaf) all = true; - for (i = REG_CC - 1; i > REG_P7; i--) - if (all - || df_regs_ever_live_p (i) - || (!leaf_function_p () && call_used_regs[i])) - { - if (i == REG_A0 || i == REG_A1) - { - rtx mem = gen_rtx_MEM (PDImode, postinc1); - MEM_VOLATILE_P (mem) = 1; - emit_move_insn (gen_rtx_REG (PDImode, i), mem); - } - else - emit_move_insn (gen_rtx_REG (SImode, i), postinc); - } - expand_epilogue_reg_restore (spreg, all, true); - emit_move_insn (gen_rtx_REG (SImode, REG_ASTAT), postinc); - /* Deallocate any space we left on the stack in case we needed to save the argument registers. */ if (fkind == EXCPT_HANDLER) @@ -949,10 +1158,12 @@ bfin_expand_prologue (void) rtx spreg = gen_rtx_REG (Pmode, REG_SP); e_funkind fkind = funkind (TREE_TYPE (current_function_decl)); rtx pic_reg_loaded = NULL_RTX; + tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); + bool all = lookup_attribute ("saveall", attrs) != NULL_TREE; if (fkind != SUBROUTINE) { - expand_interrupt_handler_prologue (spreg, fkind); + expand_interrupt_handler_prologue (spreg, fkind, all); return; } @@ -1002,7 +1213,7 @@ bfin_expand_prologue (void) emit_insn (gen_compare_lt (bfin_cc_rtx, spreg, lim)); emit_insn (gen_trapifcc ()); } - expand_prologue_reg_save (spreg, 0, false); + expand_prologue_reg_save (spreg, all, false); do_link (spreg, frame_size, false); @@ -1024,16 +1235,18 @@ bfin_expand_epilogue (int need_return, int eh_return, bool sibcall_p) rtx spreg = gen_rtx_REG (Pmode, REG_SP); e_funkind fkind = funkind (TREE_TYPE (current_function_decl)); int e = sibcall_p ? -1 : 1; + tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); + bool all = lookup_attribute ("saveall", attrs) != NULL_TREE; if (fkind != SUBROUTINE) { - expand_interrupt_handler_epilogue (spreg, fkind); + expand_interrupt_handler_epilogue (spreg, fkind, all); return; } do_unlink (spreg, get_frame_size (), false, e); - expand_epilogue_reg_restore (spreg, false, false); + expand_epilogue_reg_restore (spreg, all, false); /* Omit the return insn if this is for a sibcall. */ if (! need_return) @@ -2045,8 +2258,8 @@ bfin_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED, scratch register. */ static enum reg_class -bfin_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x, enum reg_class class, - enum machine_mode mode, secondary_reload_info *sri) +bfin_secondary_reload (bool in_p, rtx x, enum reg_class class, + enum machine_mode mode, secondary_reload_info *sri) { /* If we have HImode or QImode, we can only use DREGS as secondary registers; in most other cases we can also use PREGS. */ @@ -2074,7 +2287,7 @@ bfin_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x, enum reg_class class, if (fp_plus_const_operand (x, mode)) { rtx op2 = XEXP (x, 1); - int large_constant_p = ! CONST_7BIT_IMM_P (INTVAL (op2)); + int large_constant_p = ! satisfies_constraint_Ks7 (op2); if (class == PREGS || class == PREGS_CLOBBERED) return NO_REGS; @@ -2099,8 +2312,16 @@ bfin_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x, enum reg_class class, if (class == AREGS || class == EVEN_AREGS || class == ODD_AREGS) { + if (code == MEM) + { + sri->icode = in_p ? CODE_FOR_reload_inpdi : CODE_FOR_reload_outpdi; + return NO_REGS; + } + if (x != const0_rtx && x_class != DREGS) - return DREGS; + { + return DREGS; + } else return NO_REGS; } @@ -2116,6 +2337,7 @@ bfin_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x, enum reg_class class, if (code == MEM) if (! reg_class_subset_p (class, default_class)) return default_class; + return NO_REGS; } @@ -2134,26 +2356,79 @@ bfin_handle_option (size_t code, const char *arg, int value) return true; case OPT_mcpu_: - if (strcmp (arg, "bf531") == 0) - bfin_cpu_type = BFIN_CPU_BF531; - else if (strcmp (arg, "bf532") == 0) - bfin_cpu_type = BFIN_CPU_BF532; - else if (strcmp (arg, "bf533") == 0) - bfin_cpu_type = BFIN_CPU_BF533; - else if (strcmp (arg, "bf534") == 0) - bfin_cpu_type = BFIN_CPU_BF534; - else if (strcmp (arg, "bf536") == 0) - bfin_cpu_type = BFIN_CPU_BF536; - else if (strcmp (arg, "bf537") == 0) - bfin_cpu_type = BFIN_CPU_BF537; - else if (strcmp (arg, "bf561") == 0) - { + { + const char *p, *q; + int i; + + i = 0; + while ((p = bfin_cpus[i].name) != NULL) + { + if (strncmp (arg, p, strlen (p)) == 0) + break; + i++; + } + + if (p == NULL) + { + error ("-mcpu=%s is not valid", arg); + return false; + } + + bfin_cpu_type = bfin_cpus[i].type; + + q = arg + strlen (p); + + cputype_selected = true; + + if (*q == '\0') + { + bfin_si_revision = bfin_cpus[i].si_revision; + bfin_workarounds |= bfin_cpus[i].workarounds; + } + else if (strcmp (q, "-none") == 0) + bfin_si_revision = -1; + else if (strcmp (q, "-any") == 0) + { + bfin_si_revision = 0xffff; + while (bfin_cpus[i].type == bfin_cpu_type) + { + bfin_workarounds |= bfin_cpus[i].workarounds; + i++; + } + } + else + { + unsigned int si_major, si_minor; + int rev_len, n; + + rev_len = strlen (q); + + if (sscanf (q, "-%u.%u%n", &si_major, &si_minor, &n) != 2 + || n != rev_len + || si_major > 0xff || si_minor > 0xff) + { + invalid_silicon_revision: + error ("-mcpu=%s has invalid silicon revision", arg); + return false; + } + + bfin_si_revision = (si_major << 8) | si_minor; + + while (bfin_cpus[i].type == bfin_cpu_type + && bfin_cpus[i].si_revision != bfin_si_revision) + i++; + + if (bfin_cpus[i].type != bfin_cpu_type) + goto invalid_silicon_revision; + + bfin_workarounds |= bfin_cpus[i].workarounds; + } + + if (bfin_cpu_type == BFIN_CPU_BF561) warning (0, "bf561 support is incomplete yet."); - bfin_cpu_type = BFIN_CPU_BF561; - } - else - return false; - return true; + + return true; + } default: return true; @@ -2175,6 +2450,19 @@ bfin_init_machine_status (void) void override_options (void) { + if (bfin_csync_anomaly == 1) + bfin_workarounds |= WA_SPECULATIVE_SYNCS; + else if (bfin_csync_anomaly == 0) + bfin_workarounds &= ~WA_SPECULATIVE_SYNCS; + + if (bfin_specld_anomaly == 1) + bfin_workarounds |= WA_SPECULATIVE_LOADS; + else if (bfin_specld_anomaly == 0) + bfin_workarounds &= ~WA_SPECULATIVE_LOADS; + + if (!cputype_selected) + bfin_workarounds |= WA_RETS; + if (TARGET_OMIT_LEAF_FRAME_POINTER) flag_omit_frame_pointer = 1; @@ -2182,9 +2470,6 @@ override_options (void) if (bfin_lib_id_given && ! TARGET_ID_SHARED_LIBRARY) error ("-mshared-library-id= specified without -mid-shared-library"); - if (TARGET_ID_SHARED_LIBRARY && flag_pic == 0) - flag_pic = 1; - if (stack_limit_rtx && TARGET_STACK_CHECK_L1) error ("Can't use multiple stack checking methods together."); @@ -2199,6 +2484,9 @@ override_options (void) if (TARGET_SEP_DATA) target_flags |= MASK_ID_SHARED_LIBRARY | MASK_LEAF_ID_SHARED_LIBRARY; + if (TARGET_ID_SHARED_LIBRARY && flag_pic == 0) + flag_pic = 1; + /* There is no single unaligned SI op for PIC code. Sometimes we need to use ".4byte" and sometimes we need to use ".picptr". See bfin_assemble_integer for details. */ @@ -2425,7 +2713,7 @@ split_load_immediate (rtx operands[]) if (D_REGNO_P (regno)) { - if (CONST_7BIT_IMM_P (tmp)) + if (tmp >= -64 && tmp <= 63) { emit_insn (gen_movsi (operands[0], GEN_INT (tmp))); emit_insn (gen_movstricthi_high (operands[0], GEN_INT (val & -65536))); @@ -2452,7 +2740,7 @@ split_load_immediate (rtx operands[]) return 0; if (optimize_size - && num_compl_zero && CONST_7BIT_IMM_P (shifted_compl)) + && num_compl_zero && shifted_compl >= -64 && shifted_compl <= 63) { /* If optimizing for size, generate a sequence that has more instructions but is shorter. */ @@ -2583,7 +2871,7 @@ bfin_rtx_costs (rtx x, int code, int outer_code, int *total) { case CONST_INT: if (outer_code == SET || outer_code == PLUS) - *total = CONST_7BIT_IMM_P (INTVAL (x)) ? 0 : cost2; + *total = satisfies_constraint_Ks7 (x) ? 0 : cost2; else if (outer_code == AND) *total = log2constp (~INTVAL (x)) ? 0 : cost2; else if (outer_code == LE || outer_code == LT || outer_code == EQ) @@ -2641,7 +2929,7 @@ bfin_rtx_costs (rtx x, int code, int outer_code, int *total) { *total = 6 * cost2; if (GET_CODE (op1) != CONST_INT - || !CONST_7BIT_IMM_P (INTVAL (op1))) + || !satisfies_constraint_Ks7 (op1)) *total += rtx_cost (op1, PLUS); if (GET_CODE (op0) != REG && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG)) @@ -3108,6 +3396,8 @@ bfin_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost) if (dep_insn_type == TYPE_MOVE || dep_insn_type == TYPE_MCLD) { rtx pat = PATTERN (dep_insn); + if (GET_CODE (pat) == PARALLEL) + pat = XVECEXP (pat, 0, 0); rtx dest = SET_DEST (pat); rtx src = SET_SRC (pat); if (! ADDRESS_REGNO_P (REGNO (dest)) @@ -3303,14 +3593,14 @@ length_for_loop (rtx insn) int length = 0; if (JUMP_P (insn) && any_condjump_p (insn) && !optimize_size) { - if (TARGET_CSYNC_ANOMALY) + if (ENABLE_WA_SPECULATIVE_SYNCS) length = 8; - else if (TARGET_SPECLD_ANOMALY) + else if (ENABLE_WA_SPECULATIVE_LOADS) length = 6; } else if (LABEL_P (insn)) { - if (TARGET_CSYNC_ANOMALY) + if (ENABLE_WA_SPECULATIVE_SYNCS) length = 4; } @@ -4419,7 +4709,7 @@ bfin_reorg (void) if (cfun->machine->has_hardware_loops) bfin_reorg_loops (dump_file); - if (! TARGET_SPECLD_ANOMALY && ! TARGET_CSYNC_ANOMALY) + if (! ENABLE_WA_SPECULATIVE_LOADS && ! ENABLE_WA_SPECULATIVE_SYNCS) return; /* First pass: find predicted-false branches; if something after them @@ -4458,12 +4748,12 @@ bfin_reorg (void) if (cycles_since_jump < INT_MAX) cycles_since_jump++; - if (load_insn && TARGET_SPECLD_ANOMALY) + if (load_insn && ENABLE_WA_SPECULATIVE_LOADS) { if (trapping_loads_p (load_insn)) delay_needed = 3; } - else if (type == TYPE_SYNC && TARGET_CSYNC_ANOMALY) + else if (type == TYPE_SYNC && ENABLE_WA_SPECULATIVE_SYNCS) delay_needed = 4; if (delay_needed > cycles_since_jump) @@ -4494,7 +4784,10 @@ bfin_reorg (void) } /* Second pass: for predicted-true branches, see if anything at the branch destination needs extra nops. */ - if (! TARGET_CSYNC_ANOMALY) + if (! ENABLE_WA_SPECULATIVE_SYNCS) + return; + + if (! ENABLE_WA_RETS) return; for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) @@ -4527,7 +4820,7 @@ bfin_reorg (void) if (cycles_since_jump < INT_MAX) cycles_since_jump++; - if (type == TYPE_SYNC && TARGET_CSYNC_ANOMALY) + if (type == TYPE_SYNC && ENABLE_WA_SPECULATIVE_SYNCS) delay_needed = 2; if (delay_needed > cycles_since_jump) @@ -4872,6 +5165,7 @@ enum bfin_builtins { BFIN_BUILTIN_CSYNC, BFIN_BUILTIN_SSYNC, + BFIN_BUILTIN_ONES, BFIN_BUILTIN_COMPOSE_2X16, BFIN_BUILTIN_EXTRACTLO, BFIN_BUILTIN_EXTRACTHI, @@ -4928,6 +5222,12 @@ enum bfin_builtins BFIN_BUILTIN_CPLX_MAC_16, BFIN_BUILTIN_CPLX_MSU_16, + BFIN_BUILTIN_CPLX_MUL_16_S40, + BFIN_BUILTIN_CPLX_MAC_16_S40, + BFIN_BUILTIN_CPLX_MSU_16_S40, + + BFIN_BUILTIN_CPLX_SQU, + BFIN_BUILTIN_MAX }; @@ -4987,6 +5287,8 @@ bfin_init_builtins (void) def_builtin ("__builtin_bfin_csync", void_ftype_void, BFIN_BUILTIN_CSYNC); def_builtin ("__builtin_bfin_ssync", void_ftype_void, BFIN_BUILTIN_SSYNC); + def_builtin ("__builtin_bfin_ones", short_ftype_int, BFIN_BUILTIN_ONES); + def_builtin ("__builtin_bfin_compose_2x16", v2hi_ftype_int_int, BFIN_BUILTIN_COMPOSE_2X16); def_builtin ("__builtin_bfin_extract_hi", short_ftype_v2hi, @@ -5016,6 +5318,11 @@ bfin_init_builtins (void) def_builtin ("__builtin_bfin_abs_fr2x16", v2hi_ftype_v2hi, BFIN_BUILTIN_ABS_2X16); + def_builtin ("__builtin_bfin_min_fr1x16", short_ftype_int_int, + BFIN_BUILTIN_MIN_1X16); + def_builtin ("__builtin_bfin_max_fr1x16", short_ftype_int_int, + BFIN_BUILTIN_MAX_1X16); + def_builtin ("__builtin_bfin_add_fr1x16", short_ftype_int_int, BFIN_BUILTIN_SSADD_1X16); def_builtin ("__builtin_bfin_sub_fr1x16", short_ftype_int_int, @@ -5047,6 +5354,11 @@ bfin_init_builtins (void) def_builtin ("__builtin_bfin_mulhisihh", int_ftype_v2hi_v2hi, BFIN_BUILTIN_MULHISIHH); + def_builtin ("__builtin_bfin_min_fr1x32", int_ftype_int_int, + BFIN_BUILTIN_MIN_1X32); + def_builtin ("__builtin_bfin_max_fr1x32", int_ftype_int_int, + BFIN_BUILTIN_MAX_1X32); + def_builtin ("__builtin_bfin_add_fr1x32", int_ftype_int_int, BFIN_BUILTIN_SSADD_1X32); def_builtin ("__builtin_bfin_sub_fr1x32", int_ftype_int_int, @@ -5079,12 +5391,24 @@ bfin_init_builtins (void) BFIN_BUILTIN_SSASHIFT_1X32); /* Complex numbers. */ + def_builtin ("__builtin_bfin_cmplx_add", v2hi_ftype_v2hi_v2hi, + BFIN_BUILTIN_SSADD_2X16); + def_builtin ("__builtin_bfin_cmplx_sub", v2hi_ftype_v2hi_v2hi, + BFIN_BUILTIN_SSSUB_2X16); def_builtin ("__builtin_bfin_cmplx_mul", v2hi_ftype_v2hi_v2hi, BFIN_BUILTIN_CPLX_MUL_16); def_builtin ("__builtin_bfin_cmplx_mac", v2hi_ftype_v2hi_v2hi_v2hi, BFIN_BUILTIN_CPLX_MAC_16); def_builtin ("__builtin_bfin_cmplx_msu", v2hi_ftype_v2hi_v2hi_v2hi, BFIN_BUILTIN_CPLX_MSU_16); + def_builtin ("__builtin_bfin_cmplx_mul_s40", v2hi_ftype_v2hi_v2hi, + BFIN_BUILTIN_CPLX_MUL_16_S40); + def_builtin ("__builtin_bfin_cmplx_mac_s40", v2hi_ftype_v2hi_v2hi_v2hi, + BFIN_BUILTIN_CPLX_MAC_16_S40); + def_builtin ("__builtin_bfin_cmplx_msu_s40", v2hi_ftype_v2hi_v2hi_v2hi, + BFIN_BUILTIN_CPLX_MSU_16_S40); + def_builtin ("__builtin_bfin_csqu_fr16", v2hi_ftype_v2hi, + BFIN_BUILTIN_CPLX_SQU); } @@ -5132,6 +5456,8 @@ static const struct builtin_description bdesc_2arg[] = static const struct builtin_description bdesc_1arg[] = { + { CODE_FOR_ones, "__builtin_bfin_ones", BFIN_BUILTIN_ONES, 0 }, + { CODE_FOR_signbitshi2, "__builtin_bfin_norm_fr1x16", BFIN_BUILTIN_NORM_1X16, 0 }, { CODE_FOR_ssneghi2, "__builtin_bfin_negate_fr1x16", BFIN_BUILTIN_NEG_1X16, 0 }, { CODE_FOR_abshi2, "__builtin_bfin_abs_fr1x16", BFIN_BUILTIN_ABS_1X16, 0 }, @@ -5372,6 +5698,7 @@ bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED, return target; case BFIN_BUILTIN_CPLX_MUL_16: + case BFIN_BUILTIN_CPLX_MUL_16_S40: arg0 = CALL_EXPR_ARG (exp, 0); arg1 = CALL_EXPR_ARG (exp, 1); op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); @@ -5387,9 +5714,14 @@ bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED, if (! register_operand (op1, GET_MODE (op1))) op1 = copy_to_mode_reg (GET_MODE (op1), op1); - emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx, - const0_rtx, const0_rtx, - const1_rtx, GEN_INT (MACFLAG_NONE))); + if (fcode == BFIN_BUILTIN_CPLX_MUL_16) + emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx, + const0_rtx, const0_rtx, + const1_rtx, GEN_INT (MACFLAG_W32))); + else + emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx, + const0_rtx, const0_rtx, + const1_rtx, GEN_INT (MACFLAG_NONE))); emit_insn (gen_flag_macv2hi_parts (target, op0, op1, const1_rtx, const1_rtx, const1_rtx, const0_rtx, accvec, const1_rtx, const0_rtx, @@ -5399,6 +5731,8 @@ bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED, case BFIN_BUILTIN_CPLX_MAC_16: case BFIN_BUILTIN_CPLX_MSU_16: + case BFIN_BUILTIN_CPLX_MAC_16_S40: + case BFIN_BUILTIN_CPLX_MSU_16_S40: arg0 = CALL_EXPR_ARG (exp, 0); arg1 = CALL_EXPR_ARG (exp, 1); arg2 = CALL_EXPR_ARG (exp, 2); @@ -5422,13 +5756,30 @@ bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED, emit_move_insn (tmp2, gen_lowpart (SImode, op0)); emit_insn (gen_movstricthi_1 (gen_lowpart (HImode, tmp2), const0_rtx)); emit_insn (gen_load_accumulator_pair (accvec, tmp1, tmp2)); - emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op1, op2, const0_rtx, - const0_rtx, const0_rtx, - const1_rtx, accvec, const0_rtx, - const0_rtx, - GEN_INT (MACFLAG_W32))); - tmp1 = (fcode == BFIN_BUILTIN_CPLX_MAC_16 ? const1_rtx : const0_rtx); - tmp2 = (fcode == BFIN_BUILTIN_CPLX_MAC_16 ? const0_rtx : const1_rtx); + if (fcode == BFIN_BUILTIN_CPLX_MAC_16 + || fcode == BFIN_BUILTIN_CPLX_MSU_16) + emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op1, op2, const0_rtx, + const0_rtx, const0_rtx, + const1_rtx, accvec, const0_rtx, + const0_rtx, + GEN_INT (MACFLAG_W32))); + else + emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op1, op2, const0_rtx, + const0_rtx, const0_rtx, + const1_rtx, accvec, const0_rtx, + const0_rtx, + GEN_INT (MACFLAG_NONE))); + if (fcode == BFIN_BUILTIN_CPLX_MAC_16 + || fcode == BFIN_BUILTIN_CPLX_MAC_16_S40) + { + tmp1 = const1_rtx; + tmp2 = const0_rtx; + } + else + { + tmp1 = const0_rtx; + tmp2 = const1_rtx; + } emit_insn (gen_flag_macv2hi_parts (target, op1, op2, const1_rtx, const1_rtx, const1_rtx, const0_rtx, accvec, tmp1, tmp2, @@ -5436,6 +5787,35 @@ bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED, return target; + case BFIN_BUILTIN_CPLX_SQU: + arg0 = CALL_EXPR_ARG (exp, 0); + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + accvec = gen_reg_rtx (V2PDImode); + icode = CODE_FOR_flag_mulv2hi; + tmp1 = gen_reg_rtx (V2HImode); + tmp2 = gen_reg_rtx (V2HImode); + + if (! target + || GET_MODE (target) != V2HImode + || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode)) + target = gen_reg_rtx (V2HImode); + if (! register_operand (op0, GET_MODE (op0))) + op0 = copy_to_mode_reg (GET_MODE (op0), op0); + + emit_insn (gen_flag_mulv2hi (tmp1, op0, op0, GEN_INT (MACFLAG_NONE))); + + emit_insn (gen_flag_mulhi_parts (tmp2, op0, op0, const0_rtx, + const0_rtx, const1_rtx, + GEN_INT (MACFLAG_NONE))); + + emit_insn (gen_ssaddhi3_parts (target, tmp2, tmp2, const1_rtx, + const0_rtx, const0_rtx)); + + emit_insn (gen_sssubhi3_parts (target, tmp1, tmp1, const0_rtx, + const0_rtx, const1_rtx)); + + return target; + default: break; }