gcc_assert (data->status == AUTOPREF_MULTIPASS_DATA_UNINITIALIZED);
data->base = NULL_RTX;
- data->offset = 0;
+ data->min_offset = 0;
+ data->max_offset = 0;
+ data->multi_mem_insn_p = false;
/* Set insn entry initialized, but not relevant for auto-prefetcher. */
data->status = AUTOPREF_MULTIPASS_DATA_IRRELEVANT;
{
int n_elems = XVECLEN (pat, 0);
- int i, offset;
- rtx base, prev_base = NULL_RTX;
- int min_offset = INT_MAX;
+ int i = 0;
+ rtx prev_base = NULL_RTX;
+ int min_offset = 0;
+ int max_offset = 0;
for (i = 0; i < n_elems; i++)
{
if (GET_CODE (set) != SET)
return;
+ rtx base = NULL_RTX;
+ int offset = 0;
if (!analyze_set_insn_for_autopref (set, write, &base, &offset))
return;
+ if (i == 0)
+ {
+ prev_base = base;
+ min_offset = offset;
+ max_offset = offset;
+ }
/* Ensure that all memory operations in the PARALLEL use the same
base register. */
- if (i > 0 && REGNO (base) != REGNO (prev_base))
+ else if (REGNO (base) != REGNO (prev_base))
return;
- prev_base = base;
- min_offset = MIN (min_offset, offset);
+ else
+ {
+ min_offset = MIN (min_offset, offset);
+ max_offset = MAX (max_offset, offset);
+ }
}
- /* If we reached here then we have a valid PARALLEL of multiple memory ops
- with prev_base as the base and min_offset containing the offset. */
+ /* If we reached here then we have a valid PARALLEL of multiple memory
+ ops with prev_base as the base and min_offset and max_offset
+ containing the offsets range. */
gcc_assert (prev_base);
data->base = prev_base;
- data->offset = min_offset;
+ data->min_offset = min_offset;
+ data->max_offset = max_offset;
+ data->multi_mem_insn_p = true;
data->status = AUTOPREF_MULTIPASS_DATA_NORMAL;
+
return;
}
return;
if (!analyze_set_insn_for_autopref (set, write, &data->base,
- &data->offset))
+ &data->min_offset))
return;
/* This insn is relevant for the auto-prefetcher.
data->status = AUTOPREF_MULTIPASS_DATA_NORMAL;
}
+
+/* Helper for autopref_rank_for_schedule. Given the data of two
+ insns relevant to the auto-prefetcher modelling code DATA1 and DATA2
+ return their comparison result. Return 0 if there is no sensible
+ ranking order for the two insns. */
+
+static int
+autopref_rank_data (autopref_multipass_data_t data1,
+ autopref_multipass_data_t data2)
+{
+ /* Simple case when both insns are simple single memory ops. */
+ if (!data1->multi_mem_insn_p && !data2->multi_mem_insn_p)
+ return data1->min_offset - data2->min_offset;
+
+ /* Two load/store multiple insns. Return 0 if the offset ranges
+ overlap and the difference between the minimum offsets otherwise. */
+ else if (data1->multi_mem_insn_p && data2->multi_mem_insn_p)
+ {
+ int min1 = data1->min_offset;
+ int max1 = data1->max_offset;
+ int min2 = data2->min_offset;
+ int max2 = data2->max_offset;
+
+ if (max1 < min2 || min1 > max2)
+ return min1 - min2;
+ else
+ return 0;
+ }
+
+ /* The other two cases is a pair of a load/store multiple and
+ a simple memory op. Return 0 if the single op's offset is within the
+ range of the multi-op insn and the difference between the single offset
+ and the minimum offset of the multi-set insn otherwise. */
+ else if (data1->multi_mem_insn_p && !data2->multi_mem_insn_p)
+ {
+ int max1 = data1->max_offset;
+ int min1 = data1->min_offset;
+
+ if (data2->min_offset >= min1
+ && data2->min_offset <= max1)
+ return 0;
+ else
+ return min1 - data2->min_offset;
+ }
+ else
+ {
+ int max2 = data2->max_offset;
+ int min2 = data2->min_offset;
+
+ if (data1->min_offset >= min2
+ && data1->min_offset <= max2)
+ return 0;
+ else
+ return data1->min_offset - min2;
+ }
+}
+
/* Helper function for rank_for_schedule sorting. */
static int
autopref_rank_for_schedule (const rtx_insn *insn1, const rtx_insn *insn2)
int irrel2 = data2->status == AUTOPREF_MULTIPASS_DATA_IRRELEVANT;
if (!irrel1 && !irrel2)
- r = data1->offset - data2->offset;
+ r = autopref_rank_data (data1, data2);
else
r = irrel2 - irrel1;
}
return 0;
if (rtx_equal_p (data1->base, data2->base)
- && data1->offset > data2->offset)
+ && autopref_rank_data (data1, data2) > 0)
{
if (sched_verbose >= 2)
{