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"
#ifndef HAVE_conditional_trap
#define HAVE_conditional_trap 0
+#define gen_conditional_trap(a,b) (gcc_unreachable (), NULL_RTX)
#endif
\f
/* Add a REG_EQUAL note to the last insn in INSNS. TARGET is being set to
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;
comparison or emitting a library call to perform the comparison if no insn
is available to handle it.
The values which are passed in through pointers can be modified; the caller
- should perform the comparison on the modified values. */
+ should perform the comparison on the modified values. Constant
+ comparisons must have already been folded. */
static void
prepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
class = GET_MODE_CLASS (mode);
- /* They could both be VOIDmode if both args are immediate constants,
- but we should fold that at an earlier stage.
- With no special code here, this will call abort,
- reminding the programmer to implement such folding. */
-
- 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
y = force_reg (mode, y);
#ifdef HAVE_cc0
- /* Abort if we have a non-canonical comparison. The RTL documentation
- states that canonical comparisons are required only for targets which
- have cc0. */
+ /* Make sure if we have a canonical comparison. The RTL
+ documentation states that canonical comparisons are required only
+ for targets which have cc0. */
gcc_assert (!CONSTANT_P (x) || CONSTANT_P (y));
#endif
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. */
}
#ifdef HAVE_cc0
- /* If OP0 is still a constant, then both X and Y must be constants. Force
- X into a register to avoid aborting in emit_cmp_insn due to non-canonical
- RTL. */
+ /* If OP0 is still a constant, then both X and Y must be constants.
+ Force X into a register to create canonical RTL. */
if (CONSTANT_P (op0))
op0 = force_reg (mode, op0);
#endif
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");
/* Ensure that if old_val == mem, that we're not comparing
against an old value. */
- if (GET_CODE (old_val) == MEM)
+ if (MEM_P (old_val))
old_val = force_reg (mode, old_val);
subtarget = expand_val_compare_and_swap_1 (mem, old_val, new_val,
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);
{
enum machine_mode mode = GET_MODE (mem);
enum insn_code icode;
- rtx label, subtarget;
+ rtx label, cmp_reg, subtarget;
/* The loop we want to generate looks like
- old_reg = mem;
+ cmp_reg = mem;
label:
+ old_reg = cmp_reg;
seq;
- old_reg = compare-and-swap(mem, old_reg, new_reg)
- if (old_reg != new_reg)
+ cmp_reg = compare-and-swap(mem, old_reg, new_reg)
+ if (cmp_reg != old_reg)
goto label;
Note that we only do the plain load from memory once. Subsequent
iterations use the value loaded by the compare-and-swap pattern. */
label = gen_label_rtx ();
+ cmp_reg = gen_reg_rtx (mode);
- emit_move_insn (old_reg, mem);
+ emit_move_insn (cmp_reg, mem);
emit_label (label);
+ emit_move_insn (old_reg, cmp_reg);
if (seq)
emit_insn (seq);
{
default:
subtarget = expand_val_compare_and_swap_1 (mem, old_reg, new_reg,
- old_reg, icode);
+ cmp_reg, icode);
if (subtarget != NULL_RTX)
- break;
+ {
+ gcc_assert (subtarget == cmp_reg);
+ break;
+ }
/* FALLTHRU */
case CODE_FOR_nothing:
return false;
subtarget = expand_val_compare_and_swap_1 (mem, old_reg, new_reg,
- old_reg, icode);
+ cmp_reg, icode);
if (subtarget == NULL_RTX)
return false;
+ if (subtarget != cmp_reg)
+ emit_move_insn (cmp_reg, subtarget);
- emit_cmp_insn (subtarget, old_reg, EQ, const0_rtx, mode, true);
+ emit_cmp_insn (cmp_reg, old_reg, EQ, const0_rtx, mode, true);
}
/* ??? Mark this jump predicted not taken? */