Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Different output with different optimization levels in GCC

Tags:

gcc

g++

c++17

sfml

I am working on a rewrite of a raytracer that I developed for university last semester and I am running into the following problem: When I compile and run my code in Debug the output is as expected

expected result

But when I enable higher optimization levels e.g. "-O2" something completely different is the result:

actual result

And I am not sure why this happens. I tracked it down to the sphere intersection code

//#pragma GCC push_options
//#pragma GCC optimize("O0")

Intersection Sphere::intersect(const Ray& ray, const float previous) const
{
    const auto oc = ray.origin - center_;
    const auto lhv = -dot(ray.direction, oc);
    const auto discriminant = lhv * lhv - (oc.lensqr() - radius_ * radius_);

    if (discriminant < 0.0F)
    {
        return Intersection::failure();
    }
    float distance;
    const auto rhv = std::sqrt(discriminant);
    const auto r = std::minmax(lhv + rhv, lhv - rhv);
    if (r.first <= 0.0F)
    {
        if (r.second <= 0.0F)
        {
            return Intersection::failure();
        }
        distance = r.second;
    }
    else
    {
        distance = r.first;
    }

    const auto hit = ray.getPoint(distance);
    const auto normal = (hit - center_).normalize();

    if (0.0F <= distance && distance < previous - epsilon)
    {
        return {distance, ray, this, normal, hit};
    }
    return Intersection::failure();
}

//#pragma GCC pop_options

If I uncomment the pragma in release mode, I get the expected result again. Maybe I have some undefined behaviour in my code that leads to this?

You can also have a look here as a minimal reproducible example is not easily possible. https://github.com/Yamahari/RayTracer/blob/master/rt/solid/Sphere.cpp

(You can also clone the repo and build the project with cmake, you only need SFML as a dependency.

Use -DSFML_INCLUDE_DIR="include_dir" and -DSFML_LIB_DIR="lib_dir" with the sfml library compiled with your desired compiler)

like image 473
Yamahari Avatar asked Mar 25 '20 12:03

Yamahari


People also ask

How many optimization levels are there in GCC?

GCC has since added -Og to bring the total to 8. From the man page: -O0 (do no optimization, the default if no optimization level is specified) -O1 (optimize minimally)

What is default GCC optimization level?

GCC has a range of optimization levels, plus individual options to enable or disable particular optimizations. The overall compiler optimization level is controlled by the command line option -On, where n is the required optimization level, as follows: -O0 . (default).

How many levels of optimization are there?

6.4 Optimization levels. In order to control compilation-time and compiler memory usage, and the trade-offs between speed and space for the resulting executable, GCC provides a range of general optimization levels, numbered from 0--3, as well as individual options for specific types of optimization.

What optimization does GCC do?

The compiler optimizes to reduce the size of the binary instead of execution speed. If you do not specify an optimization option, gcc attempts to reduce the compilation time and to make debugging always yield the result expected from reading the source code.


1 Answers

std::minmax returns a pair of references to its arguments. If you call it with prvalues as arguments, the references in this pair will be dangling after the end of the full-expression, which means that the access r.first in

if (r.first <= 0.0F)

will have undefined behavior here.

So store lhv + rhv and lhv - rhv in variables and call std::minmax on them or use

std::minmax({lhv + rhv, lhv - rhv})

to select the std::initializer_list overload, which returns a pair of actual values.


As noted by @Jarod42 in the comments, you don't actually need std::minmax here. rhv is the result of a std::sqrt call, so it is always non-negative, making lhv + rhv always the bigger (or equal) value.

like image 116
walnut Avatar answered Oct 22 '22 17:10

walnut