M
mathog
Platform: gcc 4.6.3 on AMD Athlon(tm) II X2 245 Processor on
Ubuntu 12.04
The bug I thought was due to a particularly hard to find memory access
problem (see other thread I started today) seems to be even odder than
that. It was tracked down to a particular conditional, which seems to
optimize in such a way that the result is not always correct. (But
possibly only when embedded in the rest of the program.)
The skeletal elements of the problem code are:
double function(double *ymax){
double yheight;
double baseline;
double tmp=0.0;
double fs;
double yll, boff; /* these have values */
/* bbox is a struct that includes yMin and yMax */
/* set fs */
/* start of loop */
/* set yll, boff, bbox */
yheight = bbox.yMax - bbox.yMin;
printf("baseline %lf tmp %20.17lf %16llX ymax %20.17lf %16llX \n",
baseline, tmp, *(uint64_t *)&tmp,
(ymax ? *ymax: 666), (ymax ? *(uint64_t *)ymax: 666));
if(ymax){
tmp = fs * (((double)bbox.yMax)/yheight);
//the next line would "fix" the code when compiled in:
// printf("DEBUG ymax %lf tmp %lf\n", *ymax, tmp);fflush(stdout);
if(*ymax <= tmp){ // <--------THIS IS THE PROBLEM
*ymax = tmp;
baseline = yll - boff;
}
}
/* end of loop */
return(baseline);
}
When this is compiled with -O2 or -O3, AND when it is part of the larger
program, the indicated test is failing for the equals case, the
output from the printf statements is:
baseline 0.000000 tmp 0.00000000000000000 0 ymax
0.00000000000000000 0
baseline 12.680004 tmp 6.85406955898171422 401B6A9135E157A9 ymax
6.85406955898171422 401B6A9135E157A9
baseline 12.680004 tmp 6.85406955898171422 401B6A9135E157A9 ymax
6.85406955898171422 401B6A9135E157A9
baseline 12.680004 tmp 6.85406955898171422 401B6A9135E157A9 ymax
6.85406955898171422 401B6A9135E157A9
which is wrong, the baseline value should have been changing because
yll and boff were different on each loop iteration.
Compile it with -O0 (or with -O2 or -O3 and not be part of the larger
program, or with the commented out printf uncommented) and
instead it emits:
baseline 0.000000 tmp 0.00000000000000000 0 ymax
0.00000000000000000 0
baseline 12.680004 tmp 6.85406955898171422 401B6A9135E157A9 ymax
6.85406955898171422 401B6A9135E157A9
baseline 13.480004 tmp 6.85406955898171422 401B6A9135E157A9 ymax
6.85406955898171422 401B6A9135E157A9
baseline 17.480006 tmp 6.85406955898171422 401B6A9135E157A9 ymax
6.85406955898171422 401B6A9135E157A9
which is the correct result.
So, bizarrely, there is a problem with the conditional "<=" not giving
the right answer when the values of *ymax and tmp are equal when the
code is compiled in certain ways. And they are equal, down to the last
bit, as shown by the print statements!
This modification does not resolve the issue (when compiled in such a
way that it would be an issue):
if(*ymax <= (tmp * 1.0000000000000001)){
but this one does:
if(*ymax <= (tmp * 1.00000000001)){
So, what sort of "optimization" is it that gives the wrong result for
the "<=" condition when *ymax and tmp are equal????
Thanks,
David Mathog
Ubuntu 12.04
The bug I thought was due to a particularly hard to find memory access
problem (see other thread I started today) seems to be even odder than
that. It was tracked down to a particular conditional, which seems to
optimize in such a way that the result is not always correct. (But
possibly only when embedded in the rest of the program.)
The skeletal elements of the problem code are:
double function(double *ymax){
double yheight;
double baseline;
double tmp=0.0;
double fs;
double yll, boff; /* these have values */
/* bbox is a struct that includes yMin and yMax */
/* set fs */
/* start of loop */
/* set yll, boff, bbox */
yheight = bbox.yMax - bbox.yMin;
printf("baseline %lf tmp %20.17lf %16llX ymax %20.17lf %16llX \n",
baseline, tmp, *(uint64_t *)&tmp,
(ymax ? *ymax: 666), (ymax ? *(uint64_t *)ymax: 666));
if(ymax){
tmp = fs * (((double)bbox.yMax)/yheight);
//the next line would "fix" the code when compiled in:
// printf("DEBUG ymax %lf tmp %lf\n", *ymax, tmp);fflush(stdout);
if(*ymax <= tmp){ // <--------THIS IS THE PROBLEM
*ymax = tmp;
baseline = yll - boff;
}
}
/* end of loop */
return(baseline);
}
When this is compiled with -O2 or -O3, AND when it is part of the larger
program, the indicated test is failing for the equals case, the
output from the printf statements is:
baseline 0.000000 tmp 0.00000000000000000 0 ymax
0.00000000000000000 0
baseline 12.680004 tmp 6.85406955898171422 401B6A9135E157A9 ymax
6.85406955898171422 401B6A9135E157A9
baseline 12.680004 tmp 6.85406955898171422 401B6A9135E157A9 ymax
6.85406955898171422 401B6A9135E157A9
baseline 12.680004 tmp 6.85406955898171422 401B6A9135E157A9 ymax
6.85406955898171422 401B6A9135E157A9
which is wrong, the baseline value should have been changing because
yll and boff were different on each loop iteration.
Compile it with -O0 (or with -O2 or -O3 and not be part of the larger
program, or with the commented out printf uncommented) and
instead it emits:
baseline 0.000000 tmp 0.00000000000000000 0 ymax
0.00000000000000000 0
baseline 12.680004 tmp 6.85406955898171422 401B6A9135E157A9 ymax
6.85406955898171422 401B6A9135E157A9
baseline 13.480004 tmp 6.85406955898171422 401B6A9135E157A9 ymax
6.85406955898171422 401B6A9135E157A9
baseline 17.480006 tmp 6.85406955898171422 401B6A9135E157A9 ymax
6.85406955898171422 401B6A9135E157A9
which is the correct result.
So, bizarrely, there is a problem with the conditional "<=" not giving
the right answer when the values of *ymax and tmp are equal when the
code is compiled in certain ways. And they are equal, down to the last
bit, as shown by the print statements!
This modification does not resolve the issue (when compiled in such a
way that it would be an issue):
if(*ymax <= (tmp * 1.0000000000000001)){
but this one does:
if(*ymax <= (tmp * 1.00000000001)){
So, what sort of "optimization" is it that gives the wrong result for
the "<=" condition when *ymax and tmp are equal????
Thanks,
David Mathog