Как заставить Visual C ++ 9 не генерировать код, который на самом деле никогда не вызывается? - PullRequest
3 голосов
/ 16 марта 2010

Мой родной C ++ COM компонент использует ATL.В DllRegisterServer() я вызываю CComModule::RegisterServer():

STDAPI DllRegisterServer()
{
    return _Module.RegisterServer(FALSE); // <<< notice FALSE here
}

FALSE передается для указания на не регистрировать библиотеку типов .

ATL доступна в качестве источниковпоэтому я на самом деле компилирую реализацию CComModule::RegisterServer().Где-то внизу стека вызовов есть оператор if:

if( doRegisterTypeLibrary ) { //<< FALSE goes here
  // do some stuff, then call RegisterTypeLib()
}

Компилятор видит весь приведенный выше код и, таким образом, видит, что на самом деле условие if всегда false , но когда я проверяю сообщения о прогрессе компоновщика, я вижу, что ссылка на RegisterTypeLib() все еще существует, поэтому оператор if не исключается.

Можно ли заставить Visual C ++ 9 выполнять более качественный статический анализ ина самом деле видите, что какой-то код никогда не вызывается и не генерирует этот код?

Ответы [ 5 ]

1 голос
/ 22 марта 2010

Внутренний вызов AtlComModuleRegisterServer имеет внешнюю связь, которая обычно не позволяет оптимизатору распространять значение bRegTypeLib по графу вызовов. Отчасти это может быть лучше объяснено при разборке.

Так DllInstall(...) звонит CAtlDllModuleT::RegisterServer(0). Это начало проблемы:

push    0
call    ?DllRegisterServer@?$CAtlDllModuleT@VCAtlTestModule@@@ATL@@QAEJH@Z

Скажем только ради аргументов, что компилятор проверил, что CAtlDllModuleT::DllRegisterServer вызывается только один раз, и очень безопасно сдвинуть 0 / FALSE вниз еще на один уровень ... внешняя связь предотвращает отбрасывание AtlComModuleRegisterServer. высокая стоимость (дублирование кода) и не допускает никакой дополнительной оптимизации всей программы. Вероятно, безопаснее сохранить подпись как есть и выручить пораньше с помощью обычного вызова cdecl ...

?DllRegisterServer@?$CAtlDllModuleT@VCAtlTestModule@@@ATL@@QAEJH@Z proc near
<trimmed>
push    0
push    edx
push    offset ATL::_AtlComModule
call    _AtlComModuleRegisterServer@12

Этот код может быть улучшен по размеру за счет двух констант, но он, вероятно, будет стоить примерно столько же времени выполнения. Если производительность является проблемой, рассмотрите возможность явной установки порядка расположения , вы можете сохранить ошибку страницы.

1 голос
/ 16 марта 2010

Вы уверены, что код не будет удален позже в процессе компиляции / компоновки? Вы проверили сгенерированный ASM?

Как определяется функция RegisterTypeLib? Конечно, что-либо помеченное dllexport не может быть удалено компоновщиком, но на любую функцию, не помеченную как static (или помещенную в анонимное пространство имен), могут ссылаться несколько блоков перевода, поэтому компилятор не сможет удалить функция. Компоновщик может это сделать, но это может быть одной из последних оптимизаций, которые он выполняет (я понятия не имею, в каком порядке он применяет оптимизации), поэтому символы могут оставаться в сообщениях, которые вы просматриваете, даже если они устранены впоследствии.

1 голос
/ 19 марта 2010

любой код, который успешно встроен, будет сгенерирован только при вызове. Это простой способ сделать это, пока компилятор поймет подсказку. inline - это только предложение, хотя

1 голос
/ 16 марта 2010

У вас активна целая оптимизация программы [/ GL]? Это похоже на оптимизацию, которую компилятор обычно не может выполнить самостоятельно.

0 голосов
/ 05 апреля 2010

Оказывается, ключ заключается в том, чтобы включить генератор кода времени соединения на всем протяжении настроек компилятора.

Он должен быть включен на вкладке Общие - Оптимизация всей программы должна быть установлена ​​на "Использовать генерацию кода времени соединения". Он также должен быть включен на вкладке C ++ -> Optimization - «Оптимизация всей программы * должна быть установлена ​​на« Включить генерацию кода времени соединения ». Она также должна быть включена на компоновщике -> Оптимизация вкладка - Генерация временного кода связи должна быть установлена ​​на "Использовать генерацию временного кода связи". Затем / OPT: REF и / OPT: ICF (опять же, вкладка * Linker -> Optimization ") должны оба будут включены.

И это эффективно удаляет вызовы к RegisterTypeLib() - его больше нет в списке импортируемых символов.

...