[Bug middle-end/71690] New: integer conversion defeats memcpy optimizaton
msebor at gcc dot gnu.org
gcc-bugzilla@gcc.gnu.org
Tue Jun 28 21:07:00 GMT 2016
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71690
Bug ID: 71690
Summary: integer conversion defeats memcpy optimizaton
Product: gcc
Version: 7.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: middle-end
Assignee: unassigned at gcc dot gnu.org
Reporter: msebor at gcc dot gnu.org
Target Milestone: ---
Both functions in the following program are expected to result in comparably
efficient code. In expand_builtin_memcpy, GCC decides whether an invocation of
__builtin_memcpy will be expanded inline or result in a library call. Among
the factors it uses to make that decision is the range of sizes of the copy.
The range is obtained from the result of the Value Range Propagation
optimization for the size argument, provided the argument is constrained to a
subrange of its type. When the argument's type is other than size_t, VRP makes
the range available, and the call to memcpy may be expanded inline (this is the
case with the function g below). But when the argument's type is size_t, VRP
does not make its range available, and the expansion results in a library call,
thus defeating the optimization. This seems to be a general problem with VRP,
not one limited to memcpy (I just used memcpy as an example). Any built-in
whose expansion depends on the result of VRP of one of its arguments may be
affected.
char d [10];
char s [10];
void f (int);
void g (unsigned n)
{
if (n >= sizeof d) return;
__builtin_memcpy (d, s, n);
}
void h (unsigned long n)
{
if (n >= sizeof d) return;
__builtin_memcpy (d, s, n);
}
The problem can be seen in the generated assembly and also in the vrp dump for
the program (see the <<< annotations):
Value ranges after VRP:
...
_1: [0, 9]
.MEM_2: VARYING
n_3(D): VARYING
n_6: [0, 9] EQUIVALENCES: { n_3(D) } (1 elements)
g (unsigned int n)
{
long unsigned int _1;
<bb 2>:
if (n_3(D) > 9)
goto <bb 4>;
else
goto <bb 3>;
<bb 3>:
_1 = (long unsigned int) n_3(D); <<< constrained to [0, 9]
__builtin_memcpy (&d, &s, _1);
<bb 4>:
return;
}
...
Value ranges after VRP:
.MEM_1: VARYING
n_2(D): VARYING
n_5: [0, 9] EQUIVALENCES: { n_2(D) } (1 elements)
h (long unsigned int n)
{
<bb 2>:
if (n_2(D) > 9)
goto <bb 4>;
else
goto <bb 3>;
<bb 3>:
__builtin_memcpy (&d, &s, n_2(D)); <<< n_2(D) is VARYING
<bb 4>:
return;
}
More information about the Gcc-bugs
mailing list