Подтвердить что ты не робот

Ошибка компилятора JIT.Net?

Результат следующего кода отличается. Если он запущен с отладчиком в фоновом режиме или без него. Разница только там, если оптимизация включена.

Это результат:

- > с оптимизацией: 1000 2008 3016 1001 2009 3007 ...

- > без оптимизации (как и ожидалось) 1000 1008 1016 1001 1009 1017 ...

код:

using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;

namespace OptimizerTest
{   
    public class Test
    {
        int dummy;

        public void TestFunction(int stepWidth)
        // stepWidth must be a parameter
        {
            for (int step = 0; step < stepWidth; step++)
            {
                dummy = step + 1000;
                // addition with constant ( same value as later !)
                for (int x = 0; x < 20; x += stepWidth)
                {
                    int index = x + 1000 + step;
                    // constant must be same as above and ?!?! 
                    // int index = x + step + 1000; works !!!!!
                    Console.Write("\n\r" + index);
                }
            }
        }

        [MethodImpl(MethodImplOptions.NoOptimization)]
        public void TestFunctionNoOptimization(int stepWidth)
        {
            for (int step = 0; step < stepWidth; step++)
            {
                dummy = step + 1000;
                for (int x = 0; x < 20; x += stepWidth)
                {
                    int index = x + 1000 + step;                        
                    Console.Write("\n\r" + index);
                }
            }
        }
    }

    class Program
    {
        /// <summary>
        /// Result differs from Start with F5 to Ctrl-F5
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            Test test = new Test();
            Console.Write("\n\r---------\n\roptimized result\n\r-------------" );
            test.TestFunction(8);
            Console.Write("\n\r---------\n\rnot optimized result\n\r-------------");
            test.TestFunctionNoOptimization(8);
            Console.Write("\n\r---------\n\rpress any key");
            Console.ReadKey();
        }
    }
}

Поведение ошибки зависит от количества итераций внутреннего цикла (x < 5 все работает отлично). Очень интересно, что это не происходит, когда я использую

   int index = x + step + 1000; 

вместо

   int index = x + 1000 + step; 

Я работаю с Visual Studio 2010 SP1 и пробовал его с .NET Framework с 2.0 до 4.0.3. Я всегда видел тот же результат.

Кто-нибудь знает об этой ошибке или может ее воспроизвести?

4b9b3361

Ответ 1

Да, это определенно ошибка оптимизатора дрожания. Причина, по которой другие пользователи SO имеют проблемы с воспроизведением, состоит в том, что, по-видимому, только этот x64-джиттер имеет эту ошибку. Вы должны установить цель Платформы проекта в AnyCPU, отключить опцию "Предпочитайте 32-разрядную" на VS2012 и выше.

Я не рассматривал основную причину достаточно близко, но, похоже, он искал попытку устранить общую субэкпозицию step + 1000. Выделение подвыражений является одной из стандартных оптимизаций дрожания. Но он неправильно включает код выражения внутри цикла вместо того, чтобы держать его вне цикла, как написано. Например, вы увидите, что ошибка исчезает, когда вы пишете:

  dummy = step + 999;

Эта ошибка по-прежнему присутствует в последней версии .NET 4.5.1 (clrjit.dll, v4.0.30319.34003 на моей машине), также присутствующей в джиттере v2 (mscorjit.dll, v2.0.50727.7905 на моем машина).

Код слишком синтетичен, чтобы рекомендовать прочное обходное решение, вы уже нашли его в любом случае, чтобы вы могли продолжать заниматься автомобилем в своем проекте. В общем, я бы рекомендовал вам самостоятельно исключить суб-выражение:

  int index = x + dummy;  

Об этом следует сообщить в Microsoft, вы можете так опубликовать отчет об ошибке на веб-сайте connect.microsoft.com. Если вы не хотите тратить время, дайте мне знать, и я позабочусь об этом.