From Bugzilla Helper: User-Agent: Mozilla/4.76 [en] (X11; U; Linux 2.2.16-22 i686) When compiling the attached program with "gcc -O0" or "gcc -O1" it works fine. When compiling with "gcc -O2" or "gcc -O3" it crashes, printing out the string "=== TEST FAILED! ===". The problem seems to be that the code generator performs a 32-bit subtraction on the long long (64-bit) values, generating an incorrect result. This problem seems to be quite sensitive to the calling context, the attached test case is simplified as much as I could. I submitted this bug to the gcc development team, and they claimed it was not broken in their latest development builds, and hence the problem should be referred to RedHat. (bug report # 1562, http://gcc.gnu.org/cgi-bin/gnatsweb.pl?cmd=view&pr=1562&database=gcc) Reproducible: Always Steps to Reproduce: 1. Compile the attached program. "gcc -O2 gcc_bug.cc" 2. Run it. "./a.out" 3. Look for the error message "=== TEST FAILED! ===" 4. Cry. Actual Results: colohan:improv~/cvs/Tools/viola_bug> gcc -O2 gcc_bug.cc colohan:improv~/cvs/Tools/viola_bug> ./a.out === TEST FAILED! === threadTimer2.current_time() = 17868864573449973892 process2->nfetch = 1132270 threadTimer2.time_base = 333418 Abort Exit 134 colohan:improv~/cvs/Tools/viola_bug> Expected Results: colohan:improv~/cvs/Tools/viola_bug> gcc -O1 gcc_bug.cc colohan:improv~/cvs/Tools/viola_bug> ./a.out TEST PASSED! colohan:improv~/cvs/Tools/viola_bug> The test program: #include <stdio.h> #include <stdlib.h> typedef unsigned long long uint64_t; typedef long long int64_t; struct Process2 { uint64_t nfetch; } *process2; struct ThreadTimer2 { uint64_t time_base; uint64_t current_time() { return process2->nfetch - time_base; } } threadTimer2; class EventMonTiming2 { public: static uint64_t time_of_become_speculative; static void violate(uint64_t store_time); }; uint64_t EventMonTiming2::time_of_become_speculative = 0; int main(int argc, char **argv) { process2 = new Process2; threadTimer2.time_base = 333418; process2->nfetch = 1132270; EventMonTiming2::time_of_become_speculative = 0; EventMonTiming2::violate(799016); printf("TEST PASSED!\n"); return 0; } void EventMonTiming2::violate(uint64_t store_time) { uint64_t work_so_far = threadTimer2.current_time() - time_of_become_speculative; if(store_time < threadTimer2.current_time()) { if((int64_t)work_so_far < 0) { printf("=== TEST FAILED! ===\n" "threadTimer2.current_time() = %llu\n" "process2->nfetch = %llu\n" "threadTimer2.time_base = %llu\n", threadTimer2.current_time(), process2->nfetch, threadTimer2.time_base); abort(); } } }
Created attachment 10360 [details] Simplified test case which triggers gcc bug.
I've been able to reproduce it and it seems like it has been fixed somewhen between Dec 04 and Dec 06 in CVS gcc, I'll dig into this deeper today. For some reason %edx (high part of the nfetch value) seems to be clobbered by the address where to load time_base from.
Actually, it was fixed by: 2000-12-02 Bernd Schmidt <bernds.uk> * reload1.c (free_for_value_p): New function, frontend to reload_reg_free_for_value_p. All callers of the latter now call this function with an additional mode argument. which will appear in gcc-2.96-76 (have just verified it fixes it and is exactly what's going on - reload_reg_free_for_value_p would be called only on the first register of the DImode register pair (ie. %eax) while with the patch it is on both registers of the pair (ie. %eax and %edx), so %edx cannot be used for other purposes afterwards.