https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90345
Bug ID: 90345 Summary: too pessimistic check whether pointer may alias local variable Product: gcc Version: 9.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: middle-end Assignee: unassigned at gcc dot gnu.org Reporter: vanyacpp at gmail dot com Target Milestone: --- Consider the following example (reduced from a real program): #include <cstdlib> #include <cstdint> struct big_integer { void push_back(uint32_t const&); size_t size; uint32_t* digits; }; big_integer& operator*=(big_integer& a, uint32_t b) { uint64_t const BASE = 1ull << 32; uint32_t carry = 0; for (size_t i = 0; i != a.size; i++) { uint64_t sum = 1ull * a.digits[i] * b + carry; carry = static_cast<uint32_t>(sum / BASE); a.digits[i] = static_cast<uint32_t>(sum % BASE); } if (carry) { a.push_back(carry); //a.push_back(uint32_t(carry)); } return a; } GCC 9.1 compiles the inner loop to this: .L9: mov esi, DWORD PTR [rsp+12] ; load carry .L5: mov edx, DWORD PTR [rcx] add rcx, 4 imul rdx, r8 add rdx, rsi mov rsi, rdx shr rsi, 32 mov DWORD PTR [rsp+12], esi ; store carry mov DWORD PTR [rcx-4], edx cmp r9, rcx jne .L9 As one can see carry is spilled to stack and it is loaded and stored at each iteration of the loop. Loading and storing carry at each iteration is not needed: it is a local variable and its address is not taken. My guess is that GCC believes that it escapes because of the push_back after the loop. At least if I make a copy of carry before push_back'ing it (as shown in the comment) the problem goes away. I think that alias analysis can be improved here: carry may not alias a.digits[i] because it escapes only after the loop.