- 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 arose
if an induction variable (IV) is a multiple of the loop index, and there's a
comparison 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.