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; }