Hi,

on 2023/9/18 16:53, Richard Biener wrote:
> On Mon, Sep 18, 2023 at 10:41 AM Richard Sandiford
> <richard.sandif...@arm.com> wrote:
>>
>> Kewen Lin <li...@linux.ibm.com> writes:
>>> This costing adjustment patch series exposes one issue in
>>> aarch64 specific costing adjustment for STP sequence.  It
>>> causes the below test cases to fail:
>>>
>>>   - gcc/testsuite/gcc.target/aarch64/ldp_stp_15.c
>>>   - gcc/testsuite/gcc.target/aarch64/ldp_stp_16.c
>>>   - gcc/testsuite/gcc.target/aarch64/ldp_stp_17.c
>>>   - gcc/testsuite/gcc.target/aarch64/ldp_stp_18.c
>>>
>>> Take the below function extracted from ldp_stp_15.c as
>>> example:
>>>
>>> void
>>> dup_8_int32_t (int32_t *x, int32_t val)
>>> {
>>>     for (int i = 0; i < 8; ++i)
>>>           x[i] = val;
>>> }
>>>
>>> Without my patch series, during slp1 it gets:
>>>
>>>   val_8(D) 2 times unaligned_store (misalign -1) costs 2 in body
>>>   node 0x10008c85e38 1 times scalar_to_vec costs 1 in prologue
>>>
>>> then the final vector cost is 3.
>>>
>>> With my patch series, during slp1 it gets:
>>>
>>>   val_8(D) 1 times unaligned_store (misalign -1) costs 1 in body
>>>   val_8(D) 1 times unaligned_store (misalign -1) costs 1 in body
>>>   node 0x10004cc5d88 1 times scalar_to_vec costs 1 in prologue
>>>
>>> but the final vector cost is 17.  The unaligned_store count is
>>> actually unchanged, but the final vector costs become different,
>>> it's because the below aarch64 special handling makes the
>>> different costs:
>>>
>>>   /* Apply the heuristic described above m_stp_sequence_cost.  */
>>>   if (m_stp_sequence_cost != ~0U)
>>>     {
>>>       uint64_t cost = aarch64_stp_sequence_cost (count, kind,
>>>                                                stmt_info, vectype);
>>>       m_stp_sequence_cost = MIN (m._stp_sequence_cost + cost, ~0U);
>>>     }
>>>
>>> For the former, since the count is 2, function
>>> aarch64_stp_sequence_cost returns 2 as "CEIL (count, 2) * 2".
>>> While for the latter, it's separated into twice calls with
>>> count 1, aarch64_stp_sequence_cost returns 2 for each time,
>>> so it returns 4 in total.
>>>
>>> For this case, the stmt with scalar_to_vec also contributes
>>> 4 to m_stp_sequence_cost, then the final m_stp_sequence_cost
>>> are 6 (2+4) vs. 8 (4+4).
>>>
>>> Considering scalar_costs->m_stp_sequence_cost is 8 and below
>>> checking and re-assigning:
>>>
>>>   else if (m_stp_sequence_cost >= scalar_costs->m_stp_sequence_cost)
>>>     m_costs[vect_body] = 2 * scalar_costs->total_cost ();
>>>
>>> For the former, the body cost of vector isn't changed; but
>>> for the latter, the body cost of vector is double of scalar
>>> cost which is 8 for this case, then it becomes 16 which is
>>> bigger than what we expect.
>>>
>>> I'm not sure why it adopts CEIL for the return value for
>>> case unaligned_store in function aarch64_stp_sequence_cost,
>>> but I tried to modify it with "return count;" (as it can
>>> get back to previous cost), there is no failures exposed
>>> in regression testing.  I expected that if the previous
>>> unaligned_store count is even, this adjustment doesn't
>>> change anything, if it's odd, the adjustment may reduce
>>> it by one, but I'd guess it would be few.  Besides, as
>>> the comments for m_stp_sequence_cost, the current
>>> handlings seems temporary, maybe a tweak like this can be
>>> accepted, so I posted this RFC/PATCH to request comments.
>>> this one line change is considered.
>>
>> It's unfortunate that doing this didn't show up a regression.
>> I guess it's not a change we explicitly added tests to guard against.
>>
>> But the point of the condition is to estimate how many single stores
>> (STRs) and how many paired stores (STPs) would be generated.  As far
>> as this heuristic goes, STP (storing two values) is as cheap as STR
>> (storing only one value).  So the point of the CEIL is to count 1 store
>> as having equal cost to 2, 3 as having equal cost to 4, etc.
>>

Thanks for the explanation and ...

>> For a heuristic like that, costing a vector stmt once with count 2
>> is different from costing 2 vector stmts with count 1.  The former
>> makes it obvious that the 2 vector stmts are associated with the
>> same scalar stmt, and are highly likely to be consecutive.  The latter
>> (costing 2 stmts with count 1) could also happen for unrelated stmts.
>>
>> ISTM that costing once with count N provides strictly more information
>> to targets than costing N time with count 1.  Is there no way we can
>> keep the current behaviour?  E.g. rather than costing a stmt immediately
>> within a loop, could we just increment a counter and cost once at the end?
> 
> I suppose we can.  But isn't the logic currently (or before the series) 
> cheated
> for variable-strided stores with ncopies > 1?  That is, while it sounds like
> reasonable heuristics you can't really rely on this as the vectorizer doesn't
> currently provide the info whether two vector loads/stores are adjacent?
> 
> Making sure we only pass count > 1 for adjacent load/store would be possible
> though.  We should document this with comments though.

... the suggestion!

This sounds applied for both load and store, if the others in this series look
fine, I guess we can file a bug for the exposed test cases first then fix it
with a follow-up patch for both load and store.

BR,
Kewen

> 
> Richard.
> 
>>
>> Thanks,
>> Richard
>>
>>> gcc/ChangeLog:
>>>
>>>       * config/aarch64/aarch64.cc (aarch64_stp_sequence_cost): Return
>>>       count directly instead of the adjusted value computed with CEIL.
>>> ---
>>>  gcc/config/aarch64/aarch64.cc | 2 +-
>>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>>
>>> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
>>> index 37d414021ca..9fb4fbd883d 100644
>>> --- a/gcc/config/aarch64/aarch64.cc
>>> +++ b/gcc/config/aarch64/aarch64.cc
>>> @@ -17051,7 +17051,7 @@ aarch64_stp_sequence_cost (unsigned int count, 
>>> vect_cost_for_stmt kind,
>>>         if (!aarch64_aligned_constant_offset_p (stmt_info, size))
>>>           return count * 2;
>>>       }
>>> -      return CEIL (count, 2) * 2;
>>> +      return count;
>>>
>>>      case scalar_store:
>>>        if (stmt_info && STMT_VINFO_DATA_REF (stmt_info)

Reply via email to