Visual C++ Optimizer fixes for Visual Studio 2015 Update 3

Applies to: Visual Studio 2015 Update 3

This article describes a hotfix package for Microsoft Visual Studio 2015 Update 3. The hotfix contains several fixes to the Visual C++ optimizer and code generator (c2.dll). For more information, see the "Issues that are fixed in this hotfix" section.

Resolution


How to obtain this hotfix

The following file is available for download from the Microsoft Download Center:

Download Download the hotfix package now.

For more information about how to download Microsoft support files, click the following article number to view the article in the Microsoft Knowledge Base:
119591 How to obtain Microsoft support files from online services
Microsoft scanned this file for viruses. Microsoft used the most current virus-detection software that was available on the date that the file was posted. The file is stored on security-enhanced servers that help prevent any unauthorized changes to the file.

Prerequisites

To apply this hotfix, you must have Visual Studio 2015 Update 3 installed. 

Restart requirement

You may have to restart the computer after you apply this hotfix if no instance of Visual Studio is being used.

Hotfix replacement information

This hotfix doesn't replace other hotfixes. 

Issues that are fixed in this hotfix


This hotfix contains fixes for the following issues:
  • Fixes a bug in the optimizer when hoisting a loop-variant conditional store outside a loop:
    #include <cstdlib>#include <cassert>struct Foo{    int a;    int b;};int main(){    Foo foo;    foo.b = rand();    int a = rand();    int b = foo.b;    for (int i = 0; i < 10; ++i)    {        int inner_b = b;        int inner_a = a;        if (inner_b < 0) // This gets incorrect hoisted outside the loop.                         // A workaround is /d2SSAOptimizer-        {            inner_a = 0;            inner_b = 0;        }        if (inner_b >= 0)            assert(inner_a == a);        a += b;    }    return 0;}

     

  • Fix for an integer division bug in the optimizer:
    #include <stdio.h>volatile int z = 0;int main(){    unsigned a, b;    __int64 c;    a = z;    c = a;    c = (c == 0) ? 1LL : c;    b = (unsigned)((__int64)a * 100 / c); // Division was made unconditional                                          // incorrectly creating a divide by zero.                                          // A workaround is /d2SSAOptimizer-    printf("%u\n", b);    return 0;}

     

  • Fix for an integer division bug in the optimizer:
    int checkchecksum(int suly, int ell, int utkodert){    int x;    ell -= utkodert;    ell %= 103;    if (suly - 1)        utkodert /= (suly - 1); // Division was made unconditional,                                // incorrectly creating a potential divide by zero                                // A workaround is /d2SSAOptimizer-    return utkodert;}

     

  • Fix for an integer division bug in the optimizer:
    typedef int unsigned uint;volatile uint out_index = 0;bool data[1] = {true};bool __declspec(noinline) BugSSA(uint index){    uint group = index / 3;    if (group == 0) // The division result being compared to zero is replaced                     // with a range check. We then incorrectly move the division    {               // to the next use of "group", without accounting for the fact                    // that "index" has changed. A workaround is /d2SSAOptimizer-        return false;    }    index -= 3;    group--;    bool ret = data[group]; // crash here    out_index = index;    out_index = index;    return ret;}int main(){    volatile uint i = 3;    return BugSSA(i);}

     

  • Fix for a crash in the optimizer for division of MIN_INT by -1:
    int test_div(bool flag, int dummy){    int result = std::numeric_limits<int>::min();    int other;    if (flag)        other = -1;    else        other = dummy - 1 - dummy;    result /= other; // We would push the division up into both arms of the                     // if-then-else. One of those divisions would cause the                      // optimizer to evaluate MIN_INT/-1.This is a crash, similar                     // to dividing by zero. A workaround is /d2SSAOptimizer-    return result;}

     

  • Fixes a stack overflow in the optimizer:
    #include <stdio.h>// This example produced a stack overflow in the optimizer, which was // caused by mutually-recursive analysis functions not properly tracking// the number of times they were invocated.// A workaround is /d2SSAOptimizer-typedef unsigned char byte;typedef unsigned long long int uint64;int main(){    const uint64 *sieveData = new uint64[1024];    uint64 bitIndexShift = 0;    uint64 curSieveChunk = 0xfafd7bbef7ffffffULL & ~uint64(3);    const unsigned int *NumbersCoprimeToModulo = new unsigned int[16];    const unsigned int *PossiblePrimesForModuloPtr = NumbersCoprimeToModulo;    while (!curSieveChunk)    {        curSieveChunk = *(sieveData++);        const uint64 NewValues = (16 << 8) | (32 << 24);        bitIndexShift = (NewValues >> (bitIndexShift + 8)) & 255;        PossiblePrimesForModuloPtr = NumbersCoprimeToModulo + bitIndexShift;    }    if (PossiblePrimesForModuloPtr - NumbersCoprimeToModulo != 0)    {        printf("fail");        return 1;    }    printf("pass");    return 0;}

     

  • Fix for incorrect code generation when removing redundant floating point conversions involving convert an int32 parameter to f64:
    #include <string>__declspec(noinline) void test(int Val){    double Val2 = Val;    std::string Str;    printf("%lld\n", __int64(Val2)); // We incorrectly try to read 64 bits of                                      // floating point from the parameter area,                                     // instead of reading 32 bits of integer                                      // and converting it. A workaround is                                     // to throw /d2SSAOptimizer-}int main(){    test(6);    test(7);    return 0;}

     

  • Fixes a crash in the optimizer when splitting flow graph nodes in a default statement of a switch block, for more details, see https://bugs.chromium.org/p/chromium/issues/detail?id=627216#c15.
  • Fixes a bug in the loop optimizer where we perform incorrect strength reduction of unsigned secondary induction variables that are multiples of the primary induction variable:
    #include <assert.h>#include <malloc.h>#include <stdio.h>typedef unsigned int uint;typedef unsigned char byte;/*There is a corner case in the compiler's loop optimizer. The corner case aroseif an induction variable (IV) is a multiple of the loop index, and there's acomparison of the IV to an integer that is less than this multiplication factor.A workaround is to use #pragma optimize("", off) / #pragma optimize("", on)around the affected function.*/int main(int argc, char *argv[]){    const uint w = 256;    const uint h = 64;    const uint w_new = w >> 1;    const uint h_new = h >> 1;    const byte *const src = (byte *)malloc(w * h);    byte *it_out = (byte *)malloc(w_new * h_new);    int fail = 0;    for (uint y_new = 0; y_new < h_new; ++y_new)    {        for (uint x_new = 0; x_new < w_new; ++x_new, ++it_out)        {            uint x = x_new * 2;            uint y = y_new * 2;            if (x < 1 || y < 1)            {                *it_out = 0;                continue;            }            if (x != 0)            {            }            else            {                fail = 1;            }            *it_out = 4 * src[y * w + x];        }    }    if (fail)    {        printf("fail\n");        return (1);    }    printf("pass\n");    return (0);}

     

  • Offers a workaround for C4883 ": function size suppresses optimizations". When the optimizer sees functions that are massive, it will scale back the optimizations that it performs. It will issue a C4883 warning when it does this, if you have enabled the warning via /we4883. If you want to override this decision to suppress optimizations, throw the /d2OptimizeHugeFunctions switch.
  • Fixes for a compiler crash in c2!PpCanPropagateForward when you perform optimizations on x64.
  • Fixes for loop optimizer bugs which involve incorrect induction variable strength reduction.
  • Fixes for incorrect reordering of expressions which involve reads & writes to memory because of incorrect alias checking.
  • Fixes for a register allocator bug which involves a compiler-generated temporary existing across multiple exception handling regions.

Status


Microsoft has confirmed that this is a problem in the Microsoft products that are listed in the "Applies to" section.