https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128180
Bug ID: 128180
Summary: Loop not vectorized when a 16-byte memcpy of floats is
folded into a uint128_t copy
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Keywords: missed-optimization
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: konstantinos.eleftheriou at vrull dot eu
Target Milestone: ---
Target: aarch64-linux-gnu
Created attachment 65965
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65965&action=edit
reduced.c
Four of the scalar renderers in LogOpCPU.cpp of 736.ocio_r (SPEC CPU 2026)
copy each pixel with memcpy, and none of their loops is vectorized at -Ofast.
This is AntiLogRenderer::apply:
void AntiLogRenderer::apply(const void * inImg, void * outImg, long numPixels)
const
{
const float * in = (const float *)inImg;
float * out = (float *)outImg;
for (long idx = 0; idx<numPixels; ++idx)
{
const float alphares = in[3];
// NB: 'in' and 'out' could be pointers to the same memory buffer.
std::memcpy(out, in, 4 * sizeof(float));
ApplyScale(out, m_log2_base);
ApplyExp2(out);
out[3] = alphares;
in += 4;
out += 4;
}
}
ApplyScale and ApplyExp2 multiply out[0], out[1] and out[2] by m_log2_base
and then replace each of them with its exp2. The attached antilog.cc contains
this function with its helpers. The other three
(LogRenderer, Log2LinRenderer and Lin2LogRenderer) have the same memcpy around
different math. For AntiLogRenderer::apply, the vectorizer reports:
missed: not vectorized: no vectype for stmt: _2 = MEM <uint128_t> [(char *
{ref-all})in_28];
The memcpy is folded into a 128-bit integer copy at the lower pass, and FRE
turns the reads of out[0], out[1] and out[2] into BIT_FIELD_REFs of the copied
value. The copy store is not dead: this->m_log2_base, which is loaded right
after it, may alias out.
The attached reduced.c is a smaller example. At -O3, its loop body before
vectorization is:
_5 = MEM <uint128_t> [(char * {ref-all})in_28];
MEM <uint128_t> [(char * {ref-all})out_27] = _5;
_2 = BIT_FIELD_REF <_5, 32, 0>;
_1 = _2 * 2.0e+0;
*out_27 = _1;
_10 = BIT_FIELD_REF <_5, 32, 32>;
_3 = _10 * 2.0e+0;
MEM[(float *)out_27 + 4B] = _3;
_22 = BIT_FIELD_REF <_5, 32, 64>;
_4 = _22 * 2.0e+0;
MEM[(float *)out_27 + 8B] = _4;
and the vectorizer reports:
missed: not vectorized: no vectype for stmt: _5 = MEM <uint128_t> [(char *
{ref-all})in_28];
If the memcpy in reduced.c is written as four element copies (out[0] = in[0];
... out[3] = in[3];), the loop is vectorized at -O3, with 16-byte vectors and
unroll factor 4.