4

I have a small example of issue which came up during the transition from VS2013 to VS2015. In VS2015 further mentioned code example causes floating-point invalid operation.

enter image description here

int main()
{
    unsigned int enableBits = _EM_OVERFLOW | _EM_ZERODIVIDE | _EM_INVALID;

    _clearfp();
    _controlfp_s(0, ~enableBits, enableBits);

    int count = 100;
    float array[100];

    for (int i = 0; i < count; ++i)
    {
        array[i] = (float)pow((float)(count - 1 - i) / count, 4); //this causes exception in VS2015
    }

    return 0;
}

This happens only in release mode so its probably caused by different optimization. Is there something wrong with this code or is this a bug in VS 2015?

Its hard to find issues like these across the whole code base so I am looking for some systematic fix not a workaround (e.g. use different variable instead of i which works)

I also checked generated assembly code and it seems in VS2013 it uses whole 128bit registry to perform 4 float operations in one division. In VS2015 it seems to do only 2 float operations and the rest of registry is zero (or some garbage) which probably introduces this exception.

Instruction which causes exception is marked in picture.

VS2013 VS2013

and VS2015 enter image description here

Any help will be appreciated. Thanks.

Community
  • 1
  • 1
Bezousek
  • 199
  • 1
  • 6
  • Hmm. Your code works for me (Release/x64) with Full Optimization enabled. Is your VS up to date? Do you have any "special" compiler settings? – Simon Kraemer Oct 11 '16 at 09:39
  • I used VS2015 update 3. I used standard settings for release + Optimization (Maximize Speed /O2) and enable intrinsic functions (Yes /Oi) – Bezousek Oct 11 '16 at 11:08

1 Answers1

1

This looks to be an interaction with you using floating point exceptions but also enabling some floating point optimizations.

What the code is doing is it does 2 iterations at once (loop unrolling) but uses divps which does 4 divides at once (from the 4 floats in an XMM register). The upper 2 floats in the XMM register are not used, and are zero. As the result of the divide of the values in those slots aren't used it doesn't normally matter. However, as you set custom exception handling this raises a invalid op exception that you see even though its generating values which wont be used.

Your choices are, as I see them, to set /fp:strict which will disable optimisations so make this work (but it will obviously make the code slower) or remove the controlfp call.

Mike Vine
  • 9,468
  • 25
  • 44
  • Thanks for the comment. This settings to strict will help but problem is that I don't know where I should set it. I have generally hundreds of files with computation and don't want to decrease it everywhere. Do you know what happen in VS2015 vs VS2013 where it runs fine even on /fp:precise ? – Bezousek Oct 11 '16 at 11:10