X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Foptabs.c;h=2ed499e441fd63aeef4265bf95e2ea5eb5daeff0;hb=a866e0f2b523463de856075b7872e8acf2556c67;hp=2955f7b3ad998f633392ae1dedbf9149deca0910;hpb=c0a0647e646225dd85eb078beee46557680719ef;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/optabs.c b/gcc/optabs.c index 2955f7b3ad9..2ed499e441f 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -16,8 +16,8 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ #include "config.h" @@ -294,6 +294,21 @@ optab_for_tree_code (enum tree_code code, tree type) case REALIGN_LOAD_EXPR: return vec_realign_load_optab; + case REDUC_MAX_EXPR: + return TYPE_UNSIGNED (type) ? reduc_umax_optab : reduc_smax_optab; + + case REDUC_MIN_EXPR: + return TYPE_UNSIGNED (type) ? reduc_umin_optab : reduc_smin_optab; + + case REDUC_PLUS_EXPR: + return TYPE_UNSIGNED (type) ? reduc_uplus_optab : reduc_splus_optab; + + case VEC_LSHIFT_EXPR: + return vec_shl_optab; + + case VEC_RSHIFT_EXPR: + return vec_shr_optab; + default: break; } @@ -434,6 +449,61 @@ force_expand_binop (enum machine_mode mode, optab binoptab, return true; } +/* Generate insns for VEC_LSHIFT_EXPR, VEC_RSHIFT_EXPR. */ + +rtx +expand_vec_shift_expr (tree vec_shift_expr, rtx target) +{ + enum insn_code icode; + rtx rtx_op1, rtx_op2; + enum machine_mode mode1; + enum machine_mode mode2; + enum machine_mode mode = TYPE_MODE (TREE_TYPE (vec_shift_expr)); + tree vec_oprnd = TREE_OPERAND (vec_shift_expr, 0); + tree shift_oprnd = TREE_OPERAND (vec_shift_expr, 1); + optab shift_optab; + rtx pat; + + switch (TREE_CODE (vec_shift_expr)) + { + case VEC_RSHIFT_EXPR: + shift_optab = vec_shr_optab; + break; + case VEC_LSHIFT_EXPR: + shift_optab = vec_shl_optab; + break; + default: + gcc_unreachable (); + } + + icode = (int) shift_optab->handlers[(int) mode].insn_code; + gcc_assert (icode != CODE_FOR_nothing); + + mode1 = insn_data[icode].operand[1].mode; + mode2 = insn_data[icode].operand[2].mode; + + rtx_op1 = expand_expr (vec_oprnd, NULL_RTX, VOIDmode, EXPAND_NORMAL); + if (!(*insn_data[icode].operand[1].predicate) (rtx_op1, mode1) + && mode1 != VOIDmode) + rtx_op1 = force_reg (mode1, rtx_op1); + + rtx_op2 = expand_expr (shift_oprnd, NULL_RTX, VOIDmode, EXPAND_NORMAL); + if (!(*insn_data[icode].operand[2].predicate) (rtx_op2, mode2) + && mode2 != VOIDmode) + rtx_op2 = force_reg (mode2, rtx_op2); + + if (!target + || ! (*insn_data[icode].operand[0].predicate) (target, mode)) + target = gen_reg_rtx (mode); + + /* Emit instruction */ + pat = GEN_FCN (icode) (target, rtx_op1, rtx_op2); + gcc_assert (pat); + emit_insn (pat); + + return target; +} + /* This subroutine of expand_doubleword_shift handles the cases in which the effective shift value is >= BITS_PER_WORD. The arguments and return value are the same as for the parent routine, except that SUPERWORD_OP1 @@ -2943,6 +3013,39 @@ emit_unop_insn (int icode, rtx target, rtx op0, enum rtx_code code) emit_move_insn (target, temp); } +struct no_conflict_data +{ + rtx target, first, insn; + bool must_stay; +}; + +/* Called via note_stores by emit_no_conflict_block. Set P->must_stay + if the currently examined clobber / store has to stay in the list of + insns that constitute the actual no_conflict block. */ +static void +no_conflict_move_test (rtx dest, rtx set, void *p0) +{ + struct no_conflict_data *p= p0; + + /* If this inns directly contributes to setting the target, it must stay. */ + if (reg_overlap_mentioned_p (p->target, dest)) + p->must_stay = true; + /* If we haven't committed to keeping any other insns in the list yet, + there is nothing more to check. */ + else if (p->insn == p->first) + return; + /* If this insn sets / clobbers a register that feeds one of the insns + already in the list, this insn has to stay too. */ + else if (reg_mentioned_p (dest, PATTERN (p->first)) + || reg_used_between_p (dest, p->first, p->insn) + /* Likewise if this insn depends on a register set by a previous + insn in the list. */ + || (GET_CODE (set) == SET + && (modified_in_p (SET_SRC (set), p->first) + || modified_between_p (SET_SRC (set), p->first, p->insn)))) + p->must_stay = true; +} + /* Emit code to perform a series of operations on a multi-word quantity, one word at a time. @@ -2988,8 +3091,8 @@ emit_no_conflict_block (rtx insns, rtx target, rtx op0, rtx op1, rtx equiv) these from the list. */ for (insn = insns; insn; insn = next) { - rtx set = 0, note; - int i; + rtx note; + struct no_conflict_data data; next = NEXT_INSN (insn); @@ -3000,22 +3103,12 @@ emit_no_conflict_block (rtx insns, rtx target, rtx op0, rtx op1, rtx equiv) if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL) remove_note (insn, note); - if (GET_CODE (PATTERN (insn)) == SET || GET_CODE (PATTERN (insn)) == USE - || GET_CODE (PATTERN (insn)) == CLOBBER) - set = PATTERN (insn); - else if (GET_CODE (PATTERN (insn)) == PARALLEL) - { - for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++) - if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET) - { - set = XVECEXP (PATTERN (insn), 0, i); - break; - } - } - - gcc_assert (set); - - if (! reg_overlap_mentioned_p (target, SET_DEST (set))) + data.target = target; + data.first = insns; + data.insn = insn; + data.must_stay = 0; + note_stores (PATTERN (insn), no_conflict_move_test, &data); + if (! data.must_stay) { if (PREV_INSN (insn)) NEXT_INSN (PREV_INSN (insn)) = next; @@ -5038,9 +5131,18 @@ init_optabs (void) cstore_optab = init_optab (UNKNOWN); push_optab = init_optab (UNKNOWN); + reduc_smax_optab = init_optab (UNKNOWN); + reduc_umax_optab = init_optab (UNKNOWN); + reduc_smin_optab = init_optab (UNKNOWN); + reduc_umin_optab = init_optab (UNKNOWN); + reduc_splus_optab = init_optab (UNKNOWN); + reduc_uplus_optab = init_optab (UNKNOWN); + vec_extract_optab = init_optab (UNKNOWN); vec_set_optab = init_optab (UNKNOWN); vec_init_optab = init_optab (UNKNOWN); + vec_shl_optab = init_optab (UNKNOWN); + vec_shr_optab = init_optab (UNKNOWN); vec_realign_load_optab = init_optab (UNKNOWN); movmisalign_optab = init_optab (UNKNOWN); @@ -5060,9 +5162,9 @@ init_optabs (void) for (i = 0; i < NUM_MACHINE_MODES; i++) { movmem_optab[i] = CODE_FOR_nothing; - clrmem_optab[i] = CODE_FOR_nothing; cmpstr_optab[i] = CODE_FOR_nothing; cmpmem_optab[i] = CODE_FOR_nothing; + setmem_optab[i] = CODE_FOR_nothing; sync_add_optab[i] = CODE_FOR_nothing; sync_sub_optab[i] = CODE_FOR_nothing; @@ -5186,9 +5288,6 @@ init_optabs (void) memset_libfunc = init_one_libfunc ("memset"); setbits_libfunc = init_one_libfunc ("__setbits"); - unwind_resume_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS - ? "_Unwind_SjLj_Resume" - : "_Unwind_Resume"); #ifndef DONT_USE_BUILTIN_SETJMP setjmp_libfunc = init_one_libfunc ("__builtin_setjmp"); longjmp_libfunc = init_one_libfunc ("__builtin_longjmp"); @@ -5604,6 +5703,7 @@ expand_bool_compare_and_swap (rtx mem, rtx old_val, rtx new_val, rtx target) emit_jump_insn (bcc_gen_fctn[EQ] (label0)); emit_move_insn (target, const0_rtx); emit_jump_insn (gen_jump (label1)); + emit_barrier (); emit_label (label0); emit_move_insn (target, const1_rtx); emit_label (label1);