assert()s, оптимизация и директива accept () в D

Скажем, у меня есть assert() что-то вроде assert( x < limit );Я посмотрел на поведение оптимизатора в GDC в сборках выпуска и отладки со следующим фрагментом кода:

uint cxx1( uint x )
    {
    assert( x < 10 );
    return x % 10;
    }

uint cxx1a( uint x )
in  { assert( x < 10 ); }
body
    {
    return x % 10;
    }

uint cxx2( uint x )
    {
    if ( !( x < 10 ))
       assert(0);
    return x % 10;
    }

Теперь, когда я строю в режиме отладки, утверждения имеют очень приятный эффект, вызывая огромную оптимизацию. GDC избавляется от ужасного кода, чтобы полностью выполнить операцию по модулю, потому что он знает о возможном диапазоне x из-за условия if в assert. Но в режиме релиза условие if отбрасывается, поэтому внезапно код ужаса возвращается, и больше нет никакой оптимизации ни в cxx1(), ни даже в cxx1a(). Это очень иронично, что режим выпуска генерирует гораздо худший код, чем код отладки. Конечно, никто не хочет, чтобы исполняемый код, принадлежащий if-тестам, присутствовал в коде выпуска, поскольку мы должны потерять все эти накладные расходы.

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

Я полагаю, что некоторые компиляторы C++ имеют что-то, называемое __assume() или что-то подобное, но здесь мне не хватает памяти. GCC имеет специальную директиву __builtin_unreachable(), которая может использоваться для построения функции предположения (). По сути, если бы я мог создать свою собственную директиву предположить (), это дало бы эффект утверждения определенных истин об известных значениях или известных диапазонах и выставления / публикации их на этапах оптимизации независимо от режима выпуска / отладки, но без генерации какого-либо фактического кода вообще для условие accept () в сборке релиза, тогда как в режиме отладки оно будет точно таким же, как assert().

Я попробовал эксперимент, который вы видите в cxx2, который всегда запускает оптимизацию, так что это хорошая работа, но он генерирует то, что является морально отладочным кодом для if-условия accept () даже в режиме выпуска с тестом и условным переходом к неопределенная инструкция, чтобы остановить процесс.

У кого-нибудь есть идеи о том, разрешимо ли это? Или вы думаете, что это полезный элемент списка желаний фантазии компилятора D?

2 ответа

Насколько я знаю __builtin_unreachable это следующая лучшая замена для assume как функция в GCC. В некоторых случаях условие if все еще может не оптимизироваться: предложение "Assume" в gcc

Встроенные функции GCC доступны в GDC путем импорта gcc.builtins, Вот пример того, как обернуть __builtin_unreachable функция:

import gcc.builtins;

void assume()(bool condition)
{
  if (!condition)
    __builtin_unreachable();
}

bool foo(int a)
{
  assume(a > 10);
  return a > 10;
}

Здесь есть две интересные детали:

  1. Нам не нужны струнные миксины или подобные сложные вещи. Пока вы компилируете с -O В любом случае GDC полностью оптимизирует вызов функции.
  2. Для этого работать assume функция должна быть встроена. К сожалению, встроенные нормальные функции не полностью поддерживаются, когда assume находится в другом модуле в качестве вызывающей функции. В качестве обходного пути мы используем шаблон с 0 аргументами шаблона. Это должно гарантировать, что встраивание всегда может работать.

Вы можете проверить и изменить этот пример здесь: https://explore.dgnu.org/

Теперь мы (разработчики GDC) могли легко переписать assert(...) в if(...) __builtin_unreachable() в режиме релиза. Но это может сломать некоторый код, поэтому dmd должен реализовать это первым.

ОК, я действительно не знаю, что вы хотите? cxx2 это решение немного больше информации

Другие вопросы по тегам