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"
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;
}
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
class = GET_MODE_CLASS (mode);
- if (flag_force_mem)
- {
- /* Load duplicate non-volatile operands once. */
- if (rtx_equal_p (op0, op1) && ! volatile_refs_p (op0))
- {
- op0 = force_not_mem (op0);
- op1 = op0;
- }
- else
- {
- op0 = force_not_mem (op0);
- op1 = force_not_mem (op1);
- }
- }
-
/* If subtracting an integer constant, convert this into an addition of
the negated constant. */
class = GET_MODE_CLASS (mode);
- if (flag_force_mem)
- op0 = force_not_mem (op0);
-
if (!targ0)
targ0 = gen_reg_rtx (mode);
if (!targ1)
class = GET_MODE_CLASS (mode);
- if (flag_force_mem)
- {
- op0 = force_not_mem (op0);
- op1 = force_not_mem (op1);
- }
-
/* If we are inside an appropriately-short loop and we are optimizing,
force expensive constants into a register. */
if (CONSTANT_P (op0) && optimize
class = GET_MODE_CLASS (mode);
- if (flag_force_mem)
- op0 = force_not_mem (op0);
-
if (unoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
int icode = (int) unoptab->handlers[(int) mode].insn_code;
temp = target;
- /* Sign and zero extension from memory is often done specially on
- RISC machines, so forcing into a register here can pessimize
- code. */
- if (flag_force_mem && code != SIGN_EXTEND && code != ZERO_EXTEND)
- op0 = force_not_mem (op0);
-
/* Now, if insn does not accept our operands, put them into pseudos. */
if (!insn_data[icode].operand[1].predicate (op0, mode0))
op0 = copy_to_mode_reg (mode0, op0);
- if (!insn_data[icode].operand[0].predicate (temp, GET_MODE (temp))
- || (flag_force_mem && MEM_P (temp)))
+ if (!insn_data[icode].operand[0].predicate (temp, GET_MODE (temp)))
temp = gen_reg_rtx (GET_MODE (temp));
pat = GEN_FCN (icode) (temp, op0);
emit_move_insn (target, temp);
}
\f
+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.
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);
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;
class = GET_MODE_CLASS (mode);
- if (mode != BLKmode && flag_force_mem)
- {
- /* Load duplicate non-volatile operands once. */
- if (rtx_equal_p (x, y) && ! volatile_refs_p (x))
- {
- x = force_not_mem (x);
- y = x;
- }
- else
- {
- x = force_not_mem (x);
- y = force_not_mem (y);
- }
- }
-
/* If we are inside an appropriately-short loop and we are optimizing,
force expensive constants into a register. */
if (CONSTANT_P (x) && optimize
if (cmp_code == CODE_FOR_nothing)
cmp_code = cmpstr_optab[cmp_mode];
if (cmp_code == CODE_FOR_nothing)
+ cmp_code = cmpstrn_optab[cmp_mode];
+ if (cmp_code == CODE_FOR_nothing)
continue;
/* Must make sure the size fits the insn's mode. */
if (icode == CODE_FOR_nothing)
return 0;
- if (flag_force_mem)
- {
- op2 = force_not_mem (op2);
- op3 = force_not_mem (op3);
- }
-
if (!target)
target = gen_reg_rtx (mode);
if (icode == CODE_FOR_nothing)
return 0;
- if (flag_force_mem)
- {
- op2 = force_not_mem (op2);
- op3 = force_not_mem (op3);
- }
-
if (!target)
target = gen_reg_rtx (mode);
rtx temp;
REAL_VALUE_TYPE offset;
- if (flag_force_mem)
- from = force_not_mem (from);
-
/* Look for a usable floating mode FMODE wider than the source and at
least as wide as the target. Using FMODE will avoid rounding woes
with unsigned values greater than the signed maximum value. */
if (GET_MODE_SIZE (GET_MODE (from)) < GET_MODE_SIZE (SImode))
from = convert_to_mode (SImode, from, unsignedp);
- if (flag_force_mem)
- from = force_not_mem (from);
-
libfunc = tab->handlers[GET_MODE (to)][GET_MODE (from)].libfunc;
gcc_assert (libfunc);
lab1 = gen_label_rtx ();
lab2 = gen_label_rtx ();
- if (flag_force_mem)
- from = force_not_mem (from);
-
if (fmode != GET_MODE (from))
from = convert_to_mode (fmode, from, 0);
libfunc = tab->handlers[GET_MODE (to)][GET_MODE (from)].libfunc;
gcc_assert (libfunc);
- if (flag_force_mem)
- from = force_not_mem (from);
-
start_sequence ();
value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
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);
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;
+ cmpstrn_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;
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");
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);