https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77779
Bug ID: 77779 Summary: unnecessary trap checks for pointer subtraction with -ftrapv Product: gcc Version: 5.4.1 Status: UNCONFIRMED Severity: minor Priority: P3 Component: middle-end Assignee: unassigned at gcc dot gnu.org Reporter: jfc at mit dot edu Target Milestone: --- Consider this code: long diff(long *a, long *b) { return (a - b) + (a - b); } Compiled with gcc -O2 -ftrapv on x86-64 the resulting code is diff: .LFB0: .cfi_startproc subq $8, %rsp .cfi_def_cfa_offset 16 call __subvdi3 sarq $3, %rax movq %rax, %rdi movq %rax, %rsi call __addvdi3 addq $8, %rsp .cfi_def_cfa_offset 8 ret .cfi_endproc .LFE0: .size diff, .-diff There are two problems here -- not bugs, but suboptimal code. 1. Pointer subtraction of sizes larger than 2 bytes should not generate a trapping subtract. In the usual case where pointers and ptrdiff_t are the same size, the result will fit in a ptrdiff_t. 2. The addition can not overflow. In general, x/A + y/B with A and B both greater than 2 will not overflow. (This might not be worth fixing, but I think the previous problem is.) I contrived this C example after seeing the first problem in C++. The real code is a call to std::vector<T>::size() with type T 4 bytes or larger. size() can't overflow, but g++ inserts a call to __subvdi3 anyway. On Linux+ELF this results in a dynamic linker operation. This is in 5.2 and 5.4.1 20160926. I have not checked gcc 6+.