Обновить

Комментарии 4

Уже не помню точно как там в c#, возможно внутри цикла переопределить индекс, или компилятор не пропустит? Типа такого:

for (int i = 0; i != src.Length; i++) {
  sum += src[i];
  i += 100;
}

Хотя, даже если и не пропустит, наверняка через unsafe можно поменять.

А если в теории поменять можно, то и проверка границ необходима, ибо != не будет гарантировать ничего. С другой стороны, переопределением индекса на какой-нибудь max int можно поломать вообще любой цикл. Так что, наверное, не так уж и необходима проверка.

Да, C# разрешает менять i внутри тела цикла — ваш пример с i += 100 полностью валиден, компилятор его пропустит без единого предупреждения. И именно поэтому проверка границ у != обязана остаться: раз индекс может прыгнуть куда угодно, JIT не может доказать, что он не перескочит Length мимо точного равенства.

С < это неважно — там условие i < Length само по себе ловит любой выход за край на следующей итерации. А != ловит только точное совпадение, и если вы прыгнули через него — цикл убежит за массив. Проверка границ — это ровно та страховка, которая не даст ему убежать.

Так что тут не «а вдруг», а точная причина, по которой JIT осторожничает и проверку не снимает. С < он это доказать может и проверку убирает, с != — нет.

Про unsafe тоже верно: там проверок границ нет вообще — и за выход отвечаете уже вы сами.

Это ровно то, о чём issue #84697 в dotnet/runtime: там разработчики JIT прямо обсуждают, что для восходящего цикла с != нужен анализ, доказывающий монотонность индекса, а пока его нет — проверка остаётся. И это не только про C#: в треде отмечают, что ту же форму не дожимают и другие компиляторы, включая LLVM, ровно по той же причине.

Там, где нужно гарантированно избавиться от bounds checking - ref var, MemoryMarshal.Get*Reference + Unsafe.Add.

При желании, с их помощью можно соорудить цикл с обратным счётчиком и при этом "прямым" доступом к данным - экономим инструкции на загрузке предельного значения в регистр и сравнении счётчика с регистром.

По поводу выравниваний - влияет очень сильно, мало того, что выравнивание это лотерея, так ещё и даже пару лишних байт в горячем цикле может как серьёзно замедлить, так и ускорить процесс.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации